ARM 鏈結配置 lds檔案學習

2021-06-06 17:00:29 字數 2811 閱讀 6461

本文由jacky原創,來自

對於.lds檔案,它定義了整個程式編譯之後的連線過程,決定了乙個可執行程式的各個段的儲存位置。雖然現在我還沒怎麼用它,但感覺還是挺重要的,有必要了解一下。

先看一下gnu官方**上對.lds檔案形式的完整描述:

sections

>

region

:phdr

=fill..

.}

secname和contents是必須的,其他的都是可選的。下面挑幾個常用的看看:

1、secname:段名

2、contents:決定哪些內容放在本段,可以是整個目標檔案,也可以是目標檔案中的某段(**段、資料段等)

3、start:本段連線(執行)的位址,如果沒有使用at(ldadr),本段儲存的位址也是start。gnu**上說start可以用任意一種描述位址的符號來描述。

看乙個簡單的例子:(摘自《2410完全開發》)

/* nand.lds */

sections

second 0x30000000 : at(4096)

}

以上,head.o放在0x00000000位址開始處,init.o放在head.o後面,他們的執行位址也是0x00000000,即連線和儲存位址相同(沒有at指定);main.o放在4096(0x1000,是at指定的,儲存位址)開始處,但是它的執行位址在0x30000000,執行之前需要從0x1000(載入處)複製到0x30000000(執行處),此過程也就用到了讀取nand flash。

編寫好的.lds檔案,在用arm-linux-ld連線命令時帶-tfilename來呼叫執行,如

arm-linux-ld –tnand.lds x.o y.o –o xy.o。也用-ttext引數直接指定連線位址,如

arm-linux-ld –ttext 0x30000000 x.o y.o –o xy.o。

既然程式有了兩種位址,就涉及到一些跳轉指令的區別,這裡正好寫下來,以後萬一忘記了也可檢視,以前不少東西沒記下來現在忘得差不多了。。。

arm彙編中,常有兩種跳轉方法:b跳轉指令、ldr指令向pc賦值。

我自己經過歸納如下:

(1)       b step1 :b跳轉指令是相對跳轉,依賴當前pc的值,偏移量是通過該指令本身的bit[23:0]算出來的,這使得使用b指令的程式不依賴於要跳到的**的位置,只看指令本身。

(2)       ldr pc, =step1 :該指令是從記憶體中的某個位置(step1)讀出資料並賦給pc,同樣依賴當前pc的值,但是偏移量是那個位置(step1)的連線位址(執行時的位址),所以可以用它實現從flash到ram的程式跳轉。

(3)       此外,有必要回味一下adr偽指令,u-boot中那段relocate**就是通過adr實現當前程式是在ram中還是flash中。仍然用我當時的注釋:

relocate:

/* 把u-boot重新定位到ram */

adr r0, _start /* r0是**的當前位置 */

/* adr偽指令,彙編器自動通過當前pc的值算出 如果執行到_start時pc的值,放到r0中:

當此段在flash中執行時r0 = _start = 0;當此段在ram中執行時_start = _text_base(在board/smdk2410/config.mk中指定的值為0x33f80000,即u-boot在把**拷貝到ram中去執行的**段的開始) */

ldr r1, _text_base /* 測試判斷是從flash啟動,還是ram */

/* 此句執行的結果r1始終是0x33ff80000,因為此值是又編譯器指定的(ads中設定,或-d設定編譯器引數) */

cmp r0, r1 /* 比較r0和r1,除錯的時候不要執行重定位 */

下面,結合u-boot.lds看看乙個正式的連線指令碼檔案。這個檔案的基本功能還能看明白,雖然上面分析了好多,但其中那些gnu風格的符號還是著實讓我感到迷惑。。。

output_format(

"elf32­littlearm"

,"elf32­littlearm"

,"elf32­littlearm"

);指定輸出可執行檔案是elf格式,32位arm指令,小端

output_arch(arm)

;指定輸出可執行檔案的平台為arm

entry(_start)

;指定輸出可執行檔案的起始**段為_start.

sections

.= align(4)

.rodata :

;指定唯讀資料段

.= align(4)

;.data :

;指定讀/寫資料段

.= align(4)

;.got :

;指定got段, got段式是uboot自定義的乙個段, 非標準段

__u_boot_cmd_start =

.;把__u_boot_cmd_start賦值為當前位置, 即起始位置

.u_boot_cmd :

;指定u_boot_cmd段, uboot把所有的uboot命令放在該段.

__u_boot_cmd_end =

.;把__u_boot_cmd_end賦值為當前位置,即結束位置

.= align(4)

;__bss_start =

.; 把__bss_start賦值為當前位置,即bss段的開始位置

.bss :

; 指定bss段

_end =

.; 把_end賦值為當前位置,即bss段的結束位置

}

鏈結檔案lds

一段典型指令碼 hello.lds entry helloworld sections align 4 data bss 1 點號 點號在sections命令裡稱為位置計數器,代表了當前位置。如上面的0x20008000表示 段的起始位置從這個值開始。也可以不指定,如.data段和.bss段 代表緊...

Linux鏈結指令碼學習 lds

l一 概論 ld gnu的鏈結器.用來把一定量的目標檔案跟檔案檔案鏈結在一起,並重新定位它們的資料,鏈結符號引用.一般編譯乙個程式時,最後一步就是執行ld進行鏈結 每乙個鏈結都被乙個鏈結指令碼所控制,這個指令碼是用鏈結命令語言書寫的.二 鏈結指令碼 鏈結指令碼的乙個主要目的是描述輸入檔案中的各個段 ...

Linux鏈結指令碼學習 lds 轉)

一 概論 ld gnu的鏈結器.用來把一定量的目標檔案跟檔案檔案鏈結在一起,並重新定位它們的資料,鏈結符號引用.一般編譯乙個程式時,最後一步就是執行ld進行鏈結 每乙個鏈結都被乙個鏈結指令碼所控制,這個指令碼是用鏈結命令語言書寫的.二 鏈結指令碼 鏈結指令碼的乙個主要目的是描述輸入檔案中的各個段 資...