lds文件
最近在看u-boot、osekOS的啟動代碼,其中涉及到lds文件,通過參考其他網(wǎng)友的文章,希望對lds文件有個明晰的認識,為了鞏固及加深影響,特將相關(guān)博客內(nèi)容重寫一遍。
原始文章: http://linux.chinaunix.net/techdoc/beginner/2009/08/12/1129972.shtml。原始文章講解更清楚,不懂的地方可以返回參考。
一、概念
1.1 lds文件
lds文件與scatter文件相似,定義了整個程序編譯之后的連接過程,都是決定一個可執(zhí)行程序的各個段的存儲位置,以及入口地址,這也是鏈接定位的作用。
每一個鏈接過程都由鏈接腳本(linker script, 一般以lds作為文件的后綴名)控制。鏈接器通過鏈接腳本中指定的規(guī)則把一個或多個輸入文件(可以是目標文件或鏈接腳本文件)的section合成一個輸出文件(可以是目標文件或可執(zhí)行文件)。
1.2 section
為了區(qū)分不同文件的section,目標文件中的每個section需要至少包含名字和大小,大部分還包含與其相關(guān)聯(lián)的一塊數(shù)據(jù)section contents。一個section可被標記為“l(fā)oadable” (可加載的,在輸出文件運行時,該section被載入進程地址空間)或“allocatable” (可分配的,輸出文件運行時,在進程地址空間中預(yù)留section大小的部分)。
在目標文件中, loadable或allocatable的輸出section有兩種地址: VMA(virtual Memory Address,進程執(zhí)行時使用的地址)和LMA(Load Memory Address,加載到進程地址空間的地址)。一般而言, 某section的VMA = LMA. 但在嵌入式系統(tǒng)中, 經(jīng)常存在加載地址和執(zhí)行地址不同的情況: 比如將輸出文件加載到開發(fā)板的flash中(由LMA指定), 而在運行時將位于flash中的輸出文件復(fù)制到SDRAM中(由VMA指定)。
1.3 符號
每個目標文件都有符號表(SYMBOL TABLE), 包含已定義的符號(對應(yīng)全局變量和static變量和定義的函數(shù)的名字)和未定義符號(未定義的函數(shù)的名字和引用但沒定義的符號)信息。每個符號對應(yīng)一個地址, 即符號值(這與c程序內(nèi)變量的值不一樣, 某種情況下可以把它看成變量的地址)。
二、語法
2.1 腳本格式
鏈接腳本由一系列命令組成, 每個命令由一個關(guān)鍵字(一般在其后緊跟相關(guān)參數(shù))或一條對符號的賦值語句組成。命令由分號‘;’分隔開。文件名或格式名內(nèi)如果包含分號’;'或其他分隔符, 則要用引號‘”’將名字全稱引用起來,無法處理含引號的文件名。
/* */之間的是注釋。
GNU官方網(wǎng)站上對.lds文件形式的完整描述:
腳本命令;
腳本命令;
…
SECTIONS {
...
secname start BLOCK(align) (TYPE) : AT ( ldadr )
{ contents }[>REGION] [AT>LMA_REGION] [:PHDR
HDR ...] [=FILLEXP]
...
}
說明:secname和contents是必須的,前者用來命名這個段,后者用來確定代碼中的什么部分放在這個段,以下是對這個描述中的一些關(guān)鍵字的解釋。
1、腳本命令:參見2.3節(jié),可以設(shè)置內(nèi)存段、輸出格式、入口地址等。
2、secname:輸出section段名。
3、start BLOCK:是段的重定位地址,本段連接(運行)的地址,如果代碼中有位置無關(guān)指令,程序運行時這個段必須放在這個地址上。start可以用任意一種描述地址的符號來描述。設(shè)置了輸出section的VMA地址,其中align將定位符號的值調(diào)整到滿足輸出section對齊要求后的值。
4、TYPE:輸出section類型,指明是否在程序運行時載入內(nèi)存。
5、AT(ldadr):定義本段存儲(加載)的地址,默認情況下,LMA等于VMA,但可以通過關(guān)鍵字AT()指定LMA。用關(guān)鍵字AT()指定,括號內(nèi)包含表達式,表達式的值用于設(shè)置LMA。如果不用AT()關(guān)鍵字,那么可用AT>LMA_REGION表達式設(shè)置指定該section加載地址的范圍。通過這個選項可以控制各段分別保存于輸出文件中不同的位置。
6、contents:決定哪些內(nèi)容放在本段,可以是整個目標文件,也可以是目標文件中的某段(代碼段、數(shù)據(jù)段等),詳情參考2.4節(jié)。
7、region:如果start沒有定義,則以region地址為VMA,如果region也沒定義,以定位符號‘.’的值確定VMA。
8、phdr:沒在具體的實例中看到過。
9、FILLEXP:指明空閑空間(如按align對齊后的空閑部分)的填充字段。
2.2 符號及表達式
2.2.1 符號
沒有被引號“”包圍的符號,以字母、下劃線或‘.’開頭,可包含字母、下劃線、’.'和’-'。當符號名被引號包圍時,符號名可以與關(guān)鍵字相同。
(1). 是一個特殊的符號,它是定位器,一個位置指針,指向程序地址空間內(nèi)的某位置(或某section內(nèi)的偏移,如果它在SECTIONS命令內(nèi)的某section描述內(nèi)),該符號只能在SECTIONS命令內(nèi)使用。
(2)PROVIDE關(guān)鍵字:用于定義在目標文件內(nèi)被引用,但沒有在任何目標文件內(nèi)被定義的符號。
2.2.2 表達式
(1)賦值
在目標文件內(nèi)定義的符號可以在鏈接腳本內(nèi)被賦值,但只有對全局變量賦值才有效,而且此處的賦值是更改這個符號對應(yīng)的地址,而不是變量的值。賦值語句可以出現(xiàn)在連接腳本的三處地方:SECTIONS命令內(nèi),SECTIONS命令內(nèi)的section描述內(nèi)和全局位置;常用賦值操作有:
SYMBOL = EXPRESSION ; SYMBOL += EXPRESSION ; SYMBOL -= EXPRESSION ; SYMBOL *= EXPRESSION ; SYMBOL /= EXPRESSION ; SYMBOL >= EXPRESSION ; SYMBOL &= EXPRESSION ; SYMBOL |= EXPRESSION ;
注意:除了第一類表達式外, 使用其他表達式需要SYMBOL被定義于某目標文件。
(2)運算符優(yōu)先級
優(yōu)先級 結(jié)合順序 操作符 1 left ! – ~ (1) 2 left * / % 3 left + - 4 left >> = 6 left & 7 left | 8 left && 9 left || 10 right ? : 11 right &= += -= *= /= (2)
(3)內(nèi)建函數(shù)
ABSOLUTE(EXP) :轉(zhuǎn)換成絕對值 ADDR(SECTION) :返回某section的VMA值。 ALIGN(EXP) :返回定位符’.'的修調(diào)值,對齊后的值,(. + EXP – 1) & ~(EXP – 1) BLOCK(EXP) :如同ALIGN(EXP),為了向前兼容。 DEFINED(SYMBOL) :如果符號SYMBOL在全局符號表內(nèi),且被定義了,那么返回1,否則返回0。 LOADADDR(SECTION) :返回三SECTION的LMA MAX(EXP1,EXP2) :返回大者 MIN(EXP1,EXP2) :返回小者 NEXT(EXP) :返回下一個能被使用的地址,該地址是EXP的倍數(shù),類似于ALIGN(EXP)。除非使用了MEMORY命令定義了一些非連續(xù)的內(nèi)存塊,否則NEXT(EXP)與ALIGH(EXP)一定相同。 SIZEOF(SECTION) :返回SECTION的大小。當SECTION沒有被分配時,即此時SECTION的大小還不能確定時,連接器會報錯。 SIZEOF_HEADERS : sizeof_headers :返回輸出文件的文件頭大小(還是程序頭大小),用以確定第一個section的開始地址(在文件內(nèi))。
2.3 腳本命令
2.3.1 簡單命令
|
命令 |
說明 |
備注 |
|
ENTRY(SYMBOL) |
將符號SYMBOL的值設(shè)置成入口地址(進程執(zhí)行的第一條用戶空間的指令在進程地址空間的地址)。 |
進程入口地址優(yōu)先級:ld命令行的-e選項>連接腳本的ENTRY(SYMBOL)命令>如果定義了start符號, 使用start符號值>如果存在.text section, 使用.text section的第一字節(jié)的位置值>使用值0。 |
|
INCLUDE filename |
包含其他名為filename的鏈接腳本 |
可以嵌套使用, 最大深度為10。 |
|
INPUT(files) |
將括號內(nèi)的文件做為鏈接過程的輸入文件。 |
ld首先在當前目錄下尋找該文件, 如果沒有, 則在由-L指定的搜索路徑下搜索 |
|
GROUP(files) |
指定需要重復(fù)搜索符號定義的多個輸入文件 |
file必須是庫文件,被ld重復(fù)掃描,直到不在有新的未定義的引用出現(xiàn)。 |
|
OUTPUT(FILENAME) |
定義輸出文件的名字 |
|
|
SEARCH_DIR(PATH) |
定義搜索路徑 |
|
|
STARTUP(filename) |
指定filename為第一個輸入文件 |
鏈接過程中, 每個輸入文件是有順序的,此命令設(shè)置filename為第一個輸入文件。 |
|
TARGET(BFDNAME) |
設(shè)置輸入文件的BFD格式。 |
|
|
OUTPUT_FORMAT(BFDNAME) |
設(shè)置輸出文件使用的BFD格式。 |
|
|
OUTPUT_FORMAT(DEFAULT,BIG,LITTLE) |
定義三種輸出文件的格式(大小端)。 |
若有命令行選項-EB, 則使用第2個BFD格式; -EL,則使用第3個BFD格式.否則默認第一個。 |
|
ASSERT(EXP, MESSAGE) |
如果EXP不為真,終止連接過程 |
|
|
EXTERN(SYMBOL SYMBOL …) |
在輸出文件中增加未定義的符號 |
|
|
FORCE_COMMON_ALLOCATION |
為common symbol(通用符號)分配空間,即使用了-r連接選項也為其分配 |
|
|
NOCROSSREFS(SECTION SECTION …) |
檢查列出的輸出section,如果發(fā)現(xiàn)他們之間有相互引用,則報錯。 |
對于某些系統(tǒng),特別是內(nèi)存較緊張的嵌入式系統(tǒng),某些section是不能同時存在內(nèi)存中的,所以他們之間不能相互引用。 |
|
OUTPUT_ARCH(BFDARCH) |
設(shè)置輸出文件的machine architecture(體系結(jié)構(gòu)) |
BFDARCH為被BFD庫使用的名字之一。 |
|
man -S 1 ld |
查看ld的聯(lián)機幫助, 里面也包括了對以上命令的介紹. |
2.3.2 其它命令
(1)內(nèi)存區(qū)域命令
在默認情形下,連接器可以為section分配任意位置的存儲區(qū)域。你也可以用MEMORY命令定義存儲區(qū)域,并通過輸出section描述的> REGION屬性顯示地將該輸出section限定于某塊存儲區(qū)域,當存儲區(qū)域大小不能滿足要求時,連接器會報告該錯誤。
MEMORY命令的文法如下:
MEMORY {
NAME1 [(ATTR)] : ORIGIN = ORIGIN1, LENGTH = LEN2
NAME2 [(ATTR)] : ORIGIN = ORIGIN2, LENGTH = LEN2
…
}
說明如下:
NAME :存儲區(qū)域的名字,這個名字可以與符號名、文件名、section名重復(fù),因為它處于一個獨立的名字空間。
ATTR :定義該存儲區(qū)域的屬性,在講述SECTIONS命令時提到,當某輸入section沒有在SECTIONS命令內(nèi)引用時,連接器會把該輸入 section直接拷貝成輸出section,然后將該輸出section放入內(nèi)存區(qū)域內(nèi)。如果設(shè)置了內(nèi)存區(qū)域設(shè)置了ATTR屬性,那么該區(qū)域只接受滿足該屬性的section(怎么判斷該section是否滿足?輸出section描述內(nèi)好象沒有記錄該section的讀寫執(zhí)行屬性)。
ATTR屬性內(nèi)可以出現(xiàn)以下7個字符:
R 只讀section W 讀/寫section X 可執(zhí)行section A ‘可分配的’section I 初始化了的section L 同I ! 不滿足該字符之后的任何一個屬性的section
ORIGIN :關(guān)鍵字,區(qū)域的開始地址,可簡寫成org或o
LENGTH :關(guān)鍵字,區(qū)域的大小,可簡寫成len或l
(2)PHDRS命令
在連接腳本內(nèi)不指定PHDRS命令時,連接器能夠很好的創(chuàng)建程序頭,但是有時需要更精確的描述程序頭,那么PAHDRS命令就派上用場了。
注意:一旦在連接腳本內(nèi)使用了PHDRS命令,那么連接器**僅會**創(chuàng)建PHDRS命令指定的信息,所以使用時須謹慎。
PHDRS命令文法如下:
PHDRS
{
NAME TYPE [ FILEHDR ] [ PHDRS ] [ AT ( ADDRESS ) ]
[ FLAGS ( FLAGS ) ] ;
}
其中FILEHDR、PHDRS、AT、FLAGS為關(guān)鍵字。
NAME :為程序段名,此名字可以與符號名、section名、文件名重復(fù),因為它在一個獨立的名字空間內(nèi)。此名字只能在SECTIONS命令內(nèi)使用。
一個程序段可以由多個‘可加載’的section組成。通過輸出section描述的屬性:PHDRS可以將輸出section加入一個程序段,: PHDRS中的PHDRS為程序段名。在一個輸出section描述內(nèi)可以多次使用:PHDRS命令,也即可以將一個section加入多個程序段。
如果在一個輸出section描述內(nèi)指定了:PHDRS屬性,那么其后的輸出section描述將默認使用該屬性,除非它也定義了:PHDRS屬性。顯然當多個輸出section屬于同一程序段時可簡化書寫。
在TYPE屬性后存在FILEHDR關(guān)鍵字,表示該段包含ELF文件頭信息;存在PHDRS關(guān)鍵字,表示該段包含ELF程序頭信息。
TYPE可以是以下八種形式: PT_NULL 0表示未被使用的程序段 PT_LOAD 1表示該程序段在程序運行時應(yīng)該被加載 PT_DYNAMIC 2表示該程序段包含動態(tài)連接信息 PT_INTERP 3表示該程序段內(nèi)包含程序加載器的名字,在linux下常見的程序加載器是ld-linux.so.2 PT_NOTE 4表示該程序段內(nèi)包含程序的說明信息 PT_SHLIB 5一個保留的程序頭類型,沒有在ELF ABI文檔內(nèi)定義 PT_PHDR 6表示該程序段包含程序頭信息。 EXPRESSION 表達式值
以上每個類型都對應(yīng)一個數(shù)字,該表達式定義一個用戶自定的程序頭。
AT(ADDRESS)屬性定義該程序段的加載位置(LMA),該屬性將**覆蓋**該程序段內(nèi)的section的AT()屬性。
默認情況下,連接器會根據(jù)該程序段包含的section的屬性(什么屬性?好象在輸出section描述內(nèi)沒有看到)設(shè)置FLAGS標志,該標志用于設(shè)置程序段描述的p_flags域。
(3)版本號命令
請參看原文介紹
2.4 SECTIONS詳解
SECTIONS命令告訴ld如何把輸入文件的sections映射到輸出文件的各個section: 如何將輸入section合為輸出section; 如何把輸出section放入程序地址空間(VMA)和進程地址空間(LMA),格式如下:
SECTIONS
{
ENTRY命令/符號賦值語句/一個輸出section的描述(output section description)/一個section疊加描述(overlay description)
}
其中,一個輸出section描述的格式為:
SECTION [ADDRESS] [(TYPE)] : [AT(LMA)]
{
符號賦值語句/一個輸入section描述/直接包含的數(shù)據(jù)值/一個特殊的輸出section關(guān)鍵字
} [>REGION] [AT>LMA_REGION] [:PHDR
HDR ...] [=FILLEXP]
說明如下:
(1)輸出section名字(SECTION):
輸出section名字必須符合輸出文件格式要求,比如:a.out格式的文件只允許存在.text、.data和.bss section名。而有的格式只允許存在數(shù)字名字,那么此時應(yīng)該用引號將所有名字內(nèi)的數(shù)字組合在一起;另外,還有一些格式允許任何序列的字符存在于 section名字內(nèi),此時如果名字內(nèi)包含特殊字符(比如空格、逗號等),那么需要用引號將其組合在一起。
(2)輸出section地址(ADDRESS):
ADDRESS是一個表達式,它的值用于設(shè)置VMA。如果沒有該選項且有REGION選項,那么連接器將根據(jù)REGION設(shè)置VMA;如果也沒有 REGION選項,那么連接器將根據(jù)定位符號‘.’的值設(shè)置該section的VMA,將定位符號的值調(diào)整到滿足輸出section對齊要求后的值,輸出 section的對齊要求為:該輸出section描述內(nèi)用到的所有輸入section的對齊要求中最嚴格的。
注意:設(shè)置ADDRESS值,將更改定位符號的值。
(3)TYPE :
每個輸出section都有一個類型,如果沒有指定TYPE類型,那么連接器根據(jù)輸出section引用的輸入section的類型設(shè)置該輸出section的類型。它可以為以下五種值,
NOLOAD :該section在程序運行時,不被載入內(nèi)存。
DSECT,COPY,INFO,OVERLAY
:這些類型很少被使用,為了向后兼容才被保留下來。這種類型的section必須被標記為“不可加載的”,以便在程序運行不為它們分配內(nèi)存。
(4)輸出section的LMA :
默認情況下,LMA等于VMA,但可以通過關(guān)鍵字AT()指定LMA。
用關(guān)鍵字AT()指定,括號內(nèi)包含表達式,表達式的值用于設(shè)置LMA。如果不用AT()關(guān)鍵字,那么可用AT>LMA_REGION表達式設(shè)置指定該section加載地址的范圍。
這個屬性主要用于構(gòu)件ROM境象。
(5)輸入section描述:
最常見的輸出section描述命令是輸入section描述。輸入section描述是最基本的連接腳本描述。
1)輸入section描述基礎(chǔ):
基本語法:FILENAME([EXCLUDE_FILE
(FILENAME1 FILENAME2 ...) SECTION1 SECTION2 ...)
FILENAME文件名,可以是一個特定的文件的名字,也可以是一個字符串模式。
SECTION名字,可以是一個特定的section名字,也可以是一個字符串模式
例如:
*(.text) :表示所有輸入文件的.text section (*(EXCLUDE_FILE (*crtend.o *otherfile.o) .ctors)) :表示除crtend.o、otherfile.o文件外的所有輸入文件的.ctors section。 data.o(.data) :表示data.o文件的.data section data.o :表示data.o文件的所有section *(.text .data) :表示所有文件的.text section和.data section,順序是:第一個文件的.text section,第一個文件的.data section,第二個文件的.text section,第二個文件的.data section,... *(.text) *(.data) :表示所有文件的.text section和.data section,順序是:第一個文件的.text section,第二個文件的.text section,...,最后一個文件的.text section,第一個文件的.data section,第二個文件的.data section,...,最后一個文件的.data section
2)字符串模式內(nèi)可存在以下通配符:
* :表示任意多個字符 ? :表示任意一個字符 [CHARS] :表示任意一個CHARS內(nèi)的字符,可用-號表示范圍,如:a-z :表示引用下一個緊跟的字符 SORT():對滿足字符串模式的所有名字進行遞增排序,如SORT(.text*)。
在文件名內(nèi),通配符不匹配文件夾分隔符/,但當字符串模式僅包含通配符*時除外。另外,任何一個文件的任意section只能在SECTIONS命令內(nèi)出現(xiàn)一次。
3)通用符號(common symbol)的輸入section
在許多目標文件格式中,通用符號并沒有占用一個section。連接器認為:輸入文件的所有通用符號在名為COMMON的section內(nèi)。
4)輸入section和垃圾回收
在連接命令行內(nèi)使用了選項–gc-sections后,連接器可能將某些它認為沒用的section過濾掉,此時就有必要強制連接器保留一些特定的 section,可用KEEP()關(guān)鍵字達此目的。如KEEP(*(.text))或KEEP(SORT(*)(.text))。
5)在輸出section存放數(shù)據(jù)命令
能夠顯示地在輸出section內(nèi)填入你想要填入的信息(這樣是不是可以自己通過連接腳本寫程序?當然是簡單的程序)。
BYTE(EXPRESSION) 1 字節(jié)
SHORT(EXPRESSION) 2 字節(jié)
LOGN(EXPRESSION) 4 字節(jié)
QUAD(EXPRESSION) 8 字節(jié)
SQUAD(EXPRESSION) 64位處理器的代碼時,8 字節(jié)
注意,這些命令只能放在輸出section描述內(nèi),其他地方不行。
錯誤:SECTIONS { .text : { *(.text) } LONG(1) .data : { *(.data) } }
正確:SECTIONS { .text : { *(.text) LONG(1) } .data : { *(.data) } }
6)FILL(EXPRESSION)和=FILEEXP屬性
在當前輸出section內(nèi)可能存在未描述的存儲區(qū)域(比如由于對齊造成的空隙),可以用FILL(EXPRESSION)命令決定這些存儲區(qū)域的內(nèi)容, EXPRESSION的前兩字節(jié)有效,這兩字節(jié)在必要時可以重復(fù)被使用以填充這類存儲區(qū)域。如FILE(0×9090)。在輸出section描述中可以
有=FILEEXP屬性,它的作用如同F(xiàn)ILE()命令,但是FILE命令只作用于該FILE指令之后的section區(qū)域,而=FILEEXP屬性作用
于整個輸出section區(qū)域,且FILE命令的優(yōu)先級更高!!!
7)輸出section內(nèi)命令的關(guān)鍵字
CREATE_OBJECT_SYMBOLS
:為每個輸入文件建立一個符號,符號名為輸入文件的名字。每個符號所在的section是出現(xiàn)該關(guān)鍵字的section。
CONSTRUCTORS :與c++內(nèi)的(全局對象的)構(gòu)造函數(shù)和(全局對像的)析構(gòu)函數(shù)相關(guān)。具體介紹可參看原文 http://linux.chinaunix.net/techdoc/beginner/2009/08/12/1129972.shtml。
8)輸出section的丟棄
例子,.foo { *(.foo) },如果沒有任何一個輸入文件包含.foo section,那么連接器將不會創(chuàng)建.foo輸出section。但是如果在這些輸出section描述內(nèi)包含了非輸入section描述命令(如符號
賦值語句),那么連接器將總是創(chuàng)建該輸出section。
有一個特殊的輸出section,名為/DISCARD/,被該section引用的任何輸入section將不會出現(xiàn)在輸出文件內(nèi),
(6)覆蓋圖(overlay)描述
覆蓋圖描述使兩個或多個不同的section占用同一塊程序地址空間。覆蓋圖管理代碼負責(zé)將section的拷入和拷出。文法如下,
SECTIONS {
…
OVERLAY [START] : [NOCROSSREFS] [AT ( LDADDR )]
{
SECNAME1
{
OUTPUT-SECTION-COMMAND
OUTPUT-SECTION-COMMAND
…
} [:PHDR...] [=FILL]
SECNAME2
{
OUTPUT-SECTION-COMMAND
OUTPUT-SECTION-COMMAND
…
} [:PHDR...] [=FILL]
…
} [>REGION] [:PHDR...] [=FILL]
…
}
由以上文法可以看出,同一覆蓋圖內(nèi)的section具有相同的VMA。SECNAME2的LMA為SECTNAME1的LMA加上SECNAME1的大 小,同理計算SECNAME2,3,4…的LMA。SECNAME1的LMA由LDADDR決定,如果它沒有被指定,那么由START決定,如果它也沒有
被指定,那么由當前定位符號的值決定。
NOCROSSREFS關(guān)鍵字指定各section之間不能交叉引用,否則報錯。
對于OVERLAY描述的每個section,連接器將定義兩個符號__load_start_SECNAME和__load_stop_SECNAME,這兩個符號的值分別代表SECNAME
section的LMA地址的開始和結(jié)束。
連接器處理完OVERLAY描述語句后,將定位符號的值加上所有覆蓋圖內(nèi)section大小的最大值。
2.5 暗含的鏈接腳本
輸入文件可以是目標文件,也可以是連接腳本,此時的連接腳本被稱為暗含的連接腳本。如果連接器不認識某個輸入文件,那么該文件被當作連接腳本被解析。一個暗含的連接腳本不會替換默認的連接腳本,僅僅是增加新的連接而已。在連接命令行中,每個輸入文件的順序都被固定好了,暗含的連接腳本在連接命令行內(nèi)占住一個位置,這個位置決定了由該連接腳本指定的輸入文件在連接過程中的順序。
三、實例
例1:
以下腳本將輸出文件的text
section定位在0×10000, data section定位在0×8000000:
SECTIONS
{
. = 0×10000;
.text : { *(.text) }
. = 0×8000000;
.data : { *(.data) }
.bss : { *(.bss) }
}
解釋一下上述的例子:
. = 0×10000 : 把定位器符號置為0×10000
(若不指定, 則該符號的初始值為0).
.text : { *(.text) } : 將所有(*符號代表任意輸入文件)輸入文件的.text
section合并成一個.text section, 該section的地址由定位器符號的值指定, 即0×10000.
. = 0×8000000 :把定位器符號置為0×8000000
.data : { *(.data) } : 將所有輸入文件的.data
section合并成一個.data section, 該section的地址被置為0×8000000.
.bss : { *(.bss) } : 將所有輸入文件的.bss
section合并成一個.bss section,該section的地址被置為0×8000000+.data section的大小.
連接器每讀完一個section描述后, 將定位器符號的值*增加*該section的大小. 注意: 此處沒有考慮對齊約束。
例2
SECTIONS{
…
OVERLAY 0×1000 : AT (0×4000)
{
.text0 { o1/*.o(.text) }
.text1 { o2/*.o(.text) }
}
…
}
.text0 section和.text1 section的VMA地址是0×1000,.text0 section加載于地址0×4000,.text1 section緊跟在其后。
程序代碼,拷貝.text1 section代碼:
extern char __load_start_text1, __load_stop_text1; memcpy ((char *) 0×1000, &__load_start_text1, &__load_stop_text1 – &__load_start_text1);
例3
PHDRS
{
headers PT_PHDR PHDRS ;
interp PT_INTERP ;
text PT_LOAD FILEHDR PHDRS ;
data PT_LOAD ;
dynamic PT_DYNAMIC ;
}
SECTIONS
{
. = SIZEOF_HEADERS;
.interp : { *(.interp) } :text :interp
.text : { *(.text) } :text
.rodata : { *(.rodata) } /* defaults to :text */
…
. = . + 0×1000; /* move to a new page in memory */
.data : { *(.data) } :data
.dynamic : { *(.dynamic) } :data :dynamic
…
}
例4
MEMORY
{
rom (rx) : ORIGIN = 0, LENGTH = 256K
ram (!rx) : org = 0×40000000, l = 4M
}
總結(jié)
- 上一篇: 英文qq网名130个
- 下一篇: 与时俱进的意思