关于中断处理程序的问题

问题描述 投票:0回答:1

我目前正在开发一个简单的ARM固件。其中,我参与了与中断有关的部分。我将异常向量表中的IRQ异常向量与中断控制器中的中断处理程序进行了如下连接:

__attribute__ ((interrupt ("IRQ"))) void Irq_Handler(void) 
{
   interrupt_handler();
}

并转换为ARM汇编代码:

sub    lr, lr, #4
push   {r0, r1, r2, r3, r4, fp, ip, lr}
add    fp, sp, #28
bl     0 <interrupt_hanlder>
sub    sp, fp, #28
ldm    sp!, {r0, r1, r2, r3, r4, fp, ip, pc}^

我对此汇编代码有几个问题:

  1. 为什么将寄存器“​​ r0,r1,r2,r3,r4,fp,ip,lr”压入堆栈? (第二行)
  2. 它将8个寄存器压入堆栈。但是为什么它不减去32(4 * 8)而是28(4 * 7)? (第三行)
  3. 我不知道第6行末尾'^'的含义。

谢谢!

assembly gcc arm interrupt
1个回答
0
投票

为什么将寄存器“​​ r0,r1,r2,r3,r4,fp,ip,lr”压入堆栈?

之所以这样做,是因为这些寄存器可以通过功能interrupt_handler()进行修改。中断会在任何地方中断正在运行的程序。例如这里:

ldm r0, {r2, r3}
                 <=== The interrupt interrupts the program here
add r1, r2, r3

如果中断修改了某些寄存器(在示例中为r2r3,则被中断的程序将无法再正确运行。

因此,中断必须将所有寄存器恢复为其原始值。

函数interrupt_handler()不会修改寄存器r5r6,...,因此中断处理程序不需要恢复这些寄存器。

它将8个寄存器压入堆栈。但是为什么它不减去32(4 * 8)而是28(4 * 7)?

出于某种原因,fp寄存器应包含值sp+28。也许它应该指向lr寄存器的存储值。

假设sub sp, fp, #28的值自指令sp以来没有变化,则fp的指令将恢复add fp, sp, #28的值。

在您的情况下,sp没有更改,因此该指令是多余的。

我不知道第6行末^的含义。

^用于ldmstm指令,并且具有两种不同的效果。

两个效果之一是,加载pc寄存器也将加载psr寄存器。

要从中断返回,必须恢复psr寄存器。

[请注意,在早期的ARM CPU中,寄存器r15既包含pc寄存器(仅24位宽),又包含psr寄存器(其8位宽)。没有ldm^将使寄存器psr的8 r15位保持不变,而使用^将从内存中加载所有32位。

在当前的ARM CPU中不再如此。但是,使用^加载psr时,使用pc仍会恢复ldm寄存器的值。

© www.soinside.com 2019 - 2024. All rights reserved.