Linux下的lds連接腳本簡介(四)

11、 表達式
lds中表達式的文法與C語言的表達式文法一致,表達式的值都是整型,若是ld的運行主機和生成文件的目標機都是32位,則表達式是32位數據,不然是64位數據
如下是一些經常使用的表達式:
_fourk_1 = 4K; /* K、M單位 */
_fourk_2 = 4096; /* 整數 */
_fourk_3 = 0×1000; /* 16 進位 */
_fourk_4 = 01000; /* 8 進位 */
注意:1K=1024 1M=1024*1024
11.一、符號名
沒有被引號」"包圍的符號,以字母、下劃線或’.'開頭,可包含字母、下劃線、’.'和’-'。當符號名被引號包圍時,符號名能夠與關鍵字相同。如,
「SECTION」=9;
「with a space」 = 「also with a space」 + 10;
11.二、定位符號’.'
只在SECTIONS命令內有效,表明一個程序地址空間內的地址。
注意:在鏈接時, 當定位符用在SECTIONS命令的 輸出section描述內 時,它表明的是該section的當前** 偏移**,而不是程序地址空間的絕對地址。固然當程序載入後,符號最後的地址仍是程序地址空間的絕對地址。
示例11.2_1:
SECTIONS
{
output :
{
file1(.text)
. = . + 1000;
file2(.text)
. += 1000;
file3(.text)
} = 0×1234;
}
其中因爲對定位符的賦值而產生的空隙由0×1234填充。其餘的內容應該容易理解吧。
示例11.2_2:
SECTIONS
{
. = 0×100
.text : {
*(.text)
. = 0×200
}
. = 0×500
.data : {
*(.data)
. += 0×600
}
}
.text section在程序地址空間的開始位置是 0x100
示例11.2_3
文件src\a.c
#include <stdio.h>
int a = 100;
int b=0;
int c=0;
int d=1;
int main()
{
printf( "&a=%p\n", &a );
printf( "&b=%p\n", &b );
printf( "&c=%p\n", &c );
printf( "&d=%p\n", &d );
return 0;
}
文件lds\a.lds
a = 10; /* 全局位置 */
SECTIONS
{
b = 11;
.text :
{
*(.text)
c = .; /* section描述內 */
. = 10000 ;
d = .;
}
_bdata = (. + 3) & ~ 4; /* SECTIONS命令內 */
.data : { *(.data) }
}
在沒有使用 a.lds狀況下編譯
gcc -Wall -o a-without-lds.exe ./src/a.c
運行 ./a-without-lds.exe
結果:
&a=0x601020
&b=0x601038
&c=0x60103c
&d=0x601024
在使用 a.lds狀況下編譯
gcc -Wall -o a-with-lds.exe ./src/a.c ./lds/a.lds
運行 ./a-with-lds.exe
結果:
&a=0xa
&b=0xb
&c=0x400638
&d=0x402b20
10.三、表達式的操做符
在lds中,表達式的操做符與C語言一致。
優先級 結合順序 操做符
1 left ! – ~ (1)
2 left * / %
3 left + -
4 left >>  =
5 left &
6 left |
7 left &&
8 left ||
9 right ? :
10 right &= += -= *= /= (2)
(1)表示前綴符, (2)表示賦值符。
10.四、表達式的計算
鏈接器延遲計算大部分表達式的值。
可是,對待與鏈接過程緊密相關的表達式,鏈接器會當即計算表達式,若是不能計算則報錯。好比, 對於section的VMA地址、內存區域塊的開始地址和大小,與其相關的表達式應該當即被計算。
例子,
SECTIONS
{
.text 9+this_isnt_constant :
{ *(.text) }
}
這個例子中,9+this_isnt_constant表達式的值用於設置.text section的VMA地址,所以須要當即運算,可是因爲this_isnt_constant變量的值不肯定,因此此時鏈接器沒法確立表達式的值,此時鏈接器會報錯。
10.五、相對值與絕對值
在輸出 section描述內 的表達式,鏈接器取其 相對值 ,相對與該section的開始位置的偏移
SECTIONS命令內且非輸出section描述內 的表達式,鏈接器取其 絕對值
經過ABSOLUTE關鍵字能夠將相對值轉化成絕對值,即在原來值的基礎上加上表達式所在section的VMA值。
示例
SECTIONS
{
.data : { *(.data) ;_edata = ABSOLUTE ( . ); }
}
該例子中,_edata符號的值是.data section的末尾位置(絕對值,在程序地址空間內)。
10.六、內建函數
lds中有如下一些內建函數:
ABSOLUTE(EXP) :轉換成絕對值
ADDR(SECTION) :返回某section的VMA值。
ALIGN(EXP) :返回定位符’ .'的按照EXP進行對齊後的修調值,對齊後的修調值算法爲: (. + EXP – 1) & ~(EXP – 1)
BLOCK(EXP) :如同ALIGN(EXP),爲了向前兼容。
DEFINED(SYMBOL) :若是符號SYMBOL在全局符號表內,且被定義了,那麼返回1,不然返回0。
示例
SECTIONS { …
.text : {
begin = DEFINED ( begin ) ? begin : . ;
}
}
LOADADDR(SECTION) :返回三SECTION的LMA
MAX(EXP1,EXP2) :返回大者
MIN(EXP1,EXP2) :返回小者
NEXT(EXP) :返回下一個能被使用的地址,該地址是 EXP的倍數,相似於ALIGN(EXP)。除非使用了 MEMORY命令定義了一些非連續的內存塊,不然NEXT(EXP)與ALIGH(EXP)必定相同。
SIZEOF(SECTION) :返回SECTION的大小。當SECTION沒有被分配時,即此時SECTION的大小還不能肯定時,鏈接器會報錯。
SIZEOF_HEADERS :返回輸出文件頭部的字節數。這些信息出如今輸出文件的開始處。當設置第一個段的開始地址時,你可使用這個數字。若是你選擇了加速分頁,當產生一個ELF輸出文件時,若是連接器腳本使用SIZEOF_HEADERS內建函數,鏈接器必須在它
算出全部段地址和長度以前計算程序頭部的數值。若是鏈接器後來發現它須要附加程序頭,它將報告一個「not enough room for
program headers」錯誤。爲了不這樣的錯誤,你必須避免使用SIZEOF_HEADERS函數,或者你必須修改你的鏈接器腳本去避免強制
鏈接器去使用附加程序頭,或者你必須使用PHDRS命令去定義你本身的程序頭
12、 暗含的鏈接腳本
輸入文件能夠是目標文件,也能夠是鏈接腳本,此時的鏈接腳本被稱爲 暗含的鏈接腳本
若是鏈接器不認識某個輸入文件,那麼該文件被看成鏈接腳本被解析。更進一步,若是發現它的格式又不是鏈接腳本的格式,那麼鏈接器報錯。
一個暗含的鏈接腳本不會替換默認的鏈接腳本,僅僅是增長新的鏈接而已。
通常來講,暗含的鏈接腳本符號分配命令,或INPUT、GROUP、VERSION命令。
在鏈接命令行中,每一個輸入文件的順序都被固定好了,暗含的鏈接腳本在鏈接命令行內佔住一個位置,這個位置決定了由該鏈接腳本指定的輸入文件在鏈接過程當中的順序
典型的暗含的鏈接腳本是libc.so文件,在GNU/linux內通常存在/usr/lib目錄下。
相關文章
相關標籤/搜索