为什么C语言函数调用时参数按从右到左的顺序填充到寄存器?
为什么GCC会从右到左填充函数参数寄存器
你观察到的参数填充规则不是GCC的随机选择,而是x86-64架构下System V AMD64调用约定的统一要求,核心设计出发点是兼容C语言的可变参数函数,同时降低编译器实现复杂度,具体原因如下:
1. 兼容可变参数函数的实现需求
C语言支持printf这类参数个数不固定的可变参数函数,这类函数的首个参数是固定的(比如printf的格式化字符串),后续参数的数量和类型都需要通过首个参数的内容才能确定。
如果按从右到左的顺序处理参数:
- 处理完所有右侧的可变参数后,最后只需要把最左侧的固定参数放到第一个参数寄存器(x86-64下是
rdi)即可,不需要调整已经分配好的参数位置 - 可变参数的遍历逻辑
va_list/va_start也可以直接基于首个固定参数的地址,顺次向高地址读取后续所有参数,实现逻辑非常简洁。
如果换成从左到右的填充顺序,编译器处理到首个固定参数时,还不知道后面有多少个可变参数,后续分配寄存器/栈空间的时候很可能需要回头调整已经写好的寄存器值或者栈布局,实现成本会高很多。
2. 降低编译器的实现复杂度
早期计算机的内存和运算性能非常有限,编译器处理函数调用时,如果按从右到左的顺序遍历参数列表,只需要遍历一次就能完成所有参数的寄存器分配、栈偏移计算,不需要提前遍历一次统计参数总个数再做分配,能有效降低编译开销,这个设计也就作为惯例延续了下来。
额外说明
你测试的固定参数函数确实怎么填充都不影响结果——只要最终每个参数对应到了约定的寄存器(参数1对应rdi、参数2对应rsi、参数3对应rdx、参数4对应rcx)就行,哪怕你打乱顺序填充只要值对都能正常运行。但调用约定是面向所有函数类型的统一规则,必须兼顾可变参数的场景,自然不会为了符合人类阅读直觉单独给固定参数函数做特殊处理。
内容的提问来源于stack exchange,提问作者user16107274
相关产品推荐
相关产品推荐

