ARM在不同模式下如何区别同名寄存器(如fiq模式下的R8_fiq与其他模式下的R8),从而访问不同的寄存器 转

信息 160浏览

首先看下ARM状态下不同模式下的的寄存器,共37个,31个通用的。


好,问题来了:在快速中断模式下的R8_fiq与其他模式下的R8是不同的寄存器,但是在汇编代码中不会区别寄存器名字。

例如MOV R8,#0x12345678,该命令在快速中断模式下运行,与处快速中断之外的模式下执行,显然访问的是不同的R8寄存器,但是这个访问不同寄存器的过程是编译器做的,还是CPU做的?

通过请教高手得出结论如下:

编译器不能区分r8和r8_fiq

 

名词:r*_fiq (*=8~14)

在Linux内核里,如果要用到快速中断,需要初始化快速中断,首先先设置r*_fiq,然后使能快速中断。系统在同一时刻只能支持一个fiq,允许程序员在系统运行的过程中改变fiq的目标。


下面是摘抄Linux内核里设置r*_fiq的代码:

Linux3.2 arch/arm/kernel/fiqasm.S  line25:

 

ENTRY(__set_fiq_regs)

mov r2, #PSR_I_BIT | PSR_F_BIT | FIQ_MODE

mrs r1, cpsr

msr cpsr_c, r2 @ select FIQ mode

mov r0, r0 @ avoid hazard prior to ARMv4

ldmia r0!, {r8 - r12}

ldr sp, [r0], #4

ldr lr, [r0]

msr cpsr_c, r1 @ return to SVC mode

mov r0, r0 @ avoid hazard prior to ARMv4

mov pc, lr

ENDPROC(__set_fiq_regs)

 

系统程序员预先初始化一个数组,填上需要放到r8-r14的值,然后调用该函数,参

数为该数组的指针。这个函数主要做的工作是保存cpsr,将当前模式切换成FIQ

模式,将r0指向的内存里的值放到r8-r14(r*_fiq),切换回以前的管理模式,

函数返回。

 

程序里使用ldmia和ldr指令往r*_fiq寄存器里存储数据。根据ARM指令手册,

ldmia指令操作的register_list(位图)只有16位,下图为LDMIA指令的二进制码,后16位是寄存器列表。



也就是说ldmia指令只能访问r0-r15,不能在指令码里指定更多的寄存器编号。如果想要在指令二进制码里就指明不同模式下的同名寄存器(如指明快速中断模式下的r8_fiq),那就需要不止16位的寄存器编号。

LDR指令也类似,指令码里指明寄存器编号的位段只有4位,也只能访问r0-r15。

从这里我们可以看出编译器并不知道r*_fiq的存在,只能当r*处理。真正区分

fiq寄存器和通用寄存器,需要CPU根据cpsr寄存器的标志位来判断

下图是CPSR寄存器,后五位组合为不同模式位。