You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux与Windows x86汇编调用约定及printf符号问题咨询

x86汇编调用约定与函数名修饰的常见问题解答

背景与代码示例

用户编写的Windows汇编代码如下:

section .data
msg:  db "my message", 0ah, 0

section .text
_main:
        
    push   msg
    call   _printf
    add    esp, 4

核心问题解答

1. Windows是否支持两种调用约定?

是的,Windows同时支持栈传参和寄存器传参的调用约定。32位平台主流使用栈传参的cdecl/stdcall约定,也存在fastcall这类允许部分参数通过寄存器传递的约定;64位平台则统一采用基于寄存器的Microsoft x64调用约定。

2. 如何确定应使用哪种调用约定?

  • 先看目标平台位数:64位Windows程序必须遵循Microsoft x64寄存器传参约定;32位平台可选择,但必须与调用的函数约定匹配。
  • 匹配目标函数的规范:比如标准C库的printf,32位Windows下遵循cdecl(栈传参,调用者清理栈),64位下遵循Microsoft x64约定(寄存器传参)。
  • 课堂场景优先遵循课程要求;自定义函数时,需明确约定并保证调用方与被调用方规则一致。

3. 32位与64位x86程序的调用约定是否存在差异?

差异非常显著:

  • 32位x86:以栈传参为主,主流约定是cdecl(调用者清栈)和stdcall(被调用者清栈);fastcall作为补充,用ECX/EDX传递前两个参数,剩余参数入栈。
  • 64位x86(AMD64):Windows和Linux均采用寄存器传参,但规则不同:
    • Windows:前4个整数/指针参数用RCX、RDX、R8、R9传递,浮点参数用XMM0-XMM3,剩余参数入栈,由调用者负责清理栈空间。
    • Linux:前6个整数/指针参数用RDI、RSI、RDX、RCX、R8、R9传递,浮点参数用XMM0-XMM7,由被调用者清理栈。

关于printf函数名下划线的问题

这种差异是函数名修饰规则导致的:

  • 32位Windows的C编译环境中,cdecl约定的函数会被自动添加前缀下划线,比如printf会被修饰为_printf,因此汇编代码中必须调用_printf才能匹配标准库的符号。
  • 无需加下划线的场景,大多是因为使用了64位环境:64位Windows的函数名修饰规则去掉了前缀下划线,直接使用printf即可;少数情况是工具链默认配置不同,但你提到未使用NASM选项,基本可以确定是64位环境的原因。

内容的提问来源于stack exchange,提问作者Tim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 22:52:19