Compatibility with MSVC __thiscall?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello,

I'm trying to build a basic plugin system, where the main application is compiled with MSVC++, but the plugins are compiled with GCC.

application.cpp:

#include <windows.h>

int main(int argc, char *argv[]) {
	HMODULE hDll = LoadLibrary(argv[1]);

	typedef GUID (__thiscall *pget_guid)(void *this_ptr, int index);
	pget_guid get_guid = (pget_guid)GetProcAddress(hDll, "get_guid");

	GUID guid = get_guid(NULL, 1);

	CHAR str[64] = {0};
	wsprintf(str, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
		guid.Data1, guid.Data2, guid.Data3,
		guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
		guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
	OutputDebugString(str);
	
	FreeLibrary(hDll);
	return 0;
}

plugin1.c:

#include <windows.h>

__declspec(dllexport) GUID __thiscall get_guid(void *this, int index) {
	static const GUID guid_null = { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
	static const GUID guid_test = { 0xffffffff, 0xffff, 0xffff, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
	return (index == 0) ? guid_null : guid_test;
}

I expected this to work, however the application crashes with segfault. So I came up with plugin2.c, which "emulates" the MSVC __thiscall:

#include <windows.h>

__declspec(dllexport) GUID __stdcall get_guid(int index) {
	void *this = NULL;
	asm("movl %%ecx, %0" : : "m" (this));

	static const GUID guid_null = { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
	static const GUID guid_test = { 0xffffffff, 0xffff, 0xffff, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
	return (index == 0) ? guid_null : guid_test;
}

And it worked! Below are -O0 dumps of both functions:

<_get_guid_stdcall@4>:								<_get_guid_thiscall>:
	push   ebp											push   ebp
	mov    ebp,esp										mov    ebp,esp
	push   edi											push   edi
	push   esi											push   esi
	push   ebx											push   ebx
*	sub    esp,0x20										sub    esp,0x14
	mov    DWORD PTR [ebp-0x20],ecx						mov    DWORD PTR [ebp-0x20],ecx
	cmp    DWORD PTR [ebp+0xc],0x0						cmp    DWORD PTR [ebp+0xc],0x0
	jne    L1											jne    L1
	lea    ebx,[ebp-0x1c]								lea    ebx,[ebp-0x1c]
	mov    al,0x0										mov    al,0x0
	mov    edx,0x10										mov    edx,0x10
	mov    edi,ebx										mov    edi,ebx
	mov    ecx,edx										mov    ecx,edx
	rep stos BYTE PTR es:[edi],al						rep stos BYTE PTR es:[edi],al
	jmp    L2											jmp    L2
L1:													L1:
	lea    edx,[ebp-0x1c]								lea    edx,[ebp-0x1c]
	mov    ebx,0x67a03024								mov    ebx,0x64a03024
	mov    eax,0x4										mov    eax,0x4
	mov    edi,edx										mov    edi,edx
	mov    esi,ebx										mov    esi,ebx
	mov    ecx,eax										mov    ecx,eax
	rep movs DWORD PTR es:[edi],DWORD PTR ds:[esi]		rep movs DWORD PTR es:[edi],DWORD PTR ds:[esi]
L2:													L2:
*	mov    eax,DWORD PTR [ebp+0x8]						mov    eax,DWORD PTR [ebp-0x20]
	mov    edx,eax										mov    edx,eax
	lea    ebx,[ebp-0x1c]								lea    ebx,[ebp-0x1c]
	mov    eax,0x4										mov    eax,0x4
	mov    edi,edx										mov    edi,edx
	mov    esi,ebx										mov    esi,ebx
	mov    ecx,eax										mov    ecx,eax
	rep movs DWORD PTR es:[edi],DWORD PTR ds:[esi]		rep movs DWORD PTR es:[edi],DWORD PTR ds:[esi]
*	mov    eax,DWORD PTR [ebp+0x8]						mov    eax,DWORD PTR [ebp-0x20]
*	add    esp,0x20										add    esp,0x14
	pop    ebx											pop    ebx
	pop    esi											pop    esi
	pop    edi											pop    edi
	pop    ebp											pop    ebp
	ret    0x8											ret    0x8

The differences are marked with asterix. The problem seems to appear when I'm dealing with GUIDs, as __thiscall worked fine when I've been doing simple int or char* manipulations. Why does `_get_guid_thiscall` compile to a *slightly* different code, what's the reason behind it? Is it possible to compile a function, fully compatible with MSVC __thiscall?

The reason I'm using thiscall convention is that actually, the real application I'm messing with expects C++ class method implementations.

Thanks.





[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux