1. 程式人生 > >ARM中通過ldr pc, xxx地址,來跳轉到對應的絕對地址去執行

ARM中通過ldr pc, xxx地址,來跳轉到對應的絕對地址去執行

在學習ARM裸機實時,對於程式的連結地址和程式的執行地址是很重要的,通常在程式的前幾k的程式碼中使用的都是相當跳轉指令b,bl,前面幾k的程式碼的主要任務就是將整個程式複製到對應的連結地址上去的。這個過程就是程式碼的重定位,在重定位之前的程式碼與位置無關(是位置無關碼);重定位完成以後就可以跳轉到新的地址中去運行了,通常使用 ldr pc, xxx,來實現跳轉。這裡先來看看三段彙編程式碼,來理解uboot中重定位後,跳轉的實現。und_addr,do_und都是標記,也就是地址。

  • ldr pc, und_addr(這是uboot中的用法)
  • ldr pc, do_und
  • ldr pc, =do_und(這是一條偽指令)
.text
.global _start

_start:
	b reset

	ldr pc, und_addr        //1
	//ldr pc, do_und        //2
	//ldr pc, =do_und       //3
	
und_addr:
	.word do_und
	
do_und:
	//設定未定義指令異常是的棧
	ldr sp, =0x34000000
	//儲存現場
	stmdb sp!, {r0-r12, lr}
	//0x600000DB
	mrs r0, cpsr
	ldr r1, =und_string
	bl printException
	
	//輸出sprs 0x600000D3
	mrs r0, spsr
	bl putHex
	
	ldmia sp!, {r0-r12, pc}^

分別編譯這三種情況,然後反彙編檢視彙編代買。

 ldr pc, und_addr(這是uboot中的用法)

30000000 <_start>:
30000000:	ea00000e 	b	30000040 <reset>
30000004:	e51ff004 	ldr	pc, [pc, #-4]	; 30000008 <und_addr>

30000008 <und_addr>:
30000008:	3000000c 	.word	0x3000000c

3000000c <do_und>:
3000000c:	e3a0d30d 	mov	sp, #872415232	; 0x34000000
30000010:	e92d5fff 	push	{r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, lr}
30000014:	e10f0000 	mrs	r0, CPSR
30000018:	e59f109c 	ldr	r1, [pc, #156]	; 300000bc <halt+0x4>
3000001c:	eb0000dd 	bl	30000398 <printException>

 ldr pc, do_und

30000000 <_start>:
30000000:	ea00000e 	b	30000040 <reset>
30000004:	e59ff000 	ldr	pc, [pc, #0]	; 3000000c <do_und>

30000008 <und_addr>:
30000008:	3000000c 	.word	0x3000000c

3000000c <do_und>:
3000000c:	e3a0d30d 	mov	sp, #872415232	; 0x34000000
30000010:	e92d5fff 	push	{r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, lr}
30000014:	e10f0000 	mrs	r0, CPSR
30000018:	e59f109c 	ldr	r1, [pc, #156]	; 300000bc <halt+0x4>

 ldr pc, =do_und(這是一條偽指令)

30000000 <_start>:
30000000:	ea00000e 	b	30000040 <reset>
30000004:	e59ff0b0 	ldr	pc, [pc, #176]	; 300000bc <halt+0x4>

30000008 <und_addr>:
30000008:	3000000c 	.word	0x3000000c

3000000c <do_und>:
3000000c:	e3a0d30d 	mov	sp, #872415232	; 0x34000000
30000010:	e92d5fff 	push	{r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, lr}
30000014:	e10f0000 	mrs	r0, CPSR
30000018:	e59f10a0 	ldr	r1, [pc, #160]	; 300000c0 <halt+0x8>
3000001c:	eb0000dd 	bl	30000398 <printException>
30000020:	e14f0000 	mrs	r0, SPSR
...
...
...
300000b8 <halt>:
300000b8:	eafffffe 	b	300000b8 <halt>
300000bc:	3000000c 	.word	0x3000000c
300000c0:	3000002c 	.word	0x3000002c
300000c4:	4c000014 	.word	0x4c000014
300000c8:	4c000004 	.word	0x4c000004

程式碼中為什麼要在定義下面這段

und_addr:     .word do_und

主要是為了佔領一個位置,不然這個地址放大CPU的片內srom以外了,不然就找不到他了。

在ldr pc, und_addr中可以將pc=3000000c,實現跳轉

ldr pc, do_und,實現的是pc=e3a0d30d,是錯誤的。

ldr pc, =do_und,可能可以實現pc=3000000c,這還要取決於程式碼是超過了片內srom的大小ldr    pc, [pc, #176]    ; 300000bc <halt+0x4>,不可靠,也無法預測。