CALL_CONVENTION
CALL_CONVENTION
MSVC
为了让两个不同调用约定的能够互相调用,由于不同调用约定对于符号的不同修饰,我选择使用 dll 手动修改导入符号,防止符号错乱的问题。
这篇文章介绍了 MSVC 下各种调用约定。同一种调用约定在不同指令集架构下也是有区别的。
https://docs.microsoft.com/en-us/cpp/build/reference/gd-gr-gv-gz-calling-convention?view=msvc-160
其中有一个 vectorcall 似乎是为了优化而使用的。
0x01
//CdeclCall.c
#include <stdio.h>
//__declspec(dllexport)
void __cdecl foo(int a,int b){
printf("a = %d , b = %d ",a,b);
}
//FastCall.c
__declspec(dllimport) void __fastcall foo(int,int);
int main(){
foo(1,2);
return 0;
}
我们先看看 FastCall.c 编译出来的符号是什么形式的。
cl /c CdeclCall.c
dumpbin /SYMBOLS CdeclCall.obj
以下是结果
Microsoft (R) COFF/PE Dumper Version 14.28.29913.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file CdeclCall.obj
File Type: COFF OBJECT
COFF SYMBOL TABLE
000 010474D9 ABS notype Static | @comp.id
001 80010191 ABS notype Static | @feat.00
002 00000000 SECT1 notype Static | .drectve
Section length 2F, #relocs 0, #linenums 0, checksum 0
004 00000000 SECT2 notype Static | .debug$S
Section length 88, #relocs 0, #linenums 0, checksum 0
006 00000000 SECT3 notype Static | .text$mn
Section length 1A, #relocs 2, #linenums 0, checksum 7C27059A
008 00000000 SECT4 notype Static | .text$mn
Section length A, #relocs 1, #linenums 0, checksum 71A05264, selection 2 (pick any)
00A 00000000 SECT5 notype Static | .text$mn
Section length 29, #relocs 2, #linenums 0, checksum 2B25B17F, selection 2 (pick any)
00C 00000000 SECT6 notype Static | .text$mn
Section length 3A, #relocs 2, #linenums 0, checksum CAE6D625, selection 2 (pick any)
00E 00000000 SECT4 notype () External | ___local_stdio_printf_options
00F 00000000 UNDEF notype () External | ___acrt_iob_func
010 00000000 UNDEF notype () External | ___stdio_common_vfprintf
011 00000000 SECT5 notype () External | __vfprintf_l
012 00000000 SECT6 notype () External | _printf
013 00000000 SECT3 notype () External | _foo
014 00000008 UNDEF notype External | ?_OptionsStorage@?1??__local_stdio_printf_options@@9@9 (`__local_stdio_printf_options'::`2'::_OptionsStorage)
015 00000000 SECT7 notype Static | .data
Section length 11, #relocs 0, #linenums 0, checksum A358B0F1
017 00000000 SECT7 notype Static | $SG9219
018 00000000 SECT8 notype Static | .chks64
Section length 40, #relocs 0, #linenums 0, checksum 0
String Table Size = 0x90 bytes
Summary
40 .chks64
11 .data
88 .debug$S
2F .drectve
87 .text$mn
可以看见在 MSVC cdecl 下 foo 只是被简单修饰成为了 _foo,
但是当我们用同样的方法去查看 fastcall 修饰的 foo 时,会发现出现了一些变化。
@foo@8
很明显这两个不能链接。由此要有一些手动的操作,配置符号。
LIBRARY CdeclCall
EXPORTS
foo
cl .\CdeclCall.c /LD /DEF .\together.def
最后
link .\FastCall.obj .\CdeclCall.lib
得到一个神魔玩意儿
PS D:\Learn_Linker_elf_rtld\call_invention> D:\Learn_Linker_elf_rtld\call_invention\FastCall.exe
PS D:\Learn_Linker_elf_rtld\call_invention>
执行不了,ida 看看,程序上好像没什么问题,可能原因在动态链接器?留坑。。。
0x10
还有一种显示的动态链接,还没试过,可以尝试一波。
去官网找了一个 显示动态链接的模板,修改后有以下结果。
#include <windows.h>
#include <stdio.h>
//typedef int (__cdecl *MYPROC)(LPWSTR);
typedef void (__fastcall *MYPROC)(int,int);
int main( void )
{
HINSTANCE hinstLib;
MYPROC foo;
BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;
// Get a handle to the DLL module.
hinstLib = LoadLibrary(TEXT("CdeclCall.dll"));
// If the handle is valid, try to get the function address.
if (hinstLib != NULL)
{
foo = (MYPROC) GetProcAddress(hinstLib, "foo");
// If the function address is valid, call the function.
if (NULL != foo)
{
fRunTimeLinkSuccess = TRUE;
foo(1,2);
}
// Free the DLL module.
fFreeResult = FreeLibrary(hinstLib);
}
// If unable to call the DLL function, use an alternative.
if (! fRunTimeLinkSuccess)
printf("Message printed from executable\n");
return 0;
}
用 together.def CdeclCall.c 编译出 CdeclCall.dll
运行
有如下结果
PS D:\Learn_Linker_elf_rtld\call_invention> .\D_FastCall.exe
a = 608420 , b = 1
预期之中。好像学到了些什么。2333
GCC
留坑。。。
ld 的脚本麻烦一点,不过资料应该多一点。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 R0gerThat!
评论