ARMv6架构STM32二进制r0/r3传参r1返回调用约定问题咨询
结论
你观察到的是编译器针对局部小型叶函数的自定义寄存器优化结果,不属于通用标准调用约定,也不是某款编译器的专属特性。
特殊调用约定的出现原因
- ARM官方通用的AAPCS调用约定要求前4个参数按
r0→r1→r2→r3的顺序传递,返回值存入r0,这个规则是为了保证不同编译单元、不同编译器生成的代码可以互相调用,属于对外暴露的函数必须遵守的公共规则。 - 你遇到的这类函数都是仅在当前编译单元内部调用的小型叶函数(即函数内部不会再调用其他函数,也不需要操作栈存储寄存器上下文),编译器开启优化(
-Os大小优化、-O2/-O3速度优化)时,会完全跳过通用调用约定的限制,根据函数内部的操作逻辑自由分配寄存器,目的是减少不必要的寄存器数据搬运,缩小代码体积、提升执行效率。 - 以你给出的
check_if_bit_is_set函数为例:编译器把bit参数直接放在r0,刚好可以直接作为lsls指令的移位操作数,不需要额外做一次寄存器数据移动,相比遵守标准AAPCS的实现可以少1~2条指令。 - 你没有观测到3个及以上参数的同类函数是正常情况:参数数量过多时,自由分配寄存器带来的收益会被栈操作的额外开销抵消,编译器会优先选择遵守通用调用约定降低逻辑复杂度。
约定的归属性质
- 这类自定义寄存器分配是所有主流ARM编译器(GCC、ARMCC、IAR)都支持的优化策略,不属于某款编译器的专属特性,不同编译器的寄存器分配逻辑有差异,你观测到的这个参数分配规律大概率是GCC ARM编译器的优化结果。
- 这种优化只会作用于编译器可以完整观测到所有调用点的函数(比如
static修饰的静态函数、开启链接时优化后整个程序内可见的局部函数),对外暴露的全局函数绝对不会采用这种约定,否则会出现跨编译单元调用的兼容性问题。
内容的提问来源于stack exchange,提问作者Octetz
相关产品推荐
相关产品推荐

