Cortex M3在函数调用时,压栈和出栈操作
以下内容由AI生成,稍加整理如下:几个关键点:1. 在执行BL或BLX指令调用函数时,将返回地址存入 LR。2. 在进入被调函数后,通过指令将可能用到的寄存器压栈(一般由编译器完成)。3. 执行被调函数。4. 通过指令将之前保存的寄存器出栈,恢复调用之前的现场。5. 将LR寄存器内容加载到PC寄存器。6. 执行PC寄存器指向的代码,实现函数调用返回。注意:在 PUSH 和 POP 的寄存器列表中,
以下内容由AI生成,稍加整理如下:
几个关键点:
1. 在执行 BL或 BLX指令调用函数时,硬件自动将返回地址存入 LR。
2. 在进入被调函数后,通过PUSH {reg_list}指令将可能用到的寄存器压栈(一般由编译器完成)。
3. 执行被调函数。
4. 通过pop{reg_list}指令将之前保存的寄存器出栈,恢复调用之前的现场(一般由编译器完成)。
5. 将LR寄存器内容加载到PC寄存器。
6. 执行PC寄存器指向的代码,实现函数调用返回。
注意:在 PUSH 和 POP 的寄存器列表中,无论书写顺序如何,汇编器通常会按寄存器编号升序排序。但压栈时,编号大的寄存器先入栈;出栈时,顺序则相反。
Cortex-M3 在函数调用时的压栈和出栈操作,是其运行机制的核心之一,关键在于保护现场和正确返回。为了让你快速把握其核心要点,我先用一个表格来汇总关键信息。
|
关键概念 |
在 Cortex-M3 函数调用中的具体体现 |
|---|---|
|
核心指令 |
|
|
堆栈模型 |
满递减 (Full Descending): 堆栈指针(SP)先减4(向低地址生长),再存入数据。 |
|
链接寄存器 (LR) |
R14 (LR):在执行 |
|
返回技巧 |
|
💡 函数调用过程详解
下面我们一步步来看函数调用过程中,堆栈是如何工作的。
-
进入被调用函数
-
当通过
BL FunctionName指令调用函数时,处理器会自动将下一条指令的地址(返回地址)存入链接寄存器 (LR, R14)。由于 Cortex-M3 始终处于 Thumb 状态,存入 LR 的地址其最低位 (LSB) 会被硬件置为 1。 -
进入被调用函数后,编译器生成的代码通常会首先使用
PUSH {reg_list}指令保存需要保护的寄存器。例如,PUSH {R4, R5, LR}会将寄存器 R4、R5 以及 LR 的值压入堆栈。此时,SP 会先递减相应的字节数(例如压入3个寄存器则减12),然后将寄存器值存入内存。
-
-
执行函数体
-
函数体内的代码可以安全地使用这些已经保存的寄存器。
-
-
离开被调用函数
-
函数执行完毕后,需要恢复现场。使用
POP {reg_list}指令将之前压入堆栈的寄存器值按相反的顺序弹出(先进后出)。此时,SP 会相应递增。 -
一个常见且高效的返回技巧是使用
POP {R4, R5, PC}。这相当于直接将返回地址装载到程序计数器 (PC) 中,从而同时完成寄存器恢复和函数返回,省去了显式的BX LR指令。 -
执行返回后,程序将跳转回到 LR 所保存的地址(注意,在跳转时,最低位的 1 会被硬件忽略,以确保正确的指令对齐)继续执行。
-
⚡️ 中断引发的自动压栈
在中断或异常等场景下,为了追求极致的响应速度,Cortex-M3 的硬件会自动完成压栈操作。当异常发生时,处理器会自动将8个寄存器的值(R0-R3, R12, LR, PC, xPSR)压入当前堆栈中。中断服务程序 (ISR) 开始时,如果还需要使用其他寄存器(如 R4-R11),则需要通过软件指令先压栈保存。中断返回时,硬件会自动将之前压栈的寄存器值恢复。
🔄 双堆栈机制(MSP 与 PSP)
Cortex-M3 支持主堆栈指针 (MSP) 和进程堆栈指针 (PSP)。CONTROL 寄存器的位1决定了当前使用哪一个。
-
MSP:这是处理器的默认堆栈指针,复位后即使用 MSP。它主要用于操作系统内核、异常处理程序以及所有需要特权访问的代码,为系统关键部分提供一个独立、受保护的堆栈空间。
-
PSP:通常用于用户应用程序或任务。在使用实时操作系统 (RTOS) 时,每个任务通常都有自己的 PSP 堆栈空间,这样可以实现任务间的内存隔离,增强系统的稳定性和安全性。
⚠️ 重要注意事项
-
对齐要求:PUSH 和 POP 操作要求地址是 4 字节对齐 的。SP 的最低两位被硬件强制为 0,以满足这一要求。
-
寄存器顺序:在 PUSH 和 POP 的寄存器列表中,无论书写顺序如何,汇编器通常会按寄存器编号升序排序。但压栈时,编号大的寄存器先入栈;弹栈时,顺序则相反。
-
LR 位 0 的处理:在前文提到的返回技巧
POP {..., PC}中,由于弹出到 PC 的地址最低位是 1,这明确指示处理器保持在 Thumb 状态,从而能正确执行返回。
更多推荐


所有评论(0)