如何入栈xPSR?ARM汇编条件执行结果保留问题咨询
解决ARM汇编中保存xPSR的问题
你遇到的问题很典型——ARM的xPSR属于特殊功能寄存器,不能像R0-R15这类通用寄存器一样直接用PUSH/POP操作,这就是汇编器报错“bad register symbol”的原因。不过ARM架构提供了专门的指令来读写特殊寄存器,完美解决你的需求。
核心思路:用MRS/MSR中转通用寄存器
要保存xPSR的状态(其实你只需要CMP后的条件标志位,也就是APSR里的NZCV位),必须先把特殊寄存器的值转到通用寄存器,再保存到栈;恢复时反向操作即可。
修改后的代码示例
这里以保存APSR(xPSR中负责条件标志的部分)为例,比保存整个xPSR更安全,避免干扰其他状态位:
CMP R1, R2 ; 保存条件标志位到栈 MRS R3, APSR ; 将APSR(含NZCV标志)的值读到R3 PUSH {R3} ; 把R3压栈保存 BLEQ SUBROUTINE1 ; 调用子程序,即使它修改了PSR也没关系 ; 恢复之前的条件标志位 POP {R3} ; 从栈中恢复R3的值 MSR APSR_nzcvq, R3 ; 只把NZCV等标志位写回APSR,不修改其他状态 ADDEQ R4, #5 ; 现在这条指令会正确依赖最初CMP R1,R2的结果
细节说明
为什么选APSR而非xPSR?
xPSR是APSR(应用状态寄存器)、IPSR(中断状态寄存器)、EPSR(执行状态寄存器)的整合体。你只需要CMP后的条件判断标志(Z位是否为1),所以直接操作APSR的nzcvq域(对应负、零、进位、溢出标志)就足够,避免误改中断/执行状态。寄存器选择的注意事项
示例中用了R3,如果你遵循ARM的ATPCS调用规范,R0-R3属于调用者保存寄存器——子程序可能会修改它们,但我们在调用前已经把R3压栈,所以不会有问题。你也可以用其他不被子程序破坏的寄存器(比如R12,即IP寄存器),只要确保栈操作对应就行。特权级限制(如果有)
如果你的代码运行在用户模式下,直接写整个xPSR会被拒绝,但写APSR的nzcvq域是允许的,这也是我们推荐只恢复标志位的另一个原因。
这样修改后,SUBROUTINE1对PSR的修改就不会影响ADDEQ的执行条件了。
内容的提问来源于stack exchange,提问作者muyustan
相关产品推荐
相关产品推荐

