重定位的介紹

2021-07-30 10:16:14 字數 4491 閱讀 6081

1、鏈結位址和執行位址

(1)鏈結位址(2)執行位址在位置相關碼執行前,需要把**拷貝到以鏈結位址為起始位址的空間裡,然後通過跳轉語句,跳轉到以鏈結位址為起始位址的**的相應的位置繼續執行。

(3)舉例

2、重定位

(1)在執行位址處執行一段位置無關碼,把整個程式映象拷貝乙份到鏈結位址處,然後使用跳轉指令從執行位址處直接跳轉到鏈結位址處去執行同乙個函式。

ldr r0, =bss_start,這句**的作用是把bss_start(在鏈結指令碼中)的位址放入r0中,因為bss_start的值會受到鏈結指令碼中鏈結位置的影響,所以是位置有關碼。

#define wtcon         0xe2700000

#define ps_hold_control  0xe010e81c

#define svc_stack      0xd0037d80

ldr r0, =wtcon

ldr r0, =ps_hold_control

(2)當執行完**重定位後,在sram中有2份**的映象。

重定位後使用ldr pc, =led_blink這句長跳轉,直接從0xd0020010開頭的**跳轉到0xd0024000開頭的那乙份**的led_blink函式處去執行。

如果短跳轉bl led_blink,則執行的是執行位址0xd0020010開頭的這乙份;

如果長跳轉ldr pc, =led_blink,則執行的是連線位址0xd0024000開頭處的這乙份;

當鏈結位址和執行位址相同時,短跳轉和長跳轉效果一樣。

3、例子說明

(1)在sram內部重定位,不涉及記憶體的初始化

/*

* 檔名: led.s

* 描述: 演示重定位(在sram內部重定位)

*/#define wtcon 0xe2700000

#define svc_stack 0xd0037d80

.global _start // 把_start鏈結屬性改為外部,這樣其他檔案就可以看見_start了

_start:

// 第1步:關看門狗(向wtcon的bit5寫入0即可)

ldr r0, =wtcon

ldr r1, =0x0

str r1, [r0]

// 第2步:設定svc棧

ldr sp, =svc_stack

// 第3步:開/關icache

mrc p15,0,r0,c1,c0,0; // 讀出cp15的c1到r0中

//bic r0, r0, #(1<<12) // bit12 置0 關icache

orr r0, r0, #(1<<12) // bit12 置1 開icache

mcr p15,0,r0,c1,c0,0;

// 第4步:重定位

// adr指令用於載入_start當前執行位址

adr r0, _start // adr載入時就叫短載入

ldr r1, =_start // ldr載入時如果目標暫存器是pc就叫長跳轉,如果目標暫存器是r1等就叫長載入

// bss段的起始位址

ldr r2, =bss_start // 就是我們重定位**的結束位址,重定位只需重定位**段和資料段即可

cmp r0, r1 // 比較_start的執行時位址和鏈結位址是否相等

beq clean_bss // 如果相等說明不需要重定位,所以跳過copy_loop,直接到clean_bss

// 如果不相等說明需要重定位,那麼直接執行下面的copy_loop進行重定位

// 重定位完成後繼續執行clean_bss。

// 用彙編來實現的乙個while迴圈

copy_loop:

ldr r3, [r0], #4 // 源

str r3, [r1], #4 // 目的 這兩句**就完成了4個位元組內容的拷貝

cmp r1, r2 // r1和r2都是用ldr載入的,都是鏈結位址,所以r1不斷+4總能等於r2

bne copy_loop

// 清bss段,其實就是在鏈結位址處把bss段全部清零

clean_bss:

ldr r0, =bss_start

ldr r1, =bss_end

cmp r0, r1 // 如果r0等於r1,說明bss段為空,直接下去

beq run_on_dram // 清除bss完之後的位址

mov r2, #0

clear_loop:

str r2, [r0], #4 // 先將r2中的值放入r0所指向的記憶體位址(r0中的值作為記憶體位址),

cmp r0, r1 // 然後r0 = r0 + 4

bne clear_loop

run_on_dram:

// 長跳轉到led_blink開始第二階段

ldr pc, =led_blink // ldr指令實現長跳轉

// 從這裡之後就可以開始呼叫c程式了

//bl led_blink // bl指令實現短跳轉

// 彙編最後的這個死迴圈不能丟

b .

(2)重定位到記憶體中,需要先初始化記憶體

/*

* 檔名: led.s

* 描述: 演示重定位

*/#define wtcon 0xe2700000

#define svc_stack 0xd0037d80

.global _start // 把_start鏈結屬性改為外部,這樣其他檔案就可以看見_start了

_start:

// 第1步:關看門狗(向wtcon的bit5寫入0即可)

ldr r0, =wtcon

ldr r1, =0x0

str r1, [r0]

// 第2步:設定svc棧

ldr sp, =svc_stack

// 第3步:開/關icache

mrc p15,0,r0,c1,c0,0; // 讀出cp15的c1到r0中

//bic r0, r0, #(1<<12) // bit12 置0 關icache

orr r0, r0, #(1<<12) // bit12 置1 開icache

mcr p15,0,r0,c1,c0,0;

// 第4步:初始化ddr

bl sdram_asm_init

// 第5步:重定位

// adr指令用於載入_start當前執行位址

adr r0, _start // adr載入時就叫短載入

ldr r1, =_start // ldr載入時如果目標暫存器是pc就叫長跳轉,如果目標暫存器是r1等就叫長載入

// bss段的起始位址

ldr r2, =bss_start // 就是我們重定位**的結束位址,重定位只需重定位**段和資料段即可

cmp r0, r1 // 比較_start的執行時位址和鏈結位址是否相等

beq clean_bss // 如果相等說明不需要重定位,所以跳過copy_loop,直接到clean_bss

// 如果不相等說明需要重定位,那麼直接執行下面的copy_loop進行重定位

// 重定位完成後繼續執行clean_bss。

// 用彙編來實現的乙個while迴圈

copy_loop:

ldr r3, [r0], #4 // 源

str r3, [r1], #4 // 目的 這兩句**就完成了4個位元組內容的拷貝

cmp r1, r2 // r1和r2都是用ldr載入的,都是鏈結位址,所以r1不斷+4總能等於r2

bne copy_loop

// 清bss段,其實就是在鏈結位址處把bss段全部清零

clean_bss:

ldr r0, =bss_start

ldr r1, =bss_end

cmp r0, r1 // 如果r0等於r1,說明bss段為空,直接下去

beq run_on_dram // 清除bss完之後的位址

mov r2, #0

clear_loop:

str r2, [r0], #4 // 先將r2中的值放入r0所指向的記憶體位址(r0中的值作為記憶體位址),

cmp r0, r1 // 然後r0 = r0 + 4

bne clear_loop

run_on_dram:

// 長跳轉到led_blink開始第二階段

ldr pc, =led_blink // ldr指令實現長跳轉

// 從這裡之後就可以開始呼叫c程式了

//bl led_blink // bl指令實現短跳轉

// 彙編最後的這個死迴圈不能丟

b .

重定位 介紹 一

重定位 為什麼需要重定位?重定位是什麼?怎麼實現重定位?環境 1 s3c2440裸板 2 linux version 4.15.0 首先1 為什麼需要重定位?s3c2440啟動有兩種方式 a nand 啟動 b nor啟動 nornand 可以像記憶體一樣讀,不能像記憶體一樣寫,因此當 存在全域性變...

共享可寫節包含重定位 理解重定位

一 段的概念 段是程式的組成元素。將整個程式分成乙個乙個段,並且給每個段起乙個名字,然後在鏈結時就可以用這個名字來指示這些段,使得這些段排布在合適的位置。乙個程式通常包含以下五個段 段 text 存放 指令 唯讀資料段 rodata 存放有初始值並且const修飾的全域性類變數 全域性變數或stat...

定位的簡單介紹

定位 position 分為相對定位 relative 絕對定位 absolute 固定定位 fixed 偏移量 偏移的方向的具體值,方向分為top right bottom left relative 相對定位 相對於自身位置出發 特點 1 不影響元素本身的特性。2 只設定了相對定位,沒有設定偏移...