c++ - Visual C++ 内联 x86 程序集 : Accessing "this" pointer

标签 c++ visual-c++ x86 this inline-assembly

根据 MSDN 文档,“this”指针在使用默认 __thiscall 时存储在 ECX 中类函数的调用约定。尽管在翻译常规 C++ 代码时确实存在这种情况,但我在尝试使用内联汇编访问“this”时遇到了问题。

测试程序如下:

#include <cstdio>

class TestClass
{
    long x;

    public:
        inline TestClass(long x):x(x){}

    public:
        inline long getX1(){return x;}
        inline long getX2()
        {
            _asm
            {
                mov eax,dword ptr[ecx]
            }
        }
};
int main()
{
    TestClass c(42);

    printf("c.getX1() = %d\n",c.getX1());
    printf("c.getX2() = %d\n",c.getX2());

    return 0;
}

两个Get函数翻译成这样:

?getX1@TestClass@@QAEJXZ (public: long __thiscall TestClass::getX1(void)):
  00000000: 8B 01              mov         eax,dword ptr [ecx]
  00000002: C3                 ret

?getX2@TestClass@@QAEJXZ (public: long __thiscall TestClass::getX2(void)):
  00000000: 8B 01              mov         eax,dword ptr [ecx]
  00000002: C3                 ret

我认为可以肯定地说这两个函数是相同的。不过,这里是程序的输出:

c.getX1() = 42
c.getX2() = 1

显然,当调用第二个 Get 函数时,“this”存储在 ECX 中,所以我的问题是:如何确保包含内联汇编的类函数遵循调用约定和/或以与常规/非内联函数相同的方式调用?

编辑:主要功能翻译如下:

_main:
  00000000: 51                 push        ecx
  00000001: 6A 2A              push        2Ah
  00000003: 68 00 00 00 00     push        offset $SG3948
  00000008: E8 00 00 00 00     call        _printf
  0000000D: 83 C4 08           add         esp,8
  00000010: 8D 0C 24           lea         ecx,[esp]
  00000013: E8 00 00 00 00     call        ?getX2@TestClass@@QAEJXZ
  00000018: 50                 push        eax
  00000019: 68 00 00 00 00     push        offset $SG3949
  0000001E: E8 00 00 00 00     call        _printf
  00000023: 33 C0              xor         eax,eax
  00000025: 83 C4 0C           add         esp,0Ch
  00000028: C3                 ret

最佳答案

我不知道你是误读了文档,还是 它写得不好,但是__thiscall确实意味着this 指针存储在ECX中;这意味着指向对象的指针是 通过 ECX。在更大的功能中,我看到它从一个 在函数的不同地方注册到另一个,并且在一些 案例,我已经看到它溢出到内存中。你不能指望它在 ECX。并且它的位置可以根据中的其他代码而改变 函数,以及传递给编译器的优化标志。

在您的情况下,由于您的 函数是内联的,并且可能已经内联。 (除了那个 _asm 可能会抑制内联。)常量传播(一种非常简单且 广泛使用的优化技术)几乎肯定意味着你的 调用 c.getX1() 将只使用 42,没有函数调用,也没有 访问 c 任何东西。

总的来说,内联汇编是一个棘手的问题,正是因为你 不知道编译器使用的是什么寄存器。通常,在 除了实际的汇编程序指令外,还会有指令 告诉编译器诸如哪些寄存器和哪些变量你 使用,您将能够在 汇编程序和其他此类信息。除非你使用这些,否则你可以 对内联汇编程序的假设非常非常少。

但是每个编译器都有自己的规则。通常具有特殊语法。 例如 mov eax, [cx].xmov eax, x 可能是 Microsoft 内联汇编程序需要什么。无论如何,没有办法 根据您所写的内容,编译器可能会推断出 您正在访问 c.x。由于所有其他用途都已被淘汰 通过不断传播,这将是一个非常糟糕的编译器,甚至 生成了一个变量c

编辑:

FWIW:Microsoft 内联汇编程序的文档位于 http://msdn.microsoft.com/en-us/library/4ks26t93%28v=vs.71%29.aspx .我 没有详细看过,但是有一节是关于“使用 C 或 __asm block 中的 C++ 符号”。这可能会解释你如何 以编译器知道的方式在内联汇编程序中访问 x x 已被访问。

关于c++ - Visual C++ 内联 x86 程序集 : Accessing "this" pointer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12194083/

相关文章:

c++ - 由于 const,无法在构造函数中转换参数

c++ - OpenCV:我们需要删除 CvPoint 吗?如何删除?

c++ - C++ : Visual C++ mangles method signature differently from mangled method in dll 中 Unresolved external 问题

c++ - 了解 Visual C++ 控制台项目中的 _tmain

linux - 在 Linux IA-32 汇编程序 (gas) 上创建一个子字符串

c++ - 如何解析来自 EDID 的数字数据

c++ - Android NDK pthread上下文切换

C++ for each 有一个指针

x86 - Core i7 中每核 L2 和 L3 之间的互连

c# - 是否有任何好的 VB/C# x86 反汇编程序库?