簡介
這兩個都是偽指令:ADR 是小范圍的地址讀取偽指令,LDR 是大范圍的讀取地址偽指令。可實際使用的區別是: ADR 是將基於 PC 相對偏移的地址值或基於寄存器相對地址值讀取的偽指令,而 LDR 用於加載 32 位立即數或一個地址到指定的寄存器中。
以下面的匯編代碼為例:
.global _start
_start:
ldr r0, loop
adr r0, loop
ldr r0, =loop
loop:
nop
用以下命令完成匯編、鏈接操作,並輸出反匯編文件
[root@localhost asm]# arm-linux-gcc asm.S -o asm.o -c
[root@localhost asm]# arm-linux-ld -Ttext 0x1004 asm.o -o link.elf
[root@localhost asm]# arm-linux-objdump -D link.elf > link.dis
反匯編代碼如下:
link.elf: file format elf32-littlearm
Disassembly of section .text:
00001004 <_start>:
1004: e59f0004 ldr r0, [pc, #4] ; 1010 <loop>
1008: e28f0000 add r0, pc, #0
100c: e59f0000 ldr r0, [pc, #0] ; 1014 <loop+0x4>
00001010 <loop>:
1010: e320f000 nop {0}
1014: 00001010 andeq r1, r0, r0, lsl r0
反匯編文件分析
ARM9 特性:PC 指向當前指令地址 +8 的位置。
1.ldr r0, loop
這是一條指令,從內存地址 loop 的位置把值讀入。在這里 loop 是一個標號(是一個相對程序的表達式),匯編程序計算相對於 PC 的偏移量,並生成相對於 PC 的索引指令:ldr r0, [pc, #4]。執行指令后,r0 = e320f000。
2.adr r0, loop
這是一條偽指令,總是會被匯編程序匯編為一個指令。匯編程序嘗試產生單個 ADD 或 SUB 指令來裝載該地址。如果不能在一個指令中構造該地址,則生成一個錯誤,並且匯編失敗。在這里是取得標號 loop 的地址到 r0,該代碼可以在和標號相對位置不變的情況下移動:假如這段代碼在 0x30000000 運行,那么 adr r0, loop 得到 r0 = 0x3000000c;如果在地址 0 運行,就是 0x0000000c 了。
3.ldr r0, =loop
這是一條偽指令,是一個相對程序的或外部的表達式。匯編程序將相對程序的標號表達式 label-expr 的值放在一個文字池中,並生成一個相對程序的 LDR 指令來從文字池中裝載該值。如果 label-expr 是一個外部表達式,或者未包含於當前段內,則匯編程序在目標文件中放置一個鏈接程序重定位命令,程序取鏈接時生成的地址,因此取得的是標號 loop 的絕對地址,這個絕對地址是在鏈接的時候確定的。它要占用 2 個 32bits 的空間,一條是指令,另一條是文字池中存放 loop 的絕對地址。因此可以看出,不管這段代碼將來在什么地方運行,它的結果都是 r0 = 0x00001010。
參考自:blog.sina.com.cn/s/articlelist_1263669380_0_1.html