先说明一下LDR伪指令。
LDR伪指令将一个32位的常数或者一个地址值读取到寄存器中。
语法格式
LDR{cond} register,={expr|label-expr}
其中的符号及参数说明如下:
●cond为可选的指令执行条件。
●register为目标寄存器。
●expr为32位的常量,编译器将根据expr的取值情况,处理LDR伪指令如下。
●当expr表示的地址值没有超过MOV或MVN指令中地址的取值范围时,编译器使用合适的MOV或者MVN指令替代该LDR伪指令。
●当expr表示的地址超过了MOV或MVN指令中地址的取值范围时,编译器将该常数放在数据缓冲区中,同时用一条基于PC的LDR指令读取该常数。
●label-expr为基于PC的地址表达式或者是外部表达式。当label-expr为基于PC的地址表达式时,编译器将label-expr表示的数值放在数据缓冲区中,同时用一条基于PC的LDR指令读取该值。当label-expr为外部表达式,或者非当前段的表达式时,汇编编译器将在目标文件中插入链接重定位伪操作,这样链接器将在链接是生成该地址。
使用LDR伪操作编写中断向量表如下:
/* 中断向量表的第二种写法 */ ldr pc ,= reset ldr pc ,= undefined_instruction ldr pc ,= software_interrupt ldr pc ,= prefetch_abort ldr pc ,= data_abort ldr pc ,= not_used ldr pc ,= irq ldr pc ,= fiq reset: b reset undefined_instruction: b undefined_instruction software_interrupt: b software_interrupt prefetch_abort: b prefetch_abort data_abort: b data_abort not_used: b not_used irq: b irq fiq: b fiq
反汇编结果如下:
33f80000 <.text>: 33f80000: e59ff038 ldr pc, [pc, #56] ; 33f80040 <.text> 33f80004: e59ff038 ldr pc, [pc, #56] ; 33f80044 <.text> 33f80008: e59ff038 ldr pc, [pc, #56] ; 33f80048 <.text> 33f8000c: e59ff038 ldr pc, [pc, #56] ; 33f8004c <.text> 33f80010: e59ff038 ldr pc, [pc, #56] ; 33f80050 <.text> 33f80014: e59ff038 ldr pc, [pc, #56] ; 33f80054 <.text> 33f80018: e59ff038 ldr pc, [pc, #56] ; 33f80058 <.text> 33f8001c: e59ff038 ldr pc, [pc, #56] ; 33f8005c <.text> 33f80020: eafffffe b 33f8002033f80024: eafffffe b 33f80024 33f80028: eafffffe b 33f80028 33f8002c: eafffffe b 33f8002c 33f80030: eafffffe b 33f80030 33f80034: eafffffe b 33f80034 33f80038: eafffffe b 33f80038 33f8003c: eafffffe b 33f8003c 33f80040: 33f80020 mvnccs r0, #32 ; 0x20 33f80044: 33f80024 mvnccs r0, #36 ; 0x24 33f80048: 33f80028 mvnccs r0, #40 ; 0x28 33f8004c: 33f8002c mvnccs r0, #44 ; 0x2c 33f80050: 33f80030 mvnccs r0, #48 ; 0x30 33f80054: 33f80034 mvnccs r0, #52 ; 0x34 33f80058: 33f80038 mvnccs r0, #56 ; 0x38 33f8005c: 33f8003c mvnccs r0, #60 ; 0x3c
可以看出,LDR伪指令被编译器编译后,将地址常量存放在代码段的最后,并使用相对于PC偏移的地址进行访问。其中,地址常量为固定的0x33f80020...,也就是符号的地址在链接阶段已经确定了。
当代码运行于0地址时(重定位前),这条指令将使PC指向运行时地址,这时运行时地址还没有指令,所以会出错误。所以LDR register,=label-expr是地址相关的。