According to the MSDN documentation the “this” pointer is stored in ECX when using the default __thiscall calling convention for class functions. Despite this certainly being the case when translating regular C++ code I have encountered a problem when trying to access “this” with inline assembly.
Here’s the test program:
#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;
}
The two Get functions are translated like this:
?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
I think it’s safe to say that these two functions are identical. Nevertheless, here’s the output from the program:
c.getX1() = 42
c.getX2() = 1
Obviously “this” is not stored in ECX when the second Get function is invoked, so my question is: How do I ensure that class functions containing inline assembly follow the calling convention and/or are invoked the same way as regular/non-inlined functions?
EDIT: The main function is translated like this:
_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
This is how I managed to make the function work corretly (ie. pass “this” in ECX):
testclass.hpp:
testclass.cpp:
testmain.cpp:
Output:
The problem is that inlined class functions in MSVC 2010 not necessarily follow the calling conventions specified by MSDN. I don’t think this is a bug, but you should at least be aware of it if you are planning to use inline assembly in inlined functions. My advice is that you don’t do it. If you need inline assembly in a class function keep the declaration and implementation separated.