0

使用 Linaro gcc 为 ARM GIC 编译中断处理程序时出现奇怪的结果。

代码是:

void foo1(void) __attribute__(( interrupt("IRQ") ));
void foo2(void) __attribute__(( interrupt("IRQ") ));

void foo1() {
  dummy();
  return;
}

void foo2() {
  return;
}

结果汇编代码:

foo1:
        sub     lr, lr, #4
        push    {r0, r1, r2, r3, r4, fp, ip, lr}
        add     fp, sp, #28
        bl      dummy
        nop
        sub     sp, fp, #28
        pop     {r0, r1, r2, r3, r4, fp, ip, pc}^

foo2:
        str     fp, [sp, #-4]!
        add     fp, sp, #0
        nop
        sub     sp, fp, #0
        ldr     fp, [sp], #4
        subs    pc, lr, #4

因此,如果处理程序代码中没有子例程,则使用 SUBS 从中断返回,如果有任何子例程,则使用 PUSH{lr}/POP{pc}。

问题是 SUBS 会自动从处理器 IRQ 模式切换到 SVC 模式,但 POP{pc} 不会。因此,应该使用 SUBS,对于 foo1,需要添加外部 SUBS 指令才能从 IRQ 切换到 SVC 模式。

它是功能还是错误?

有什么方法可以强制编译器每次都使用 SUBS 吗?

4

1 回答 1

1

我找不到参考,但 IIRCpop {}相当于LDM sp ...

对于 LDM,ARM ARM (A4.1.22 LDM (3)) 声明:

^ 对于加载 PC 的 LDM 指令,这表示将当前模式的 SPSR 复制到 CPSR。

这就是生成的弹出指令从 SPSR 恢复 CPSR 的原因,因此返回之前的 CPU 模式。

于 2016-08-31T10:26:13.657 回答