【问题标题】:Using DLLs with NASM将 DLL 与 NASM 一起使用
【发布时间】:2012-03-25 16:10:47
【问题描述】:

我一直在使用 NASM 在 Windows 中进行一些 x86 编程,但我遇到了一些困惑。我很困惑为什么我必须这样做:

extern _ExitProcess@4

特别是我对“_”和“@4”感到困惑。我知道“@4”是堆栈的大小,但为什么需要它?当我用十六进制编辑器查看 kernel32.dll 时,我只看到“ExitProcess”而不是“_ExitProcess@4”。

我也很困惑为什么 C 函数不需要下划线和堆栈大小,例如:

extern printf

为什么 C 函数不需要修饰?

我的第三个问题是“我应该以这种方式使用这些功能吗?”现在我正在链接实际的 dll 文件本身。

【问题讨论】:

    标签: windows dll assembly x86 nasm


    【解决方案1】:

    我知道 '@4' 是堆栈的大小,但为什么需要它?

    如果您的编译器假定函数的调用约定错误,使链接器能够报告致命错误(如果您忘记在 C 中包含头文件并忽略所有编译器警告,或者如果声明不完全正确,则可能会发生这种情况匹配共享库中的函数)。

    为什么 C 函数不需要修饰?

    使用cdecl 调用约定的函数用单个前导修饰(因此它实际上是_printf)。

    没有参数大小编码到修饰名称的原因是调用者负责设置和拆除堆栈,因此参数计数不匹配对堆栈设置不会是致命的(尽管调用函数可能当然,如果没有给出正确的论点,它仍然会崩溃)。甚至可能参数计数是可变的,例如 printf

    当我使用十六进制编辑器查看 kernel32.dll 时,我只看到 ExitProcess 而不是 _ExitProcess@4

    损坏的名称通常使用定义文件 (*.def) 映射到 DLL 的实际导出名称,然后编译为可在链接器调用中使用的 *.lib 导入库文件。 kernel32.dll 的这种定义文件的一个示例是 this one。以下行定义了ExitProcess 的映射:

    _ExitProcess@4 = ExitProcess
    

    这是我应该使用这些功能的方式吗?

    我不太了解 NASM,但到目前为止我看到的代码通常指定修饰名称,就像在您的示例中一样。

    您可以找到更多信息on this excellent page about Win32 calling conventions

    【讨论】:

    • 我尝试在 'printf' 前面加上一个下划线,比如 'extern _printf',但它没有编译。关于为什么的任何想法?我将所有对 printf 的调用更改为“调用 _printf”。
    • @Hudson:它适用于extern printf / call printf?我很惊讶,我的 NASM 安装不是这种情况。也许您的 NASM 实际上知道调用约定?您是否使用了-fwin32 标志?
    • 是的,我就是这么想的。我将查看 NASM 文档以找到答案。
    • 是的,我做到了。我认为问题实际上是因为我使用的链接器。我正在使用 GoLink,我认为发生这种情况的原因在这里:masm32.com/board/index.php?topic=10770
    • @Hudson:也许您使用错误的.lib/.def 文件进行链接(Microsoft DLL 本身不会导出错误名称)。我使用link test.obj msvcrt.lib 使用MS 链接器。我在解决该问题的答案中添加了一段。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-04
    • 1970-01-01
    • 2020-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多