在ARM汇编指令中,ldr是一条常用的内存访问指令,如:
ldr r1, [r2] //将地址为r2的内存单元位数据读取到r1中
它也可以作为大范围的地址读取伪指令,如:
ldr r1, =label //r1=label的地址
label:
……
这里有一个问题,ldr伪指令是怎么得到label的地址?通过查看反汇编文件,可以看到以下代码:
/* ldr pc, =do_und */
30000004: e59ff0b0 ldr pc, [pc, #176] ; 300000bc <.text+0xbc>
/* do_und在反汇编文件中的位置 */
30000008 <do_und>:
……
从上面看出,使用ldr伪指令时,他并不是直接把label的地址传给r1,而是到一个地址为300000bc的地方读取数据,而300000bc存放着label的地址:
/* 3000000bc存放label的地址 */
300000bc: 30000008 andcc r0, r0, r8
由上面可以知道ldr伪指令读取地址时回到程序的某个地方去读取地址,而这个地方编译器会安排在程序的后面。2440片内sram只有4k,如果此时程序大于4k,并且遇到了异常,那将会出现读不到数据的情况,为了让程序直接获取异常处理函数的地址,此时可以借助.word伪指令:
/* 在label的地方放一个word类型的数据:expression */
label:
.word expression
/* 此处使用ldr指令,不是伪指令 */
ldr pc, addr_und
/* 使用.word,在此处存放do_und地址 */
addr_und:
.word do_und
do_und:
……
经过修改后再来看看反汇编
30000004: e51ff004 ldr pc, [pc, #-4] ; 30000008 <addr_und>
30000008 <addr_und>:
30000008: 3000000c andcc r0, r0, ip
3000000c <do_und>:
现在程序不会跳到后面去读取地址了