1

我在 NASM 中为 Windows 进行汇编编程,我在代码中发现了这一点:

extern _ExitProcess@4
  ;Rest of code...
  ; ...
call  _ExitProcess@4

@4winapi库函数的声明和调用是什么意思?

4

3 回答 3

6

winapi 使用 __stdcall 调用约定。调用者将堆栈上的所有参数从右向左推送,被调用者再次弹出它们以清理堆栈,通常使用RET n指令。

它是 __cdecl 调用约定的对立面,这是 C 和 C++ 代码中的常见默认值,调用者清理堆栈,通常ADD ESP,n在 CALL 之后使用指令。__stdcall 的优点是它生成更紧凑的代码,在被调用的函数中只需要一条清理指令,而不是每次调用函数都需要多条清理指令。但有一个很大的缺点:它很危险。

危险潜伏在调用该函数的代码中,该代码已使用过时的函数声明进行编译。例如,通过添加参数更改函数时的典型情况。这结果很糟糕,除了函数试图使用不可用的参数之外,新函数会从堆栈中弹出太多参数。这会使堆栈不平衡,不仅导致被调用者失败,还导致调用者失败。极难诊断。

所以他们对此做了一些事情,他们装饰了函数的名称。首先使用前导 _underscore,就像对 __cdecl 函数所做的那样。并附加@n, 的值是函数末尾指令n的操作数。RET或者换句话说,堆栈上的参数占用的字节数。

这会在出现不匹配时提供链接器诊断,例如生成名称的foo(int)函数更改。尚未重新编译的调用代码将寻找一个函数。链接器失败,它找不到该符号。灾难避免了。foo(int, int)_foo@8_foo@4

于 2013-09-15T13:56:08.640 回答
5

C 的名称装饰方案记录在Format of a C Decorated Name中。包含@字符的修饰名称用于__stdcall调用约定:

__stdcall: 前导下划线 ( _) 和尾随符号 ( @) 后跟一个数字,表示参数列表中的字节数

Dependency Walker这样的工具能够显示修饰和未修饰的名称。

非官方文档可以在这里找到:名称装饰

于 2013-09-15T13:27:19.497 回答
3

这是一个名称装饰,指定函数参数的总大小:

名称后跟 at 符号 (@),后跟参数列表中的字节数(十进制)。

来源

于 2013-09-15T12:50:42.817 回答