一、概論
ld:
GNU的鏈接器.
用來把一定量的目標文件跟檔案文件鏈接在一起,並重新定位它們的數據,鏈接符號引用.
一般編譯一個程序時,最后一步就是運行ld進行鏈接
每一個鏈接都被一個鏈接腳本所控制,這個腳本是用鏈接命令語言書寫的.
二、鏈接腳本
鏈接腳本的一個主要目的是描述輸入文件中的各個段(數據段,代碼段,堆,棧,bss)如何被映射到輸出文件中,並控制輸出文件的內存排布.
鏈接器總是使用鏈接腳本的,如果你不提供,則鏈接器會使用一個缺省的腳本,這個腳本是被編譯進鏈接器可執行文件的.
可以使用--verbose命令行顯示缺省的鏈接器腳本的內容.
你可以使用-T命令行來提供你自己的鏈接腳本來替換缺省的鏈接腳本.
三、簡單的鏈接腳本示例.
許多腳本是相當簡單的.
可能最簡單的腳本只含有一個命令:’SECTIONS’.
你可以使用’SECTIONS’來描述輸出文件的內存布局.
‘SECTIONS’是一個功能很強大的命令.
假設你的程序只有代碼段,初始化過的數據段,和未初始化過的數據段.這些會存在於’.text’,’data’,’bss’段中.
對於這個例子,假設代碼應該被載入到地址0x1000處,而數據應該從0x8000000開始,如下是實現這個功能的腳本:
SECTIONS
{
.=0x1000;
.text:{*(.text)}
.=0x8000000;
.data:{*(.data)}
.bss:{*(.bss)}
}
具體分析:
關鍵字’SECTIONS’開始於這個配置.后面跟有一串放在花括號中的符號賦值和輸出端描述的內容.
第一行是對一個特殊的符號’.’賦值,這是一個定位標識器.如果你沒有以其他的方式制定輸出段的地址,那地址值就會被設為定位標識器的現有值,即0x1000.
第二行定義一個輸出段,’.text’.冒號’:’是語法需要,現在可以被忽略.段后面的花括號中,應該列出所有應該放入這個輸出段中的輸入端的名字.’*’是通配符,匹配所有文件名.即將所有輸入文件中的.text段都保存在此段中.
余下的是.data和.bss段,同理,鏈接器會把所有.data段從地址0x8000000開始處放置.
最后,定位標識器的值變為0x8000000加上所有.data段的地址.此時鏈接器把所有.bss放在此處開始的地址.
四、簡單的鏈接腳本命令
設置入口點
在運行一個程序時,第一個被執行到的指令成為”入口點”.你可以使用”ENTRY”鏈接腳本命令來設置入口點.參數是一個符號名,如下:
ENTRY(SYMBOL)
有很多不同的方法來設置入口點.鏈接器會通過按順序嘗試一下方法來設置入口點,如果成功了,就會停止.
1,’-e’ 入口命令行選項
2,鏈接腳本中的ENTRY(SYMBOL)命令
3,如果定義了start,就使用start的值
4,如果存在就使用’.text’段的首地址
5,地址’0’
五、命令行設置鏈接地址
ld用於將多個obj或者so(庫)文件鏈接成可執行文件.
使用-T選項可以指定數據段,代碼段,bss段起始位置.(-T只用於鏈接bootloader、內核等沒有底層軟件支持的軟件.鏈接運行於操作系統之上的應用程序時,一般使用默認方式鏈接).
1,直接指定代碼段、數據段、bss段起始地址
如下:
-Ttext startaddr
-Tdata startaddr
-Tbss startaddr
例如:
ld –Ttext 0x00000000 –g led_on.o –o led_on_elf
2,直接使用鏈接腳本來設置起始地址
ld –Ttimer.lds –o timer_elf a.o b.o
鏈接腳本timer.lds內容如下:
SECTIONS{
.=0x30000000;
.text : {*(.text)}
.rodata ALIGN(4) : {*(.rodata)}
.data ALIGN(4) : {*(.data)}
.bss ALIGN(4) : {*.(.bss) *(COMMON)}
}
一個SECTIONS命令內部包含一個或多個段,段(section)是連接腳本的基本單元,它表示輸入文件中的某部分怎么放置.
完整的鏈接腳本