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

GCC中C与汇编代码间参数传递及返回值机制问询

GCC下C与汇编的参数传递及返回值规则

嘿,这个问题问到点子上了——搞C和汇编混合编程的时候,最核心的就是摸透GCC的调用约定,不然参数传递和返回值分分钟出问题!下面我就针对最常用的32位x86和64位x86_64架构,结合你写的int f(int arg)函数,把规则讲得明明白白:

1. 返回值的传递逻辑

不管是32位还是64位架构,对于int这类整数型返回值,规则特别统一:

  • 32位x86:返回值会存在%eax寄存器里
  • 64位x86_64:返回值会存在%rax寄存器里
    举个例子,你的函数f如果要返回arg + 1,只要把计算结果放到对应的寄存器里,直接ret就行,完全不需要操作栈。

2. 参数的传递方式

这里不同架构差异很大,咱们分开说:

2.1 32位x86(i386 System V ABI)

这种架构下GCC默认用栈传递参数,而且是从右往左入栈(不过你的函数只有一个参数,所以逻辑更简单):

  • 当C代码调用f(arg)时,会先把arg的值push到栈上,再执行call指令调用f
  • call指令会把返回地址压到栈顶,所以在f的汇编实现里,参数arg的位置是%esp + 4(栈顶是返回地址,占4字节)
  • 通常写汇编函数时,会先建立栈帧:push %ebp然后mov %esp, %ebp,这样参数就可以通过%ebp + 8来访问(%ebp本身占4字节,加上返回地址的4字节,偏移量就是8)

2.2 64位x86_64(System V AMD64 ABI)

这是寄存器优先的传递方式,效率更高:

  • 前6个整数/指针类型的参数,会依次放到%rdi, %rsi, %rdx, %rcx, %r8, %r9这6个寄存器里
  • 你的函数f只有一个int参数,所以这个arg会直接存在%rdi寄存器里(因为int是32位,也可以用它的低32位寄存器%edi)
  • 如果参数数量超过6个,剩下的才会用栈传递,同样遵循从右往左入栈的规则

3. 关于你的编译选项

你写的编译选项是gcc -Wall -g -std=c99 -pedantic -g(注意笔误啦,是gcc不是gccc),这些选项里没有修改调用约定的参数,所以GCC会自动采用目标架构的默认调用约定——比如你在64位系统上编译,就用System V AMD64 ABI;32位系统上就用i386的栈传递规则。

4. 给你两个实际的汇编例子

x86_64架构下的实现

如果你的f函数要返回参数加1,汇编代码可以这么写:

.global f
f:
    movl %edi, %eax   # 把参数(%edi是%rdi的低32位)放到返回值寄存器%eax
    addl $1, %eax     # 参数加1
    ret               # 返回,%eax里就是结果

32位x86架构下的实现

.global f
f:
    push %ebp         # 保存旧的栈帧基址
    mov %esp, %ebp    # 建立新的栈帧
    movl 8(%ebp), %eax# 从栈中取出参数(%ebp+8是第一个参数的位置)
    addl $1, %eax     # 参数加1
    pop %ebp          # 恢复旧栈帧
    ret               # 返回

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:34:37