Win32 Assembly - 外部函数命名('@'的含义)
Win32 Assembly - Extern function naming (The meaning of '@')
正如我所见,extern
汇编代码中的 WinAPI 函数的名称类似于 _ExitProcess@4
。
@4
部分是什么意思,如何确定@
后面使用什么数字?
我知道这与我们链接的 DLL 有关,但在很多情况下,不知道在 @
之后使用什么数字,这会导致许多令人讨厌的 undefined reference
错误。
如果您想获取要使用的号码,请确保将 _NT_SYMBOL_PATH 定义为正确的值。
喜欢:
srv*https://msdl.microsoft.com/download/symbols
或
srv*c:\MyServerSymbols*https://msdl.microsoft.com/download/symbols
例如(在cmd.exe、windows命令行中):
set _NT_SYMBOL_PATH=srv*https://msdl.microsoft.com/download/symbols
然后使用:
dumpbin /exports /symbols kernel32.lib | findstr _ExitProcess@
您必须在 kernel32 所在的目录中,并且必须有 grep。
可能是一种使用内置查找命令的方法。您也可以将它重定向到一个文件,然后在您的编辑器中查看它。
当为函数指定 stdcall 调用约定时,@ 符号作为前导下划线是函数名称的一部分。
该数字指定函数从堆栈中删除的字节数。
编译器生成这个数字。
添加后缀是为了不会意外调用函数时使用错误的调用约定或源代码中的原型指定了错误的参数数量或大小。所以目的是提供一种避免程序崩溃的方法。
正如 Andreas H 的回答所说,@
之后的数字是函数在函数 returns 之前从堆栈中删除的字节数。这意味着应该很容易确定该数字,因为它也是您需要压入堆栈以正确调用该函数的字节数。它应该是调用前的 PUSH 指令数乘以 4。在大多数情况下,这也将是传递给函数的参数数乘以 4。
如果您想仔细检查您获得的号码是否正确并且您安装了 Microsoft Visual Studio,您可以从开发人员命令提示符中找到装饰符号名称,如下所示:
C:\> dumpbin /headers kernel32.lib | find "ExitProcess"
Symbol name : _ExitProcess@4
Name : ExitProcess
如果您使用 MinGW 编译器工具link您的汇编代码,您可以改为这样做:
C:\> nm C:\MinGW\lib\libkernel32.a | find "ExitProcess"
00000000 I __imp__ExitProcess@4
00000000 T _ExitProcess@4
您需要将 C:\MinGW
替换为您安装 MinGW 的目录。
因为并非所有 Windows API 都驻留在 kernel32
导入库中,因此您需要将 kernel32
替换为在Windows 您想要 link 的 API 功能的 SDK 文档。例如,对于 MessageBoxA
,您需要将 user32.lib
与 Visual Studio 一起使用,将 libuser32.a
与 MinGW 一起使用。
请注意,很少有 Windows API 不使用 stdcall
调用约定。这些函数如 wsprintf
接受可变数量的参数,stdcall
调用约定不支持。这些函数只是在它们的名称前有一个下划线 _
,后面没有 @
或数字。他们还要求调用者从堆栈中删除参数。
正如我所见,extern
汇编代码中的 WinAPI 函数的名称类似于 _ExitProcess@4
。
@4
部分是什么意思,如何确定@
后面使用什么数字?
我知道这与我们链接的 DLL 有关,但在很多情况下,不知道在 @
之后使用什么数字,这会导致许多令人讨厌的 undefined reference
错误。
如果您想获取要使用的号码,请确保将 _NT_SYMBOL_PATH 定义为正确的值。
喜欢:
srv*https://msdl.microsoft.com/download/symbols
或
srv*c:\MyServerSymbols*https://msdl.microsoft.com/download/symbols
例如(在cmd.exe、windows命令行中):
set _NT_SYMBOL_PATH=srv*https://msdl.microsoft.com/download/symbols
然后使用:
dumpbin /exports /symbols kernel32.lib | findstr _ExitProcess@
您必须在 kernel32 所在的目录中,并且必须有 grep。
可能是一种使用内置查找命令的方法。您也可以将它重定向到一个文件,然后在您的编辑器中查看它。
当为函数指定 stdcall 调用约定时,@ 符号作为前导下划线是函数名称的一部分。
该数字指定函数从堆栈中删除的字节数。
编译器生成这个数字。
添加后缀是为了不会意外调用函数时使用错误的调用约定或源代码中的原型指定了错误的参数数量或大小。所以目的是提供一种避免程序崩溃的方法。
正如 Andreas H 的回答所说,@
之后的数字是函数在函数 returns 之前从堆栈中删除的字节数。这意味着应该很容易确定该数字,因为它也是您需要压入堆栈以正确调用该函数的字节数。它应该是调用前的 PUSH 指令数乘以 4。在大多数情况下,这也将是传递给函数的参数数乘以 4。
如果您想仔细检查您获得的号码是否正确并且您安装了 Microsoft Visual Studio,您可以从开发人员命令提示符中找到装饰符号名称,如下所示:
C:\> dumpbin /headers kernel32.lib | find "ExitProcess"
Symbol name : _ExitProcess@4
Name : ExitProcess
如果您使用 MinGW 编译器工具link您的汇编代码,您可以改为这样做:
C:\> nm C:\MinGW\lib\libkernel32.a | find "ExitProcess"
00000000 I __imp__ExitProcess@4
00000000 T _ExitProcess@4
您需要将 C:\MinGW
替换为您安装 MinGW 的目录。
因为并非所有 Windows API 都驻留在 kernel32
导入库中,因此您需要将 kernel32
替换为在Windows 您想要 link 的 API 功能的 SDK 文档。例如,对于 MessageBoxA
,您需要将 user32.lib
与 Visual Studio 一起使用,将 libuser32.a
与 MinGW 一起使用。
请注意,很少有 Windows API 不使用 stdcall
调用约定。这些函数如 wsprintf
接受可变数量的参数,stdcall
调用约定不支持。这些函数只是在它们的名称前有一个下划线 _
,后面没有 @
或数字。他们还要求调用者从堆栈中删除参数。