【问题标题】:Windows function names followed by @ number symbol?Windows函数名称后跟@数字符号?
【发布时间】:2013-09-19 16:31:46
【问题描述】:

我在 NASM 中为 Windows 进行汇编编程,我在代码中找到了这个:

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

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

【问题讨论】:

    标签: winapi assembly nasm stdcall


    【解决方案1】:

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

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

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

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

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

    【讨论】:

    • +1 对比__cdecl__stdcall 以推断名称装饰的必要性。非常好的解释,超越了它是什么,并解释了为什么
    【解决方案2】:

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

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

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

    非官方文档可以在这里找到:Name Decoration

    【讨论】:

      【解决方案3】:

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

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

      (source)

      【讨论】:

      • 谢谢。有没有办法确定有多少字节?
      • 如果是 Windows API 函数,您可以在 msdn 查找函数原型。然后你只需将参数的大小相加。例如,CreateThread 有六个参数,每个参数大小为 4 个字节(这需要了解所使用的类型)。所以符号是_CreateThread@24
      • 谢谢,很有帮助。
      猜你喜欢
      • 2011-01-03
      • 2016-12-12
      • 2018-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多