ARM上函数调用参数超过四个的时传递方法

本文详细解析了ARM架构中函数参数如何通过寄存器和栈进行传递的过程,并通过一个具体的示例展示了当参数数量超过四个时,如何利用栈来传递额外的参数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

众所周知,ARM架构下,函数参数是通过 r0~r4寄存器传递的;但是如果参数超过四个,就要借助于栈了。

下面以一个例子说明。

int func(int a1, int a2, int a3, int a4, int a5, int a6)
{
	return a1 + a2 + a3 + a4 + a5;
}

int main(void)
{
	func(1, 2, 3, 4, 5, 6);
	return 0;
}
main()的汇编如下:

   0x00010418 <+0>:	push	{r11, lr}
   0x0001041c <+4>:	add	r11, sp, #4
   0x00010420 <+8>:	sub	sp, sp, #8
   0x00010424 <+12>:	mov	r3, #5
   0x00010428 <+16>:	str	r3, [sp]
   0x0001042c <+20>:	mov	r3, #6
   0x00010430 <+24>:	str	r3, [sp, #4]
   0x00010434 <+28>:	mov	r0, #1
   0x00010438 <+32>:	mov	r1, #2
   0x0001043c <+36>:	mov	r2, #3
   0x00010440 <+40>:	mov	r3, #4
----> 0x00010444 <+44>:	bl	0x103c8 <func>
   0x00010448 <+48>:	mov	r3, #0
   0x0001044c <+52>:	mov	r0, r3
   0x00010450 <+56>:	sub	sp, r11, #4
   0x00010454 <+60>:	pop	{r11, pc}
这个时候(执行到箭头指向的位置),栈的状态如下:


函数 func的汇编如下:

   0x000103c8 <+0>:	push	{r11}		; (str r11, [sp, #-4]!)
   0x000103cc <+4>:	add	r11, sp, #0
   0x000103d0 <+8>:	sub	sp, sp, #20
   0x000103d4 <+12>:	str	r0, [r11, #-8]
   0x000103d8 <+16>:	str	r1, [r11, #-12]
   0x000103dc <+20>:	str	r2, [r11, #-16]
   0x000103e0 <+24>:	str	r3, [r11, #-20]	; 0xffffffec
   0x000103e4 <+28>:	ldr	r2, [r11, #-8]
   0x000103e8 <+32>:	ldr	r3, [r11, #-12]
   0x000103ec <+36>:	add	r2, r2, r3
   0x000103f0 <+40>:	ldr	r3, [r11, #-16]
   0x000103f4 <+44>:	add	r2, r2, r3
   0x000103f8 <+48>:	ldr	r3, [r11, #-20]	; 0xffffffec
----> 0x000103fc <+52>:	add	r2, r2, r3
   0x00010400 <+56>:	ldr	r3, [r11, #4]
   0x00010404 <+60>:	add	r3, r2, r3
   0x00010408 <+64>:	mov	r0, r3
   0x0001040c <+68>:	sub	sp, r11, #0
   0x00010410 <+72>:	pop	{r11}		; (ldr r11, [sp], #4)
   0x00010414 <+76>:	bx	lr

此时,栈状态如下:


ldr	r3, [r11, #4]
上面这一句汇编代码就是从栈上取回保存的第5个参数的值。

(gdb) x /x $r11 + 4
0xbefffcd0:	0x00000005


### 中断寄存器 R0 至 R15 的作用及用法 #### 寄存器分类及其功能 ARM 架构下的通用寄存器包括 R0 到 R15,依据其特性可分为三类:未分组寄存器 (R0 ~ R7),分组寄存器 (R8 ~ R14),以及程序计数器 PC (R15)[^1]。 - **未分组寄存器 (R0 ~ R7)** 这些寄存器在不同工作模式下具有相同的功能定义,在任何异常模式间共享同一物理寄存器。这类寄存器通常用于数据传递和临存储变量值。 - **分组寄存器 (R8 ~ R14)** 此类别中的某些成员会根据当前处理器所处的状态拥有不同的实例化版本;例如 FIQ 快速中断模式会有自己独立的一套 R8_fiq 至 R12_fiq 来支持更高效的快速响应机制。而像链接寄存器 LR 即 R14,则专门用来保存子程序调用前的返回地址以便后续跳转回原位置继续执行代码逻辑[^3]。 - **程序计数器 PC (R15)** 负责指向即将被执行指令的位置,即下一个要取指解码并最终执行的机器语言命令所在内存单元地址。值得注意的是,由于 ARM 处理器采用流水线技术,实际读取到的内容可能已经提前过了几条指令的距离。 #### 实际应用场景示例 考虑如下汇编代码片段展示如何利用上述提到的一些寄存器来实现基本的任务切换: ```assembly PUSH {R4, R5} ; 将 R4 和 R5 当前持有的数值推送到栈顶以备稍后恢复使用 POP {R6, R7} ; 从栈底取出先前保存的数据填充给 R6 及 R7 完成一次上下文还原过程 ``` 此段伪代码体现了操作系统内核或实操作系统 RTOS 如 FreeRTOS 在进行任务调度常见的做法——通过 PUSH/POP 操作保护现场环境从而确保多任务并发安全可靠地交替运行而不互相干扰[^2]。 另外,在发生硬件级别的异步事件比如外部设备触发 IRQ 请求同样需要遵循类似的流程先暂存 CPU 上下文再转向相应的服务例行程序处理之后再次回到原来被打断的地方接着往下走[^5]。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值