根据MSDN文档,当使用类函数的默认
__thiscall调用约定时,“this”指针存储在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并不意味着这个
指针存储在ECX中;它意味着指向对象的指针是
通过ECX.在较大的功能中,我看到它从一个移动
在函数的不同位置注册另一个,在某些地方
我已经看到它溢满了记忆.你不能指望它在
ECX.它将在哪里可以根据其他代码而改变
函数,以及传递给编译器的优化标志.
它的写得不好,但__thiscall并不意味着这个
指针存储在ECX中;它意味着指向对象的指针是
通过ECX.在较大的功能中,我看到它从一个移动
在函数的不同位置注册另一个,在某些地方
我已经看到它溢满了记忆.你不能指望它在
ECX.它将在哪里可以根据其他代码而改变
函数,以及传递给编译器的优化标志.
在你的情况下,你的问题更加复杂
函数是内联的,可能已内联. (除了那个
_asm可能会抑制内联.)不断传播(非常简单和
广泛使用的优化技术)几乎肯定意味着你的
调用c.getX1()只会使用42,没有函数调用而没有
访问c什么的.
一般来说,内联汇编程序是一个棘手的问题,正是因为你
不知道编译器用于什么寄存器.通常,在
除了实际的汇编程序指令外,还有指令
告诉编译器你是哪些寄存器和哪些变量
使用,你将能够在中引用变量本身
汇编程序和其他此类信息.除非你使用这些,否则你可以
关于内联汇编程序,假设非常非常少.
但每个编译器都有自己的规则.经常使用特殊语法.
像mov eax,[cx] .x或者mov eax,x这样的东西可能是
Microsoft内联汇编程序需要什么.无论如何,没有办法
从你所写的,编译器可能推断出它
你正在访问c.x.而且因为所有其他用途都已被淘汰
通过不断传播,它甚至可能是一个非常差的编译器
生成变量c.
编辑:
FWIW:微软内联汇编程序的文档是
http://msdn.microsoft.com/en-us/library/4ks26t93%28v=vs.71%29.aspx.我没有仔细看过它,但有一节关于“使用C或C __asm中的符号阻止“.这可能会解释你怎么做以编译器将知道的方式访问内联汇编程序中的x已访问x.