|
Posted on 2011-06-03 23:15 S.l.e!ep.¢% 閱讀(1457) 評論(0) 編輯 收藏 引用 所屬分類: Unix
使用ld
********
本文檔介紹GNU連接器ld的2.14版本.
本文檔在GNU自由文檔許可證下發(fā)行.在"GNU自由文檔許可證"一章中有關(guān)于本許可證的一份拷貝.
概述
********
'ld'把一定量的目標(biāo)文件跟檔案文件連接起來,并重定位它們的數(shù)據(jù),連接符號引用.一般,在編譯一個程序
時(shí),最后一步就是運(yùn)行'ld'.
'ld'能接受連接命令語言文件,這是一種用AT&T的連接編輯命令語言的超集寫成的文件,用來在連接的整個
過程中提供顯式的,全局的控制.
本版本的'ld'使用通用BFD庫來操作目標(biāo)文件.這就允許'ld'讀取,合并,寫入目標(biāo)文件時(shí),可以使用各種不同
的格式,比如,COFF或'a.out'. 不同的格式可以被連接到一起產(chǎn)生一個有效的目標(biāo)文件.
除了它的靈活性,GNU連接器比其它連接器更有用的地方在于它提供了診斷信息. 許多連接器在碰到一個錯誤
的時(shí)候立即放棄執(zhí)行;但'ld'卻能夠繼續(xù)執(zhí)行,以讓你發(fā)現(xiàn)其他的錯誤(或者,在某些情況下,得到一個帶有錯誤
的輸出文件)
引用
**********
GNU連接器'ld'能夠處理大量的不同情況,并且跟其他的連接器保持盡可能的兼容.這樣,你就擁有更多的選擇來
控制它的行為.
命令行選項(xiàng)
====================
連接器提供大量的命令行選項(xiàng),但是,在實(shí)際使用中,只有少數(shù)被經(jīng)常使用.比如,'ld'的一個經(jīng)常的使用場合是在
一個標(biāo)準(zhǔn)的Unix系統(tǒng)上連接標(biāo)準(zhǔn)的Unix目標(biāo)文件.在這樣的一個系統(tǒng)上,連接文件'hello.o'如下:
ld -o OUTPUT /lib/crt0.o hello.o -lc
這告訴'ld'產(chǎn)生一個叫OUTPUT的文件,作為連接文件'/lib/crt0.o'和'hello.o'和庫'libc.a'的結(jié)果.'libc.a'
來自標(biāo)準(zhǔn)的搜索路徑.(參閱下文的關(guān)于'-l'選項(xiàng)的討論).
有些命令行選項(xiàng)可以在命令行的任何位置出現(xiàn).但是,那些帶有文件名的選項(xiàng),比如'-l'或者'-T',會讓文件在選
項(xiàng)出現(xiàn)的位置上被讀取. 對于非文件選項(xiàng),以帶不同的參數(shù)重復(fù)它,不會有進(jìn)一步的效果,或者覆蓋掉前面的相同
項(xiàng).那些多次出現(xiàn)時(shí)具有特殊含義的選項(xiàng)會在下文的描述中指出.
無參數(shù)選項(xiàng)是那些被連接的目標(biāo)文件和檔案文件.它們可能緊隨命令行選項(xiàng),或在它們前面,或者跟它們夾雜在一
起,但是一個目標(biāo)文件參數(shù)是不會出現(xiàn)在一個選項(xiàng)跟它的參數(shù)之間的.
通常,連接器至少引用一個目標(biāo)文件,但是你可指定其它形式的二進(jìn)制輸入文件,這可以通過'-l','-R'或者腳本
命令語言來實(shí)現(xiàn).如果沒有任何二進(jìn)制文件被指定,連接器不會產(chǎn)生任何輸出,并給出信息:"缺少輸入文件."
如果連接器不能識別目標(biāo)文件的格式,它會假設(shè)這些只是連接腳本.以這種方式指定的腳本增加了連接用的主連
接腳本的內(nèi)容(主連接腳本即缺省連接腳本或使用'-T'指定的腳本). 這個特性可以允許連接器連接一些文件,
它們看上去既像目標(biāo)文件,又像檔案文件,但實(shí)際上只是定義了一些符號值,或者使用'INPUT'或'GROUP'來載入其
它的目標(biāo)文件.需要注意的是,用這種方式指定一個腳本只是增加了主連接腳本的內(nèi)容;要完全替換掉主連接腳本
,需要使用'-T'.
對于名稱是單個字符的選項(xiàng),選項(xiàng)參數(shù)必須緊跟在選項(xiàng)字母后面,中間不留空,或者也可留有一個空格.
對于名稱是多個字符的選項(xiàng),選項(xiàng)前可以有一個或兩個破折號;比如,'-trace-symbol'和`--trace-symbol'是等價(jià)
的. 注意,對于這條規(guī)則有一個例外.那些以小寫字母'o'開頭的多字符選項(xiàng)前面只能是兩個破折號,這是為了避免
跟選項(xiàng)'-o'混淆. 比如'-omagic'把輸出文件的名字定為'magic',而'--omagic'在輸出文件中設(shè)置NMAGIC標(biāo)志.
多字符選項(xiàng)的參數(shù)必須跟選項(xiàng)名間以一個等于號分開,或者以一個空格分開.比如:`--trace-symbol foo'和
`--trace-symbol=foo'是等價(jià)的. 多字符選項(xiàng)的名字唯一縮寫符也是可以被接受的.
注意,如果連接器通過被編譯器驅(qū)動來間接引用(比如gcc), 那所有的連接器命令行選項(xiàng)前必須加上前綴'-Wl'
(或者能被特定編譯器驅(qū)動接受的其他前綴),就像下面這樣:
gcc -Wl,--startgroup foo.o bar.o -Wl,--endgroup
這很重要,因?yàn)榉駝t的話,編譯器驅(qū)動程序會默認(rèn)丟掉這些連接選項(xiàng),產(chǎn)生一個錯誤的連接.
下面是關(guān)于被GNU連接器接受的常用命令行開關(guān)的一個列表:
`-aKEYWORD'
這個選項(xiàng)在HP/UX兼容系統(tǒng)上被支持. 參數(shù)KEYWORD必須是下面字符串中的一個:`archive',
`shared', or `default'. `-aarchive'在功能上跟`-Bstatic'相同,而另外兩個關(guān)鍵字功能上跟
`-Bdynamic'相同. 這個選項(xiàng)可被多次使用.
`-AARCHITECTURE'
`--architecture=ARCHITECTURE'
在最近發(fā)行版本的'ld'中,這個選項(xiàng)只在Intel 960系列架構(gòu)上有用. 在那種'ld'配置中,參數(shù)
ARCHITECTURE確定960系列的某一特定架構(gòu),啟用某些安全措施,并修改檔案庫的搜索路徑.
將來的'ld'發(fā)行版可能為其它架構(gòu)系列支持相似的功能.
`-b INPUT-formAT'
`--format=INPUT-formAT'
'ld'可以被配置為支持多于一種的目標(biāo)文件.如果你的'ld'以這種方式被配置,你可以使用'-b'選
項(xiàng)為輸入目標(biāo)文件指定二進(jìn)制格式. 就算'ld'被配置為支持可選目標(biāo)格式,你不必經(jīng)常指定這一項(xiàng),
因?yàn)?ld'被配置為在每一臺機(jī)子上把最常用的格式作為默認(rèn)輸入格式. INPUT-formAT是一個字符串,
你可能在連接一個不常用的二進(jìn)制格式文件時(shí)需要這個參數(shù).你也可使用'-b'來顯式切換格式(在連接
不同格式的目標(biāo)文件時(shí)),方法是在每一組特定格式的目標(biāo)前使用'-b INPUT-formAT'.
缺省的格式是從環(huán)境變量'GNUTARGET'中得到的.你也可以從一個腳本中定義輸入格式,使用的命令是
'TARGET'.
`-c MRI-COMMANDFILE'
`--mri-script=MRI-COMMANDFILE'
為了跟MRI生產(chǎn)的連接器兼容,'ld'接受另一種用受限命令語言寫成的腳本文件,通過選項(xiàng)'-c'引入MRI
腳本文件;使用'-T'選項(xiàng)是運(yùn)行用普通'ld'腳本語言寫的連接腳本.如果MRI-CMDFILE不存在,'ld'在'-L'
指定的目錄中尋找.
`-d'
`-dc'
`-dp'
這三個選項(xiàng)是等價(jià)的; 多字符形式是為了跟其他連接器兼容才被支持的.它們給普通符號分配空間,即
使一個重定位輸出文件已經(jīng)被指定(通過'-r'). 腳本命令`FORCE_COMMON_ALLOCATION'具有同樣的效果.
`-e ENTRY'
`--entry=ENTRY'
使用符號ENTRY作為你的程序的開始執(zhí)行點(diǎn),而不是使用缺省的進(jìn)入點(diǎn).如果沒有叫做ENTRY的符號,連接器
會企圖把ENTRY作為一個數(shù)字進(jìn)行分析,并使用它作為入口地址(數(shù)字會被解釋為10進(jìn)制的;你可以使用前
導(dǎo)的'0x'強(qiáng)制為16進(jìn)制,或'0'作為8進(jìn)制.)
`-E'
`--export-dynamic'
當(dāng)創(chuàng)建一個動態(tài)連接的可執(zhí)行程序時(shí), 把所有的符號加到動態(tài)符號表中.動態(tài)符號表是一個符號集,這
些符號對于運(yùn)行時(shí)的動態(tài)對象是可見的.
如果你不使用這個選項(xiàng),動態(tài)符號表中就會只含有那些連接進(jìn)來的動態(tài)對象中用到的符號
如果你使用'dlopen'來載入動態(tài)對象,它需要引用程序中的符號,那你可能需要在連接程序時(shí)用到這個
選項(xiàng).
你也可以使用版本腳本來控制哪些符號應(yīng)當(dāng)被加到動態(tài)符號表中.
`-EB'
連接big-endian對象. 這會影響缺省輸出格式.
`-EL'
連接little-endian對象. 這會影響缺省輸出格式.
`-g'
忽略. 為了跟其它工具兼容而提供.
`-i'
執(zhí)行一個增量連接(跟'-r'等同)
`-init NAME'
當(dāng)創(chuàng)建一個ELF可執(zhí)行文件或共享對象時(shí),當(dāng)可執(zhí)行文件或共享對象被加載時(shí),調(diào)用NAME, 這是通過把
DT_INIT設(shè)置成函數(shù)的地址實(shí)現(xiàn)的. 缺省情況下,連接器使用'_init'作為調(diào)用的函數(shù).
`-lARCHIVE'
`--library=ARCHIVE'
增加一個檔案文件ARCHIVE到連接的文件列表中.這個選項(xiàng)可以被多次使用. 'ld'會為每一個指定的
ARCHIVE搜索它的路徑列表,尋找`libARCHIVE.a'
對于支持共享庫的系統(tǒng), 'ld'可能還會搜索擴(kuò)展名不是'.a'庫.特別的,在ELF和SunOS系統(tǒng)上,'ld'會
在搜索帶有'.a'擴(kuò)展名的庫前搜索帶'.so'擴(kuò)展名的庫.
`-M'
`--print-map'
打印一個連接位圖到標(biāo)準(zhǔn)輸出.一個連接位圖提供的關(guān)于連接的信息有如下一些:
* 目標(biāo)文件和符號被映射到內(nèi)存的哪些地方.
* 普通符號如何被分配空間.
* 所有被連接進(jìn)來的檔案文件,還有導(dǎo)致檔案文件被包含進(jìn)來的那個符號.
`-n'
`--nmagic'
關(guān)閉所有節(jié)的頁對齊,如果可能,把輸出格式標(biāo)識為'NMAGIC'.
`-N'
`--omagic'
把text和data節(jié)設(shè)置為可讀寫.同時(shí),取消數(shù)據(jù)節(jié)的頁對齊,同時(shí),取消對共享庫的連接.如果輸出格式
支持Unix風(fēng)格的magic number, 把輸出標(biāo)志為'OMAGIC'.
`--no-omagic'
這個選項(xiàng)執(zhí)行的操作大部分正好跟'-N'相反.它設(shè)置text節(jié)只讀,強(qiáng)制data節(jié)頁對齊. 但是,這個選項(xiàng)
并不開啟連接共享庫的功能. 使用'-Bdynamic'開啟這個功能.
`-o OUTPUT'
`--output=OUTPUT'
使用OUTPUT作為'ld'產(chǎn)生的程序的名字;如果這個選項(xiàng)沒有指定,缺省的輸出文件名是'a.out'.腳本命
令'OUTPUT'也可以被用來指定輸出文件的文件名.
`-O LEVEL'
如果LEVEL是一個比0大的數(shù)值, 'ld'優(yōu)化輸出.這可能會明顯多占用時(shí)間,所以只有在生成最后的文件
時(shí)使用.
`-q'
`--emit-relocs'
把重定位節(jié)和內(nèi)容留在完全連接后的可執(zhí)行文件中. 連接分析和優(yōu)化工具可能需要這些信息用來進(jìn)行
正確的修改與執(zhí)行. 這在大的可執(zhí)行文件中有用.
這個選項(xiàng)目前只支持ELF平臺.
`-r'
`--relocateable'
產(chǎn)生可重定位的輸出, 比如,產(chǎn)生一個輸出文件它可再次作為'ld'的輸入.這經(jīng)常被叫做"部分連接".
作為一個副作用,在支持標(biāo)準(zhǔn)Unix魔數(shù)的環(huán)境中,這個選項(xiàng)會把輸出文件的魔數(shù)設(shè)置為'OMAGIC'. 如
果這個選項(xiàng)沒有被指定,一個絕對文件就會被產(chǎn)生.當(dāng)連接C++程序時(shí),這個選項(xiàng)就不會解析構(gòu)造函數(shù)的
引用;要解析,必須使用'-Ur'
如果輸入文件跟輸出文件的格式不同,只有在輸入文件不含有重定位信息的時(shí)候部分連接才被支持.輸
出格式不同的時(shí)候會有更多的限制.比如,有些'a.out'的格式在輸入文件是其他格式的時(shí)候完全不支
持部分連接.
這個選項(xiàng)跟'-i'等效.
`-R FILENAME'
`--just-symbols=FILENAME'
從FILENAME中讀取符號名跟它們的值,但不重位這個文件,或者根本不把它包含在輸出文件中.這就允
許你的輸出文件引用其它程序中定義的絕對內(nèi)存地址.你可以多次使用這個選項(xiàng).
為了跟其他ELF連接器兼容,如果'-R'選項(xiàng)后面跟有一個目錄名,而不是一個文件名,它會被處理成
'-rpath'選項(xiàng).
`-s'
`--strip-all'
忽略輸出文件中所有的符號信息.
`-S'
`--strip-debug'
忽略輸出文件中所有的調(diào)試符號信息(但不是所有符號).
`-t'
`--trace'
打印'ld'處理的所有輸入文件的名字.
`-T SCRIPTFILE'
`--script=SCRIPTFILE'
把SCRIPTFILE作為連接腳本使用. 這個腳本會替代'ld'的缺省連接腳本(而不是增加它的內(nèi)容),所以
命令文件必須指定所有需要的東西以精確描述輸出文件. 如果SCRIPTFILE在當(dāng)前目錄下不存在,'ld'
會在'-L'選項(xiàng)指定的所有目錄下去尋找.多個'-T'選項(xiàng)會使內(nèi)容累積.
`-u SYMBOL'
`--undefined=SYMBOL'
強(qiáng)制SYMBOL在輸出文件中作為一個無定義的符號被輸入.這樣做會有一些效果,比如,會引發(fā)從標(biāo)準(zhǔn)庫
中連接更多的模塊. '-u'可以以不同的參數(shù)反復(fù)使用,以輸入多個無定義的符號.這個選項(xiàng)跟連接腳
本命令中的'EXTERN'是等效的.
`-Ur'
對于不是C++的程序,這個選項(xiàng)跟'-r'是等效的: 它產(chǎn)生可重定位的輸出,比如,一個輸出文件它可以再
次作為'ld'的輸入. 當(dāng)連接C++程序時(shí),'-Ur'解析構(gòu)造函數(shù)的引用,跟'-r'不同. 但如果在一些用'-Ur'
連接過的文件上再次使用'-Ur',它不會工作,因?yàn)橐坏?gòu)造函數(shù)表被建立,它不能被添加內(nèi)容.請只在
最后一遍連接的時(shí)候使用'-Ur', 對其它的,只使用'-r'.
`--unique[=SECTION]'
對于所有匹配SECTION的輸入節(jié),在輸出文件中都各自創(chuàng)建單獨(dú)的節(jié),或者,如果可選的通配符SECTION
參數(shù)丟失了,為每一個孤兒輸入節(jié)創(chuàng)建一個輸出節(jié). 一個孤兒節(jié)是一個連接腳本中沒有指定的節(jié).你
可以在命令行上多次使用這個選項(xiàng); 它阻止對同名輸入節(jié)的合并,在連接腳本中重載輸出節(jié)分配.
`-v'
`--version'
`-V'
顯示'ld'的版本. '-V'選項(xiàng)同時(shí)會列出支持的模擬器.
`-x'
`--discard-all'
刪除所有的本地符號.
`-X'
`--discard-locals'
刪除所有的臨時(shí)本地符號.對于大多數(shù)目標(biāo)平臺,就是所有的名字以'L'開頭的本地符號.
`-y SYMBOL'
`--trace-symbol=SYMBOL'
打印出所有SYMBOL出現(xiàn)的被連接文件的名字. 這個選項(xiàng)可以被多次使用. 在很多系統(tǒng)中,這在預(yù)先確定底
線時(shí)很有必要.
當(dāng)你擁有一個未定義的符號,但不知道這個引用出自哪里的時(shí)候,這個選項(xiàng)很有用.
`-Y PATH'
為缺省的庫搜索路徑增加一條路徑.這個選項(xiàng)是為了跟Solaris兼容.
`-z KEYWORD'
能被識別的關(guān)鍵字包括'initfirst', 'interpose', 'loadfltr',`nodefaultlib', `nodelete',
`nodlopen', `nodump', `now', `origin',`combreloc', `nocombreloc' and `nocopyreloc'. 為了跟
Solaris兼容,所有其它的關(guān)鍵字都被忽略. 'initfirst'標(biāo)志一個對象,使它在運(yùn)行時(shí),在所有其他對象之
前被初始化. 'interpose'標(biāo)志一個對象,使它的符號表放在所有其他符號之前,作為主要的執(zhí)行者.
'loadfltr'標(biāo)志一個對象, 使它的過濾器在運(yùn)行時(shí)立即被處理.'nodefaultlib'標(biāo)志一個對象,使在搜索
本對象所依賴的庫時(shí),忽略所有缺省庫搜索路徑. 'nodelete'標(biāo)志一個對象,使它在運(yùn)行時(shí)不會被從內(nèi)存
中刪除.'nodlopen'標(biāo)志一個對象,使這個對象不可以通過'dlopen'載入.'nodump'標(biāo)志一個對象,使它不能
被'dldump'轉(zhuǎn)儲. 'now'標(biāo)志一個對象,使它成為非懶惰運(yùn)行時(shí)綁定對象. 'origin'標(biāo)志一些可能含有
$ORIGIN的對象,'defs'不允許無定義符號. 'muldefs'允許重定義. 'comberloc'組合多個重定位節(jié),重新
排布它們,讓動態(tài)符號可見. 'nocomberloc'使多個重定位節(jié)組合無效. 'nocopyreloc'使重定位拷貝后的
結(jié)果無效.
`-( ARCHIVES -)'
`--start-group ARCHIVES --end-group'
ARCHIVES應(yīng)當(dāng)是一個關(guān)于檔案文件的列表. 它們可以是顯式的文件名,或者'-l'選項(xiàng).
這些指定的檔案文件會被多遍搜索,直到?jīng)]有新的無定義引用被創(chuàng)建. 通常,一個檔案文件只會被搜索一
次. 但如果這個檔案文件中的一個符號需要被用來解析一個檔案中的目標(biāo)引用到的無定義的符號,而這個
符號在命令行上的后面某個檔案文件中出現(xiàn), 連接器不能解析這個引用. 把這些檔案文件分組后,它們都
可被反復(fù)搜索直到所有可能的引用都被解析了為止.
使用這個選項(xiàng)有一個很大的運(yùn)行開銷. 只有在無法避免在多個檔案文件中使用循環(huán)引用時(shí)才用它.
`--accept-unknown-input-arch'
`--no-accept-unknown-input-arch'
告訴連接器接受那些架構(gòu)不能被識別的輸入文件. 但前提假設(shè)是用戶知道他們在做什么,并且是故意要連
接這些未知的輸入文件. 在版本2.14之前,這個是連接器的缺省行為. 從版本2.14以后的,缺省行為是拒
絕這類輸入文件, 所以`--accept-unknown-input-arch'選項(xiàng)被用來恢復(fù)舊的行為.
`-assert KEYWORD'
這個選項(xiàng)被忽略,只是用來跟SunOS保持兼容.
`-Bdynamic'
`-dy'
`-call_shared'
連接動態(tài)鏈接庫. 這個僅僅在支持共享庫的平臺上有用.在這些平臺上,這個選項(xiàng)通常是默認(rèn)行為. 這個選
項(xiàng)的不同形式是為了跟不同的系統(tǒng)保持兼容. 你可以在命令行上多次使用這個選項(xiàng):它影響緊隨其后的'-l'
選項(xiàng)的庫搜索.
`-Bgroup'
在動態(tài)節(jié)的'DT_FLAGS_1'入口上設(shè)置'DF_1_GROUP'標(biāo)志.這會讓運(yùn)行時(shí)連接器在處理在這個對象和它的相
關(guān)部分搜索時(shí)只在組中. '--no-undefined'是隱式的. 這個選項(xiàng)只在支持共享庫的ELF平臺上有用.
`-Bstatic'
`-dn'
`-non_shared'
`-static'
不連接共享庫. 這個僅僅在支持共享庫的平臺上有用. 這個選項(xiàng)的不同形式是為了跟不同的系統(tǒng)保持兼
容. 你可以在命令行上多次使用這個選項(xiàng):它影響緊隨其后的'-l'選項(xiàng)的庫搜索.
`-Bsymbolic'
當(dāng)創(chuàng)建一個共享庫時(shí), 把對全局符號的引用綁定到共享庫中的定義(如果有), 通常, 一個連接共享庫的程
序重載共享庫中的定義是可能的. 這個選項(xiàng)只在支持共享庫的ELF平臺上有用.
`--check-sections'
`--no-check-sections'
讓連接器在節(jié)地址被分配后不要去檢查節(jié)地址是否重疊.通常,連接器會執(zhí)行這種檢查,如果它發(fā)現(xiàn)了任何
重疊,它會產(chǎn)生相應(yīng)的錯誤信息. 連接器知道也允許節(jié)的重疊. 缺省的行為可以使用命令行開關(guān)
`--check-sections'來恢復(fù).
`--cref'
輸出一個交叉引用表. 如果一個連接器位圖文件被產(chǎn)生, 交叉引用表被打印到位圖文件. 否則, 它被打印
到標(biāo)準(zhǔn)輸出.
表的格式相當(dāng)?shù)暮唵? 所以,如果需要,可以通過一個腳本很輕易地處理它. 符號是以名字被打印輸出,存
儲. 對于每一個符號,給出一個文件名列表. 如果符號被定義了, 列出的第一個文件是符號定義的所在.
接下來的文件包含符號的引用.
`--no-define-common'
這個選項(xiàng)限制對普通符號的地址分配. 腳本命令`INHIBIT_COMMON_ALLOCATION'具有同等的效果.
`--no-define-common'選項(xiàng)允許從輸出文件的類型選擇中確定對普通符號的地址分配; 否則, 一個非重定
位輸出類型強(qiáng)制為普通符號分配地址. 使用'--no-define-common'允許那些從共享庫中引用的普通符號只
在主程序中被分配地址. 這會消除在共享庫中的無用的副本的空間, 同時(shí),也防止了在有多個指定了搜索
路徑的動態(tài)模塊在進(jìn)行運(yùn)行時(shí)符號解析時(shí)引起的混亂.
`--defsym SYMBOL=EXdivSSION'
在輸出文件中建立一個全局符號,這個符號擁有一個EXdivSSION指定的絕對地址. 你可以多次使用這個選
項(xiàng)定義多個符號. EXdivSSION支持一個受限形式的算術(shù)運(yùn)算:你可以給出一個十六進(jìn)制常數(shù)或者一個已存
在符號的名字,或者使用'+'和'-'來加或減十六進(jìn)制常數(shù)或符號. 如果你需要更多的表達(dá)式,可以考慮在腳
本中使用連接器命令語言, 注意在SYMBOL,=和EXdivSSION之間不允許有空格.
`--demangle[=style]'
`--no-demangle'
這些選項(xiàng)控制是否在錯誤信息和其它的輸出中重組符號名. 當(dāng)連接器被告知要重組, 它會試圖把符號名以
一種可讀的形式的展現(xiàn): 如果符號被以目標(biāo)文件格式使用,它剝?nèi)デ皩?dǎo)的下劃線,并且把C++形式的符號名
轉(zhuǎn)換成用戶可讀的名字. 不同的編譯器有不同的重組形式. 可選的重組形式參數(shù)可以被用來為你的編譯器
選擇一個相應(yīng)的重組形式. 連接器會以缺省形式重組直至環(huán)境變量`COLLECT_NO_DEMANGLE'被設(shè)置. 這些
選項(xiàng)可以被用來重載缺省的設(shè)置.
`--dynamic-linker FILE'
設(shè)置動態(tài)連接器的名字. 這個只在產(chǎn)生動態(tài)連接的ELF可執(zhí)行文件時(shí)有效. 缺省的動態(tài)連接器通常是正確
的; 除非你知道你在干什么,不要使用這個選項(xiàng).
`--embedded-relocs'
這個選項(xiàng)只在連接MIPS嵌入式PIC代碼時(shí)有效, 這些代碼必須是由GNU的編譯器跟匯編器通過-membedded-pic
選項(xiàng)生成的. 它導(dǎo)致連接器產(chǎn)生一個表,這個表被用來在運(yùn)行時(shí)重定位所有的被靜態(tài)初始化為指針值的數(shù)
據(jù).
`--fatal-warnings'
把所有的警告視為錯誤.
`--force-exe-suffix'
確保輸出文件有一個.exe后綴.
如果一個被成功完整連接的輸出文件不帶有一個'.exe'或'.dll'后綴, 這個選項(xiàng)確保連接器把輸出文件
拷貝成帶有'.exe'后綴的同名文件. 這個選項(xiàng)在使用微軟系統(tǒng)來編譯未經(jīng)修改的Unix的makefile時(shí)很有
用, 因?yàn)橛行┌姹镜?a class="channel_keylink" 后綴的映像.
`--no-gc-sections'
`--gc-sections'
允許對未使用的輸入節(jié)的碎片收集. 在不支持這個選項(xiàng)的平臺上,被忽略. 這個選項(xiàng)不能跟 '-r'選項(xiàng)共存
也不能被用來進(jìn)行動態(tài)連接. 缺省行為可以用`--no-gc-sections'進(jìn)行恢復(fù).
`--help'
在標(biāo)準(zhǔn)輸出上打印一個命令行選項(xiàng)概要,然后退出.
`--target-help'
打印一個所有目標(biāo)平臺相關(guān)的選項(xiàng)的概要,然后退出.
`-Map MAPFILE'
打印一個連接位圖到文件MAPFILE中. 參閱上面關(guān)于'-M'選項(xiàng)的描述.
`--no-keep-memory'
'ld'通常會以速度優(yōu)先于內(nèi)存使用的方式優(yōu)化程序,這是通過把輸入文件的符號表放在內(nèi)存緩沖中實(shí)現(xiàn)的,
這個選項(xiàng)告訴'ld'以內(nèi)存使用優(yōu)先來優(yōu)化, 盡可能的減小符號表的重讀. 這在'ld'在連接一個大文件時(shí)
超出內(nèi)存限制時(shí)有用.
`--no-undefined'
`-z defs'
通常,當(dāng)創(chuàng)建一個非符號共享庫時(shí), 無定義的符號允許出現(xiàn),并留待運(yùn)行時(shí)連接器去解決. 這個選項(xiàng)關(guān)閉這
樣的無定義符號的使用. 開關(guān)`--no-allow-shlib-undefined'控制共享對象被連接進(jìn)共享庫時(shí)的行為.
`--allow-multiple-definition'
`-z muldefs'
通常,當(dāng)一個符號被定義多次時(shí), 連接器會報(bào)告一個致命錯誤. 這些選項(xiàng)允許重定義并且第一個定義被使
用
`--allow-shlib-undefined'
`--no-allow-shlib-undefined'
允許(缺省)或不允許無定義符號存在于共享對象中. 這個開關(guān)的設(shè)置會重載'--no-undefined',這里只關(guān)
注共享對象. 這樣,如果'--no-undefined'被設(shè)置,但'--no-allow-shlib-undefined'未被設(shè)置, 連鎖反應(yīng)
是存在于規(guī)則對象文件中的無定義的符號會引起一個錯誤,但是在共享對象中的未定義的符號會被忽略.
把`--allow-shlib-undefined'設(shè)置為缺省的原因是在連接時(shí)指定的共享對象并不一定是載入時(shí)可載入的
那個,所以,符號可能要到載入時(shí)間才被解析.
`--no-undefined-version'
通常當(dāng)一個符號有一個未定義的版本時(shí),連接器會忽略它. 這個選項(xiàng)不允許符號有未定義的版本,并且碰
到這種情況,會報(bào)告一個嚴(yán)重錯誤.
`--no-warn-mismatch'
通常, 如果你因?yàn)橐恍┰?企圖把一些不匹配的輸入文件連接起來的時(shí)候,'ld'會給出一個錯誤,可能這
些文件是因?yàn)橛刹煌奶幚砥骶幾g. 這個選項(xiàng)告訴'ld'應(yīng)當(dāng)對這樣的錯誤默認(rèn)允許. 這個選項(xiàng)必須小心
使用.
`--no-whole-archive'
為后面的檔案文件關(guān)閉'--whole-archive'選項(xiàng)的影響.
`--noinhibit-exec'
當(dāng)一個可執(zhí)行文件還可以使用時(shí),就保留它. 通常,連接器如果在連接過程中遇到了錯誤,就不會產(chǎn)生輸出
文件;當(dāng)它遇上錯誤時(shí),它會退出而不寫輸出文件.
`-nostdlib'
僅搜索那些在命令行上顯式指定的庫路徑. 在連接腳本中(包含在命令行上指定的連接腳本)指定的庫路
徑都被忽略.
`--oformat OUTPUT-formAT'
'ld'可以被配置為支持多于一種的目標(biāo)文件. 如果你的'ld'以這種方式被配置,你可以使用'--oformat'
選項(xiàng)來指定輸出目標(biāo)文件的二進(jìn)制格式.就算'ld'被配置為支持多種目標(biāo)格式,你也不必指定這個項(xiàng),因
為'ld'應(yīng)當(dāng)被配置為把最常用的輸出格式作為默認(rèn)格式. OUTPUT-formAT是一個文本串,是被BFD庫支持
的一個特定格式的名字.腳本命令'OUTPUT_formAT'也可以指定輸出格式,但這個選項(xiàng)可以覆蓋它.
`-qmagic'
這個選項(xiàng)被忽略,只是為了跟Linux保持兼容.
`-Qy'
這個選項(xiàng)被忽略,只是為了跟SVR4保持兼容.
`--relax'
一個機(jī)器相關(guān)的選項(xiàng). 只有在少數(shù)平臺上,這個選項(xiàng)被支持.
在某些平臺上,'--relax'選項(xiàng)在連接器解析程序中的地址時(shí)執(zhí)行可能的全局優(yōu)化, 比如松散地址模式和在輸出文件
中合成新的指令.
在某些平臺上,連接時(shí)全局優(yōu)化會進(jìn)行符號調(diào)試導(dǎo)致程序不能運(yùn)行.
在不支持這個選項(xiàng)的平臺上,'--relax'被接受,但被忽略.
`--retain-symbols-file FILENAME'
只保留在FILENAME中列出的那些符號,丟棄所有其他的. FILENAME是一個簡單地平坦模式文件, 一個符號占一行.
這個選項(xiàng)在那些會逐步積累起一個大的全局符號表的系統(tǒng)中(比如 VxWorks)會很有用,它能有效地節(jié)約內(nèi)存空間.
'--retain-symbols-file'不丟棄未定義的符號,和需要重定位的符號.
你可能在命令行上只指定'--retain-symbol-file'一次, 它覆蓋'-s'和'-S'的功能.
`-rpath DIR'
為運(yùn)行時(shí)庫的搜索路徑增加一個目錄. 這個在連接帶有共享庫的ELF可執(zhí)行文件時(shí)有用. '-rpath'的所有參數(shù)會被
連接起來傳遞給運(yùn)行時(shí)連接器, 運(yùn)行時(shí)連接器在運(yùn)行時(shí)用它們定位共享對象. '-rpath'選項(xiàng)在定位那些在連接參數(shù)
指定的共享對象需要的共享對象時(shí)也很有用; 參閱關(guān)于'-rpath-link'選項(xiàng)的描述, 如果在連接一個ELF可執(zhí)行文件
時(shí)不使用'-rpath'選項(xiàng),那些環(huán)境變量'LD_RUN_PATH'選項(xiàng)就會被使用.
'-rptah'選項(xiàng)也可以使用在SunOS上. 缺省地,在SunOS上,連接器會從所有的'-L'選項(xiàng)中形成一個運(yùn)行時(shí)搜索路徑.
如果使用了'-rpath'選項(xiàng), 那運(yùn)行時(shí)搜索路徑就只從'-rpath'選項(xiàng)中得到, 忽略'-L'選項(xiàng). 這在使用GCC時(shí)非常有
用, 它會用上很多的'-L'選項(xiàng),而這些路徑很可能就是NFS掛上去的文件系統(tǒng)中.
為了同ELF的連接器兼容, 如果'-R'選面后面跟有一個目錄名, 而不是一個文件名,那它也會被處理成'-rpath'選
項(xiàng).
`-rpath-link DIR'
當(dāng)在SunOS上使用ELF時(shí),一個共享庫可能會用到另一個共享庫. 當(dāng)'ld -share'把一個共享庫作為一個輸入文件連接
時(shí)就有可能發(fā)生這種情況.
當(dāng)一個連接器在作非共享,不可重定位連接時(shí),如果遇上這種依賴情況,它會自動定位需要的共享庫,然后把它包含在
連接中, 如果在這種情況中,它沒有被顯式包含, 那'-rpath-link'選項(xiàng)指定優(yōu)先搜索的一組路徑名.
這個選項(xiàng)必須小心使用,因?yàn)樗鼤采w那些可能已經(jīng)被編譯進(jìn)共享庫中的搜索路徑. 在這種情況下,它就有可能使用
一個非內(nèi)部的不同的搜索路徑.
連接器使用下面的搜索路徑來定位需要的共享庫:
1. 所有由'-rpath-link'選項(xiàng)指定的搜索路徑.
2. 所有由'-rpath'指定的搜索路徑. '-rpath'跟'-rpath_link'的不同之處在于,由'-rpath'指定的路徑被包含在可
執(zhí)行文件中,并在運(yùn)行時(shí)使用, 而'-rpath-link'選項(xiàng)僅僅在連接時(shí)起作用. 它只用于本地連接器.
3. 在一個ELF系統(tǒng)中, 如果'-rpath'和'rpath-link'選項(xiàng)沒有被使用, 會搜索環(huán)境變量'LD_RUN_PATH'的內(nèi)容.它也只
對本地連接器起作用.
4. 在SunOS上, '-rpath'選項(xiàng)不使用, 只搜索所有由'-L'指定的目錄.
5. 對于一個本地連接器,環(huán)境變量'LD_LIBRARY_PATH'的內(nèi)容被搜索.
6. 對于一個本地ELF連接器,共享庫中的`DT_RUNPATH'和`DT_RPATH'操作符會被需要它的共享庫搜索. 如果'DT_RUNPATH'
存在了, 那'DT_RPATH'就會被忽略.
7. 缺省目錄, 常規(guī)的,如'/lib'和'/usr/lib'.
8. 對于ELF系統(tǒng)上的本地連接器, 如果文件'/etc/ld.so.conf'存在, 這個文件中有的目錄會被搜索.
如果需要的共享庫沒有被找到, 那連接器會發(fā)出一條警告信息,并繼續(xù)執(zhí)行連接.
`-shared'
`-Bshareable'
創(chuàng)建一個共享庫. 這個選項(xiàng)只在ELF, XCOFF和SunOS平臺上有用。 在SunOS上,如果'-e'選項(xiàng)沒有被使用,并在連接
中有未定義的符號,連接器會自動創(chuàng)建一個共享庫,
`--sort-common'
這個選項(xiàng)告訴'ld'當(dāng)它把普通符號放到相應(yīng)的輸出節(jié)中時(shí)按大小進(jìn)行排序。排在最前面的是所有的一字節(jié)符號,然
后是所有的二字節(jié),然后是所有的四字節(jié), 然后是其它的。 這是為了避免因?yàn)閷R約束而在符號間產(chǎn)生的斷裂
`--split-by-file [SIZE]'
跟'--split-by-reloc'相似,但在SIZE達(dá)到時(shí),為每一個輸入文件創(chuàng)建一個新的輸出節(jié)。如果沒有給出,SIZE缺省
地設(shè)置為1
`--split-by-reloc [COUNT]'
試圖在輸出文件中創(chuàng)建節(jié)外的節(jié),這樣就沒有單個的輸出節(jié)含有多于COUNT個重定位符。這在產(chǎn)生巨大的用于COFF格
式的實(shí)時(shí)內(nèi)核的可重定位文件時(shí)非常有用;因?yàn)镃OFF不能在一個節(jié)中表示多于65535個重定位。 注意,這在不支持
專有節(jié)的目標(biāo)文件格式中會失敗,連接器不會把單個輸入節(jié)分割進(jìn)行重分配, 所以,如果單個輸入節(jié)含有多于COUNT
個重定位符, 那一個輸出節(jié)會含有同樣多的可重定位符。COUNT缺省被設(shè)為32768.
`--stats'
計(jì)算并顯示關(guān)于連接器操作的統(tǒng)計(jì)信息, 比如執(zhí)行時(shí)間,內(nèi)存占用等.
`--traditional-format'
對于某些目標(biāo)平臺, 'ld'的輸出會跟某些面有的連接器的輸出有所不同. 這個開關(guān)要求'ld'使用傳
統(tǒng)的格式.
比如, 在SunOS上, 'ld'會把符號串表中的兩上完全相同的入口合并起來. 這可以把一個帶有調(diào)試信息
的輸出文件的大小減小百發(fā)之三十. 不幸地是, SunOS的'dbx'程序不能讀取這個輸出的程序(gdb就沒
有問題).'--trafitinal-format'開關(guān)告訴'ld'不要把相同的入口合并起來.
`--section-start SECTIONNAME=ORG'
通過指定ORG, 指定節(jié)在輸出文件中的絕對地址. 你可以多次使用這個選項(xiàng)來定位多個節(jié). ORG必須是
一個十六進(jìn)制整數(shù); 為了跟基他的連接器兼容,你可以忽略前導(dǎo)'0x'. 注意,在SECTIONNAME,等號,ORG
之間不允許有空格出現(xiàn).
`-Tbss ORG'
`-Tdata ORG'
`-Ttext ORG'
跟-section-start同義, 不過把SECTIONNAME替換為'.bss', '.data'或'.text'.
`--dll-verbose'
`--verbose'
顯示'ld'的版本號,并列出支持的連接器模擬. 顯示哪些輸入文件能被打開,而哪些不能. 顯示連接器
使用的連接腳本.
`--version-script=VERSION-SCRIPTFILE'
指定連接器的腳本的版本名. 這個常在創(chuàng)建一個需要指定附加的關(guān)于版本層次的信息的共享庫時(shí)使用,
這個選項(xiàng)只有支持共享庫的ELF平臺上有效.
`--warn-common'
當(dāng)一個普通符號跟另一個普通符號或會號定義合并起來時(shí),警告. 類Unix連接器允許這個選項(xiàng),有時(shí)比
較實(shí)用, 但是在其他的操作系統(tǒng)上的連接器不允許這個. 這個選項(xiàng)可以讓你在合并全局符號時(shí)發(fā)現(xiàn)某
些潛在的問題. 不幸的是,有些C庫使用這項(xiàng)特性,所以你可能會像在你的程序中一樣,在庫中得到一些
警告信息.
這里給出三種類型的全局符號的解釋(用C語言):
`int i = 1;'
一個定義, 它會存在于輸出文件中的已初始化數(shù)據(jù)節(jié).
`extern int i;'
一個未定義符號,它不占用空間. 必須在另外某一處對它有一個定義,或一個普通符號
`int i;'
一個普通符號.如果對于一個變量只有(一個或多個)普通符號, 它進(jìn)入輸出文件的未初始化數(shù)據(jù)域. 連
接器會把同一變量的多個普通符號合并成一個單一的符號. 如果他們有不同的大小, 它采用最大的一
個. 如果是對同一變量的定義,連接器把一個普通符號轉(zhuǎn)化為一個聲明.
'--warn-common'選項(xiàng)可以產(chǎn)生五種類型的警告. 每種警告由兩行組成: 第一行描述遇到的符號, 第二
行描述遇到的前一個具有相同名字的符號. 一個或兩個都可能成為普通符號.
1. 把一個普通符號轉(zhuǎn)化為一個引用, 因?yàn)檫@個符號已經(jīng)有一個定義了.
FILE(SECTION): warning: common of `SYMBOL'
overridden by definition
FILE(SECTION): warning: defined here
2. 把一個普通符號轉(zhuǎn)化為一個引用,因?yàn)橛龅搅说诙€關(guān)于符號的定義. 這跟前一種情況相同,除了符
號遇到的順序相反.
FILE(SECTION): warning: definition of `SYMBOL'
overriding common
FILE(SECTION): warning: common is here
3. 把一個普通符號跟前一個相同大小的普通符號合并.
FILE(SECTION): warning: multiple common
of `SYMBOL'
FILE(SECTION): warning: divvious common is here
4. 把一個普通符號跟前一個更大的普通符號合并.
FILE(SECTION): warning: common of `SYMBOL'
overridden by larger common
FILE(SECTION): warning: larger common is here
5. 把一個普通符號跟前一個更小的普通符號合并. 這跟前一種情況相同, 除了遇到的符號的順序不同.
FILE(SECTION): warning: common of `SYMBOL'
overriding smaller common
FILE(SECTION): warning: smaller common is here
`--warn-constructors'
如果有全局結(jié)構(gòu)體被使用到了,警告. 這只對很少的一些目標(biāo)文件格式有用. 對于COFF或ELF格式, 連
接器不同探測到全局結(jié)構(gòu)體的使用.
`--warn-multiple-gp'
如果在輸出文件中,需要多個全局指針值,警告. 這只對特定的處理器有意義, 比如Alpha. 特別的,有
些處理器在特定的節(jié)中放入很大的常數(shù)值. 一個特殊的寄存器(全局指針)指向這個節(jié)的中間部分, 所
以通過一個基地址寄存器相關(guān)的地址模式,這個常數(shù)可以很容易地被載入. 因?yàn)檫@個基寄存器相關(guān)模式
的偏移值是固定的而且很小(比如,16位), 這會限制常量池的最大尺寸. 所以,一個很大的問題是,為了
能夠定位所有可能的常數(shù),經(jīng)常需要使用多個全局指針值. 這個選項(xiàng)在這種情況發(fā)生時(shí)產(chǎn)生一條警告.
`--warn-once'
對于每一個未定義符號只警告一次, 而不是在每一個用到它的模塊中警告一次.
`--warn-section-align'
如果輸出節(jié)的地址因?yàn)閷R被改變了,警告. 通常, 對齊會被輸入節(jié)設(shè)置. 如果'SECTION'命令沒有指
定節(jié)的起始地址, 地址就會被隱式改變.
`--whole-archive'
對于每一個在命令行中'--whole-archive'選項(xiàng)后面出現(xiàn)的檔案文件, 在連接中包含檔案文件中的所有
目標(biāo)文件, 而不是為需要的目標(biāo)文件搜索檔案文件. 這在把一個檔案文件轉(zhuǎn)化為一個共享庫時(shí)使用, 把
所有的目標(biāo)放到最終的共享庫中. 這個選項(xiàng)可以被多次使用.
在GCC中使用這個選項(xiàng)需要注意兩點(diǎn): 首先,GCC不知道這個選項(xiàng), 所以,你必須使用'-Wl, -whole-archive'.
第二, 不要忘了在你的檔案文件列表的后面使用'-Wl, -no-whole-archive',因?yàn)镚CC會把它自己的檔
案列表加到你的連接后面, 而這可能并不是你所預(yù)期的.
`--wrap SYMBOL'
對SYMBOL符號使用包裝函數(shù). 任何未定義的對SYMBOL符號的引用會被解析成'_wrap_SYMBOL'. 而任何
未定義的對'_real_SYMBOL'的引用會被解析成SYMBOL.
這可以用來為系統(tǒng)函靈敏提供一個包裝. 包裝函靈敏應(yīng)當(dāng)被叫做'__wrap_SYMBOL'. 如果需要調(diào)用這個
函數(shù), 那就應(yīng)該調(diào)用'__real_SYMBOL'
這里是一個沒什么實(shí)用價(jià)值的例子:
void *
__wrap_malloc (int c)
{
printf ("malloc called with %ld\n", c);
return __real_malloc ?;
}
如果你使用'--wrap malloc'把這節(jié)代碼跟其他的代碼連接, 那所有的對'malloc'的調(diào)用都會調(diào)用
'__wrap_malloc'函數(shù). 而在'__wrap_malloc'中的'__real_malloc'會調(diào)用真正的'malloc'函數(shù).
你有可能也希望提供一個'__real_malloc'函數(shù), 這樣,不帶有'--wrap'的連接器也會成功連接.如果
你這樣做了, 你不能把'__real_malloc'的定義跟'__wrap_malloc'放到同一個文件中;如果放在一起
匯編器會在連接器之前把調(diào)用解析成真正的'malloc'.
`--enable-new-dtags'
`--disable-new-dtags'
連接器可以在ELF中創(chuàng)建一個新的動態(tài)標(biāo)簽. 但是舊的ELF系統(tǒng)可能不理解這個. 如果你指定了
'--enable-new-dtags',動態(tài)標(biāo)簽會按需要被創(chuàng)建. 如果你指定了'--disable-new-dtags',那不會有
新的動態(tài)標(biāo)簽被創(chuàng)建. 缺省地,新的動態(tài)標(biāo)簽不會被創(chuàng)建. 注意這些選項(xiàng)只在ELF系統(tǒng)中有效.
i386 PE平臺的特定選項(xiàng).
-----------------------------------
i386 PE連接器支持'-shared'選項(xiàng), 它使輸出文件為一個動態(tài)鏈接庫(DLL),而不是一個普通的可執(zhí)行文件. 在
使用這個選項(xiàng)的時(shí)候,你應(yīng)當(dāng)為輸出文件取名'*.dll',另外, 連接器完全支持標(biāo)準(zhǔn)的'*.def'文件, 這類文件可
以在連接器命令行上象一個目標(biāo)文件一樣被指定(實(shí)際上, 它應(yīng)當(dāng)被放在它從中導(dǎo)出符號的那個檔案文件前面,
以保證它們象一個普通的目標(biāo)文件一樣被連接進(jìn)去.)
除了對所有平臺通用的那些選項(xiàng)外,i386 PE連接器支持一些只對i386平臺專有的命令行選面. 帶有值的選項(xiàng)應(yīng)
當(dāng)用空格或等號把它跟值分隔開.
`--add-stdcall-alias'
如果給出這個選項(xiàng), 帶有標(biāo)準(zhǔn)調(diào)用后綴(@NN)的符號會被剝掉后綴后導(dǎo)出.
`--base-file FILE'
使用FILE作為文件名,該文件是存放用'dlltool'產(chǎn)生 DLL文件時(shí)所需的所有重定位符的基地址的.(這
個選面是i386 PE平臺所專有的]
`--dll'
創(chuàng)建一個DLL文件而不是一個常規(guī)可執(zhí)行文件. 你可能在一個給出的'.def'文件中使用'-shared'或指
定'LIBRARY'.
`--enable-stdcall-fixup'
`--disable-stdcall-fixup'
如果連接器發(fā)現(xiàn)有符號不能解析, 它會試圖進(jìn)行'失真連接',即尋找另一個定義的符號,它們只是在
符號名的格式上不同(cdecl vs stdcall),并把符號解析為找到的這個符號. 比如, 一個未定義的符
號'_foo'可能被連接到函數(shù)'_foo@12', 或者一個未定義的符號'_bar@16'可能被連接到函數(shù)'_bar'.
如果連接器這么做了, 它會打印出一條警告信息, 因?yàn)樵谡G闆r下,這會連接失敗, 但有時(shí),由第三
方庫產(chǎn)生的導(dǎo)入庫可能需要這個特性. 如果你指定了'--enable-stdcall-fixup', 這個特性會被完全
開啟,警告信息也不會打印出來. 如果你指定了'--disable-stdcall-fixup',這個特性被關(guān)閉,而且這
樣的錯誤匹配會被認(rèn)為是個錯誤.
`--export-all-symbols'
如果給出這個選項(xiàng),目標(biāo)中所有由DLL建立的全局符號會被DLL導(dǎo)出. 注意這是缺省情況,否則沒有任何
符號被導(dǎo)出. 如果符號由DEF文件顯式地導(dǎo)出,或由函數(shù)本身的屬性隱式地導(dǎo)出, 缺省情況是除非選項(xiàng)
給出,否則不導(dǎo)出任何其他的符號. 注意符號`DllMain@12',`DllEntryPoint@0',
`DllMainCRTStartup@12'和`impure_ptr'不會自動被導(dǎo)出.而且,由其他的DLL導(dǎo)入的符號也不會被再
次導(dǎo)出, 還有指定DLL內(nèi)部布局的符號,比如那些以'_head_'開頭,或者以'_iname'結(jié)尾的符號也不會
被導(dǎo)出.還有,'libgcc','libstd++','libmingw32'或'crtX.o'中的符號也不會被導(dǎo)出. ......
環(huán)境變量
=====================
你可以通過環(huán)境變量`GNUTARGET', `LDEMULATION'和`COLLECT_NO_DEMANGLE'改變'ld'的行為.
`GNUTARGET'在你沒有使用'-b'(或者它的同義詞'--format')的時(shí)候,決定輸入文件的格式. 它的值應(yīng)當(dāng)是BFD
中關(guān)于輸入格式的一個名字. 如果環(huán)境中沒有'GNUTARGET'變量, 'ld'使用目標(biāo)平臺的缺省格式. 如果
'GNUTARGET'被設(shè)為'default', 那BFD就會通過檢查二進(jìn)制的輸入文件來找到輸入格式; 這個方法通常會成功,
但會有潛在的不明確性, 因?yàn)闆]有辦法保證指定一個目標(biāo)文件格式的魔數(shù)總是唯一的. 但是, 在每一個系統(tǒng)上
的BFD配置程序會把這個系統(tǒng)的常規(guī)格式放在搜索列表的首位, 所以不明確性可以通過這種慣列來解決.
`LDEMULATION'在你沒有使用'-m'選項(xiàng)的時(shí)候決定缺省的模擬器. 模擬器可以影響到連接器行為的很多方面,
特別是連接器的缺省連接腳本. 你可以通過'--verbose'或'-V'選項(xiàng)列出所有可用的模擬器. 如果'-m'選項(xiàng)沒
有使用, 而且`LDEMULATION'環(huán)境變量沒有定義, 缺省的模擬器跟連接器如何被配置有關(guān).
一般地,連接器缺省狀況下會重構(gòu)符號.但是,如果在環(huán)境中設(shè)置了`COLLECT_NO_DEMANGLE', 那缺省狀態(tài)下就不
會重構(gòu)符號.這個環(huán)境變量在GCC的連接包裝程序中會以相似的方式被使用. 這個缺省的行為可以被'--demangle'
或'--no-demangle'選項(xiàng)覆蓋.
連接腳本
**************
每個連接都被一個'連接腳本'所控制. 這個腳本是用連接命令語言書寫的.
連接腳本的一個主要目的是描述輸入文件中的節(jié)如何被映射到輸出文件中,并控制輸出文件的內(nèi)存排布. 幾乎
所有的連接腳本只做這兩件事情. 但是,在需要的時(shí)候,連接器腳本還可以指示連接器執(zhí)行很多其他的操作.這
通過下面描述的命令實(shí)現(xiàn).
連接器總是使用連接器腳本的.如果你自己不提供, 連接器會使用一個缺省的腳本,這個腳本是被編譯進(jìn)連接器
可執(zhí)行文件的. 你可以使用'--verbose'命令行選項(xiàng)來顯示缺省的連接器腳本的內(nèi)容. 某些命令行選項(xiàng),比如
'-r'或'-N', 會影響缺省的連接腳本.
你可以過使用'-T'命令行選項(xiàng)來提供你自己的連接腳本. 當(dāng)你這么做的時(shí)候, 你的連接腳本會替換缺省的連
接腳本.
你也可以通過把連接腳本作為一個連接器的輸入文件來隱式地使用它,就象它們是一個被連接的文件一樣.
基本的連接腳本的概念
============================
我們需要定義一些基本的概念與詞匯以描述連接腳本語言.
連接器把多個輸入文件合并成單個輸出文件. 輸出文件和輸入文件都以一種叫做'目標(biāo)文件格式'的數(shù)據(jù)格式形
式存在. 每一個文件被叫做'目標(biāo)文件'. 輸出文件經(jīng)常被叫做'可執(zhí)行文件',但是由于需要,我們也把它叫做目
標(biāo)文件. 每一個目標(biāo)文件中,在其它東西之間,有一個節(jié)列表.我們有時(shí)把輸入文件的節(jié)叫做輸入節(jié); 相似的,輸
出文件中的一個節(jié)經(jīng)常被叫做輸出節(jié).
一個目標(biāo)文件中的每一個節(jié)都有一個名字和一個大小尺寸. 大多數(shù)節(jié)還有一個相關(guān)的數(shù)據(jù)塊, 稱為節(jié)內(nèi)容. 某
一個節(jié)可能被標(biāo)式詎'loadable',含義是在輸出文件被執(zhí)行時(shí),這個節(jié)應(yīng)當(dāng)被載入到內(nèi)存中去. 一個沒有內(nèi)容的
節(jié)可能是'allocatable', 含義是內(nèi)存中必須為這個節(jié)開辟一塊空間,但是沒有實(shí)際的內(nèi)容載入到這里(在某些
情況下,這塊內(nèi)存必須被標(biāo)式詎零). 一個既不是loadable也不是allocatable的節(jié)一般含有一些調(diào)試信息.
每一個loadable或allocatable的輸出節(jié)有兩個地址. 第一個是'VMA'或稱為虛擬內(nèi)存地址. 這是當(dāng)輸出文件運(yùn)
行時(shí)節(jié)所擁有的地址. 第二個是"LMA', 或稱為載入內(nèi)存地址. 這個節(jié)即將要載入的內(nèi)存地址. 這大多數(shù)情況下
這兩個地址是相同的. 它們兩個有可能不同的一個例子是當(dāng)一個數(shù)據(jù)節(jié)在ROM中時(shí), 當(dāng)程序啟動時(shí),被拷貝到RAM
中(這個技術(shù)經(jīng)常被用在基于ROM的系統(tǒng)中進(jìn)行全局變量的初始化). 在這種情況下, ROM地址就是LMA, 而RAM地
址就是VMA.
你可以通過使用帶有'-h'選項(xiàng)的'objdump'來察看目標(biāo)文件中的節(jié).
每一個目標(biāo)文件還有一個關(guān)于符號的列表, 被稱為'符號表'. 一個符號可能是定義過了的,也可能是未定義的.
每一個符號有一個名字, 而且每一個定義的符號有一個地址. 如果你把一個C/C++程序編譯為一個目標(biāo)文件,對
于每一個定義的函數(shù)和全局或靜態(tài)變量,你為得到一個定義的符號. 每一個在輸入文件中只是一個引用而未定義
的函數(shù)或全局變量會變成一個未定義的符號.
你可以使用'nm'程序來看一個目標(biāo)文件中的符號, 或者使用'objdump'程序帶有'-t'選項(xiàng).
連接腳本的格式
====================
連接腳本是文本文件.
你寫了一系列的命令作為一個連接腳本. 每一個命令是一個帶有參數(shù)的關(guān)鍵字,或者是一個對符號的賦值. 你可
以用分號分隔命令. 空格一般被忽略.
文件名或格式名之類的字符串一般可以被直接鍵入. 如果文件名含有特殊字符,比如一般作為分隔文件名用的逗
號, 你可以把文件名放到雙引號中. 文件名中間無法使用雙引號.
你可以象在C語言中一樣,在連接腳本中使用注釋, 用'/*'和'*/'隔開. 就像在C中,注釋在語法上等同于空格.
簡單的連接腳本示例
============================
許多腳本是相當(dāng)?shù)暮唵蔚?
可能的最簡單的腳本只含有一個命令: 'SECTIONS'. 你可以使用'SECTIONS'來描述輸出文件的內(nèi)存布局.
'SECTIONS'是一個功能很強(qiáng)大的命令. 這里這們會描述一個很簡單的使用. 讓我們假設(shè)你的程序只有代碼節(jié),
初始化過的數(shù)據(jù)節(jié), 和未初始化過的數(shù)據(jù)節(jié). 這些會存在于'.text','.data'和'.bss'節(jié), 另外, 讓我們進(jìn)一
步假設(shè)在你的輸入文件中只有這些節(jié).
對于這個例子, 我們說代碼應(yīng)當(dāng)被載入到地址'0x10000'處, 而數(shù)據(jù)應(yīng)當(dāng)從0x8000000處開始. 下面是一個實(shí)現(xiàn)
這個功能的腳本:
SECTIONS
{
. = 0x10000;
.text : { *(.text) }
. = 0x8000000;
.data : { *(.data) }
.bss : { *(.bss) }
}
你使用關(guān)鍵字'SECTIONS'寫了這個SECTIONS命令, 后面跟有一串放在花括號中的符號賦值和輸出節(jié)描述的內(nèi)容.
上例中, 在'SECTIONS'命令中的第一行是對一個特殊的符號'.'賦值, 這是一個定位計(jì)數(shù)器. 如果你沒有以其
它的方式指定輸出節(jié)的地址(其他方式在后面會描述), 那地址值就會被設(shè)為定位計(jì)數(shù)器的現(xiàn)有值. 定位計(jì)數(shù)器
然后被加上輸出節(jié)的尺寸. 在'SECTIONS'命令的開始處, 定位計(jì)數(shù)器擁有值'0'.
第二行定義一個輸出節(jié),'.text'. 冒號是語法需要,現(xiàn)在可以被忽略. 節(jié)名后面的花括號中,你列出所有應(yīng)當(dāng)被
放入到這個輸出節(jié)中的輸入節(jié)的名字. '*'是一個通配符,匹配任何文件名. 表達(dá)式'*(.text)'意思是所有的輸
入文件中的'.text'輸入節(jié).
因?yàn)楫?dāng)輸出節(jié)'.text'定義的時(shí)候, 定位計(jì)數(shù)器的值是'0x10000',連接器會把輸出文件中的'.text'節(jié)的地址設(shè)
為'0x10000'.
余下的內(nèi)容定義了輸出文件中的'.data'節(jié)和'.bss'節(jié). 連接器會把'.data'輸出節(jié)放到地址'0x8000000'處. 連接
器放好'.data'輸出節(jié)之后, 定位計(jì)數(shù)器的值是'0x8000000'加上'.data'輸出節(jié)的長度. 得到的結(jié)果是連接器會
把'.bss'輸出節(jié)放到緊接'.data'節(jié)后面的位置.
連接器會通過在必要時(shí)增加定位計(jì)數(shù)器的值來保證每一個輸出節(jié)具有它所需的對齊. 在這個例子中, 為'.text'
和'.data'節(jié)指定的地址會滿足對齊約束, 但是連接器可能會需要在'.data'和'.bss'節(jié)之間創(chuàng)建一個小的缺口.
就這樣,這是一個簡單但完整的連接腳本.
簡單的連接腳本命令.
=============================
在本章中,我們會描述一些簡單的腳本命令.
設(shè)置入口點(diǎn).
-----------------------
在運(yùn)行一個程序時(shí)第一個被執(zhí)行到的指令稱為"入口點(diǎn)". 你可以使用'ENTRY'連接腳本命令來設(shè)置入口點(diǎn).參數(shù)
是一個符號名:
ENTRY(SYMBOL)
有多種不同的方法來設(shè)置入口點(diǎn).連接器會通過按順序嘗試以下的方法來設(shè)置入口點(diǎn), 如果成功了,就會停止.
* `-e'入口命令行選項(xiàng);
* 連接腳本中的`ENTRY(SYMBOL)'命令;
* 如果定義了start, 就使用start的值;
* 如果存在,就使用'.text'節(jié)的首地址;
* 地址`0'.
處理文件的命令.
---------------------------
有幾個處理文件的連接腳本命令.
`INCLUDE FILENAME'
在當(dāng)前點(diǎn)包含連接腳本文件FILENAME. 在當(dāng)前路徑下或用'-L'選項(xiàng)指定的所有路徑下搜索這個文件,
你可以嵌套使用'INCLUDE'達(dá)10層.
`INPUT(FILE, FILE, ...)'
`INPUT(FILE FILE ...)'
'INPUT'命令指示連接器在連接時(shí)包含文件, 就像它們是在命令行上指定的一樣.
比如,如果你在連接的時(shí)候總是要包含文件'subr.o',但是你對每次連接時(shí)要在命令行上輸入感到厭煩
, 你就可以在你的連接腳本中輸入'INPUT (subr.o).
事實(shí)上,如果你喜歡,你可以把你所有的輸入文件列在連接腳本中, 然后在連接的時(shí)候什么也不需要,
只要一個'-T'選項(xiàng)就夠了.
在一個'系統(tǒng)根前綴'被配置的情況下, 一個文件名如果以'/'字符打頭, 并且腳本也存放在系統(tǒng)根
前綴的某個子目錄下, 文件名就會被在系統(tǒng)根前綴下搜索. 否則連接器就會企圖打開當(dāng)前目錄下的文
件. 如果沒有發(fā)現(xiàn), 連接器會通過檔案庫搜索路徑進(jìn)行搜索.
如果你使用了'INPUT (-lFILE)', 'ld'會把文件名轉(zhuǎn)換為'libFILE.a', 就象命令行參數(shù)'-l'一樣.
當(dāng)你在一個隱式連接腳本中使用'INPUT'命令的時(shí)候, 文件就會在連接時(shí)連接腳本文件被包含的點(diǎn)上
被包含進(jìn)來. 這會影響到檔案搜索.
`GROUP(FILE, FILE, ...)'
`GROUP(FILE FILE ...)'
除了文件必須全是檔案文件之外, 'GROUP'命令跟'INPUT'相似, 它們會被反復(fù)搜索,直至沒有未定義
的引用被創(chuàng)建.
`OUTPUT(FILENAME)'
'OUTPUT'命令命名輸出文件. 在連接腳本中使用'OUTPUT(FILENAME)'命令跟在命令行中使用'-o
FILENAME'命令是完全等效的. 如果兩個都使用了, 那命令行選項(xiàng)優(yōu)先.
你可以使用'OUTPUT'命令為輸出文件創(chuàng)建一個缺省的文件名,而不是常用的'a.out'.
`SEARCH_DIR(PATH)'
`SEARCH_DIR'命令給'ld'用于搜索檔案文件的路徑中再增加新的路徑. 使用`SEARCH_DIR(PATH)'跟在
命令行上使用'-L PATH'選項(xiàng)是完全等效的. 如果兩個都使用了, 那連接器會兩個路徑都搜索. 用命
令行選項(xiàng)指定的路徑首先被搜索.
`STARTUP(FILENAME)'
除了FILENAME會成為第一個被連接的輸入文件, 'STARTUP'命令跟'INPUT'命令完全相似, 就象這個文
件是在命令行上第一個被指定的文件一樣. 如果在一個系統(tǒng)中, 入口點(diǎn)總是存在于第一個文件中,那
這個就很有用.
處理目標(biāo)文件格式的命令.
-----------------------------------------
有兩個處理目標(biāo)文件格式的連接腳本命令.
`OUTPUT_formAT(BFDNAME)'
`OUTPUT_formAT(DEFAULT, BIG, LITTLE)'
`OUTPUT_formAT'命令為輸出文件使用的BFD格式命名. 使用`OUTPUT_formAT(BFDNAME)'跟在命令行上
使用'-oformat BFDNAME'是完全等效的. 如果兩個都使用了, 命令行選項(xiàng)優(yōu)先.
你可在使用`OUTPUT_formAT'時(shí)帶有三個參數(shù)以使用不同的基于'-EB'和'-EL'的命令行選項(xiàng)的格式.
如果'-EB'和'-EL'都沒有使用, 那輸出格式會是第一個參數(shù)DEFAULT, 如果使用了'-EB',輸出格式會是
第二個參數(shù)BIG, 如果使用了'-EL', 輸出格式會是第三個參數(shù), LITTLE.
比如, 缺省的基于MIPS ELF平臺連接腳本使用如下命令:
OUTPUT_formAT(elf32-bigmips, elf32-bigmips, elf32-littlemips)
這表示缺省的輸出文件格式是'elf32-bigmips', 但是當(dāng)用戶使用'-EL'命令行選項(xiàng)的時(shí)候, 輸出文件就會
被以`elf32-littlemips'格式創(chuàng)建.
`TARGET(BFDNAME)'
'TARGET'命令在讀取輸入文件時(shí)命名BFD格式. 它會影響到后來的'INPUT'和'GROUP'命令. 這個命令跟
在命令行上使用`-b BFDNAME'相似. 如果使用了'TARGET'命令但`OUTPUT_formAT'沒有指定, 最后的
'TARGET'命令也被用來設(shè)置輸出文件的格式.
其它的連接腳本命令.
----------------------------
還有一些其它的連接腳本命令.
`ASSERT(EXP, MESSAGE)'
確保EXP不等于零,如果等于零, 連接器就會返回一個錯誤碼退出,并打印出MESSAGE.
`EXTERN(SYMBOL SYMBOL ...)'
強(qiáng)制SYMBOL作為一個無定義的符號輸入到輸出文件中去. 這樣做了,可能會引發(fā)從標(biāo)準(zhǔn)庫中連接一些
節(jié)外的庫. 你可以為每一個EXTERN'列出幾個符號, 而且你可以多次使用'EXTERN'. 這個命令跟'-u'
命令行選項(xiàng)具有相同的效果.
`FORCE_COMMON_ALLOCATION'
這個命令跟命令行選項(xiàng)'-d'具有相同的效果: 就算指定了一個可重定位的輸出文件('-r'),也讓'ld'
為普通符號分配空間.
`INHIBIT_COMMON_ALLOCATION'
這個命令跟命令行選項(xiàng)`--no-define-common'具有相同的效果: 就算是一個不可重位輸出文件, 也讓
'ld'忽略為普通符號分配的空間.
`NOCROSSREFS(SECTION SECTION ...)'
這個命令在遇到在某些特定的節(jié)之間引用的時(shí)候會產(chǎn)生一條錯誤信息.
在某些特定的程序中, 特別是在使用覆蓋技術(shù)的嵌入式系統(tǒng)中, 當(dāng)一個節(jié)被載入內(nèi)存時(shí),另外一個節(jié)
就不會在內(nèi)存中. 任何在兩個節(jié)之間的直接引用都會是一個錯誤. 比如, 如果節(jié)1中的代碼調(diào)用了另
一個節(jié)中的一個函數(shù),這就會產(chǎn)生一個錯誤.
`NOCROSSREFS'命令帶有一個輸出節(jié)名字的列表. 如果'ld'遇到任何在這些節(jié)之間的交叉引用, 它就
會報(bào)告一個錯誤,并返回一個非零退出碼. 注意, `NOCROSSREFS'命令使用輸出節(jié)名,而不是輸入節(jié)名.
`OUTPUT_ARCH(BFDARCH)'
指定一個特定的輸出機(jī)器架構(gòu). 這個參數(shù)是BFD庫中使用的一個名字. 你可以通過使用帶有'-f'選項(xiàng)
的'objdump'程序來查看一個目標(biāo)文件的架構(gòu).
為符號賦值.
===========================
你可以在一個連接腳本中為一個符號賦一個值. 這會把一個符號定義為一個全局符號.
簡單的賦值.
------------------
你可以使用所有的C賦值符號為一個符號賦值.
`SYMBOL = EXdivSSION ;'
`SYMBOL += EXdivSSION ;'
`SYMBOL -= EXdivSSION ;'
`SYMBOL *= EXdivSSION ;'
`SYMBOL /= EXdivSSION ;'
`SYMBOL <<= EXdivSSION ;'
`SYMBOL >>= EXdivSSION ;'
`SYMBOL &= EXdivSSION ;'
`SYMBOL |= EXdivSSION ;'
第一個情況會把SYMBOL定義為值EXdivSSION. 其它情況下, SYMBOL必須是已經(jīng)定義了的, 而值會作出相應(yīng)的調(diào)
整.
特殊符號名'.'表示定位計(jì)數(shù)器. 你只可以在'SECTIONS'命令中使用它.
EXdivSSION后面的分號是必須的.
表達(dá)式下面會定義.
你在寫表達(dá)式賦值的時(shí)候,可以把它們作為單獨(dú)的部分,也可以作為'SECTIONS'命令中的一個語句,或者作為
'SECTIONS'命令中輸出節(jié)描述的一個部分.
符號所在的節(jié)會被設(shè)置成表達(dá)式所在的節(jié).
下面是一個關(guān)于在三處地方使用符號賦值的例子:
floating_point = 0;
SECTIONS
{
.text :
{
*(.text)
_etext = .;
}
_bdata = (. + 3) & ~ 3;
.data : { *(.data) }
}
在這個例子中, 符號`floating_point'被定義為零. 符號'-etext'會被定義為前面一個'.text'節(jié)尾部的地址.
而符號'_bdata'會被定義為'.text'輸出節(jié)后面的一個向上對齊到4字節(jié)邊界的一個地址值.
PROVIDE
-------
在某些情況下, 一個符號被引用到的時(shí)候只在連接腳本中定義,而不在任何一個被連接進(jìn)來的目標(biāo)文件中定
義. 這種做法是比較明智的. 比如, 傳統(tǒng)的連接器定義了一個符號'etext'. 但是, ANSI C需要用戶能夠把
'etext'作為一個函數(shù)使用而不會產(chǎn)生錯誤. 'PROVIDE'關(guān)鍵字可以被用來定義一個符號, 比如'etext', 這個
定義只在它被引用到的時(shí)候有效,而在它被定義的時(shí)候無效.語法是 `PROVIDE(SYMBOL = EXdivSSION)'.
下面是一個關(guān)于使用'PROVIDE'定義'etext'的例子:
SECTIONS
{
.text :
{
*(.text)
_etext = .;
PROVIDE(etext = .);
}
}
在這個例子中, 如果程序定義了一個'_etext'(帶有一個前導(dǎo)下劃線), 連接器會給出一個重定義錯誤. 如果,
程序定義了一個'etext'(不帶前導(dǎo)下劃線), 連接器會默認(rèn)使用程序中的定義. 如果程序引用了'etext'但不
定義它, 連接器會使用連接腳本中的定義.
SECTIONS命令
================
'SECTIONS'命令告訴連接器如何把輸入節(jié)映射到輸出節(jié), 并如何把輸出節(jié)放入到內(nèi)存中.
'SECTIONS'命令的格式如下:
SECTIONS
{
SECTIONS-COMMAND
SECTIONS-COMMAND
...
}
每一個SECTIONS-COMMAND可能是如下的一種:
* 一個'ENTRY'命令.
* 一個符號賦值.
* 一個輸出節(jié)描述.
* 一個重疊描述.
'ENTRY'命令和符號賦值在'SECTIONS'命令中是允許的, 這是為了方便在這些命令中使用定位計(jì)數(shù)器. 這也可
以讓連接腳本更容易理解, 因?yàn)槟憧梢栽诟幸饬x的地方使用這些命令來控制輸出文件的布局.
輸出節(jié)描述和重疊描述在下面描述.
如果你在連接腳本中不使用'SECTIONS'命令, 連接器會按在輸入文件中遇到的節(jié)的順序把每一個輸入節(jié)放到同
名的輸出節(jié)中. 如果所有的輸入節(jié)都在第一個文件中存在,那輸出文件中的節(jié)的順序會匹配第一個輸入文件中
的節(jié)的順序. 第一個節(jié)會在地址零處.
輸出節(jié)描述
--------------------------
一個完整的輸出節(jié)的描述應(yīng)該是這個樣子的:
SECTION [ADDRESS] [(TYPE)] : [AT(LMA)]
{
OUTPUT-SECTION-COMMAND
OUTPUT-SECTION-COMMAND
...
} [>REGION] [AT>LMA_REGION] [:PHDR :PHDR ...] [=FILLEXP]
大多數(shù)輸出節(jié)不使用這里的可選節(jié)屬性.
SECTION邊上的空格是必須的, 所以節(jié)名是明確的. 冒號跟花括號也是必須的. 斷行和其他的空格是可選的.
每一個OUTPUT-SECTION-COMMAND可能是如下的情況:
* 一個符號賦值.
* 一個輸入節(jié)描述.
* 直接包含的數(shù)據(jù)值.
* 一個特定的輸出節(jié)關(guān)鍵字.
輸出節(jié)名.
-------------------
輸出節(jié)的名字是SECTION. SECTION必須滿足你的輸出格式的約束. 在一個只支持限制數(shù)量的節(jié)的格式中,比如
'a.out',這個名字必須是格式支持的節(jié)名中的一個(比如, 'a.out'只允許'.text', '.data'或'.bss').如果
輸出格式支持任意數(shù)量的節(jié), 但是只支持?jǐn)?shù)字,而沒有名字(就像Oasys中的情況), 名字應(yīng)當(dāng)以一個雙引號中的
數(shù)值串的形式提供.一個節(jié)名可以由任意數(shù)量的字符組成,但是一個含有任意非常用字符(比如逗號)的字句必須
用雙引號引起來.
輸出節(jié)描述
--------------------------
ADDRESS是關(guān)于輸出節(jié)中VMS的一個表達(dá)式. 如果你不提供ADDRESS, 連接器會基于REGION(如果存在)設(shè)置它,或
者基于定位計(jì)數(shù)器的當(dāng)前值.
如果你提供了ADDRESS, 那輸出節(jié)的地址會被精確地設(shè)為這個值. 如果你既不提供ADDRESS也不提供REGION, 那
輸出節(jié)的地址會被設(shè)為當(dāng)前的定位計(jì)數(shù)器向上對齊到輸出節(jié)需要的對齊邊界的值. 輸出節(jié)的對齊要求是所有輸
入節(jié)中含有的對齊要求中最嚴(yán)格的一個.
比如:
.text . : { *(.text) }
和
.text : { *(.text) }
有細(xì)微的不同. 第一個會把'.text'輸出節(jié)的地址設(shè)為當(dāng)前定位計(jì)數(shù)器的值. 第二個會把它設(shè)為定位計(jì)數(shù)器的
當(dāng)前值向上對齊到'.text'輸入節(jié)中對齊要求最嚴(yán)格的一個邊界.
ADDRESS可以是任意表達(dá)式; 比如,如果你需要把節(jié)對齊對0x10字節(jié)邊界,這樣就可以讓低四字節(jié)的節(jié)地址值為
零, 你可以這樣做:
.text ALIGN(0x10) : { *(.text) }
這個語句可以正常工作,因?yàn)?ALIGN'返回當(dāng)前的定位計(jì)數(shù)器,并向上對齊到指定的值.
指定一個節(jié)的地址會改變定位計(jì)數(shù)器的值.
輸入節(jié)描述
-------------------------
最常用的輸出節(jié)命令是輸入節(jié)描述.
輸入節(jié)描述是最基本的連接腳本操作. 你使用輸出節(jié)來告訴連接器在內(nèi)存中如何布局你的程序. 你使用輸入節(jié)
來告訴連接器如何把輸入文件映射到你的內(nèi)存中.
輸入節(jié)基礎(chǔ)
---------------------------
一個輸入節(jié)描述由一個文件名后跟有可選的括號中的節(jié)名列表組成.
文件名和節(jié)名可以通配符形式出現(xiàn), 這個我們以后再介紹.
最常用的輸入節(jié)描述是包含在輸出節(jié)中的所有具有特定名字的輸入節(jié). 比如, 包含所有輸入'.text'節(jié),你可以
這樣寫:
*(.text)
這里,'*'是一個通配符,匹配所有的文件名. 為把一部分文件排除在匹配的名字通配符之外, EXCLUDE_FILE可
以用來匹配所有的除了在EXCLUDE_FILE列表中指定的文件.比如:
(*(EXCLUDE_FILE (*crtend.o *otherfile.o) .ctors))
會讓除了`crtend.o'文件和`otherfile.o'文件之外的所有的文件中的所有的.ctors節(jié)被包含進(jìn)來.
有兩種方法包含多于一個的節(jié):
*(.text .rdata)
*(.text) *(.rdata)
上面兩句的區(qū)別在于'.text'和'.rdata'輸入節(jié)的輸出節(jié)中出現(xiàn)的順序不同. 在第一個例子中, 兩種節(jié)會交替
出現(xiàn),并以連接器的輸入順序排布. 在第二個例子中,所有的'.text'輸入節(jié)會先出現(xiàn),然后是所有的'.rdata'節(jié).
你可以指定文件名,以從一個特定的文件中包含節(jié). 如果一個或多個你的文件含有特殊的數(shù)據(jù)在內(nèi)存中需要特
殊的定位,你可以這樣做. 比如:
data.o(.data)
如果你使用一個不帶有節(jié)列表的文件名, 那輸入文件中的所有的節(jié)會被包含到輸出節(jié)中. 通常不會這樣做, 但
是在某些場合下這個可能非常有用. 比如:
data.o
當(dāng)你使用一個不含有任何通配符的文件名時(shí), 連接器首先會查看你是否在連接命令行上指定了文件名或者在
'INPUT'命令中. 如果你沒有, 連接器會試圖把這個文件作為一個輸入文件打開, 就像它在命令行上出現(xiàn)一樣.
注意這跟'INPUT'命令不一樣, 因?yàn)檫B接器會在檔案搜索路徑中搜索文件.
輸入節(jié)通配符
---------------------------------
在一個輸入節(jié)描述中, 文件名或者節(jié)名,或者兩者同時(shí)都可以是通配符形式.
文件名通配符'*'在很多例子中都可以看到,這是一個簡單的文件名通配符形式.
通配符形式跟Unix Shell中使用的一樣.
`*'
匹配任意數(shù)量的字符.
`?'
匹配單個字符.
`[CHARS]'
匹配CHARS中的任意單個字符; 字符'-'可以被用來指定字符的方訌, 比如[a-z]匹配任意小字字符.
`\'
轉(zhuǎn)義其后的字符.
當(dāng)一個文件名跟一個通配符匹配時(shí), 通配符字符不會匹配一個'/'字符(在UNIX系統(tǒng)中用來分隔目錄名), 一個
含有單個'*'字符的形式是個例外; 它總是匹配任意文件名, 不管它是否含有'/'. 在一個節(jié)名中, 通配符字
符會匹配'/'字符.
文件名通配符只匹配那些在命令行或在'INPUT'命令上顯式指定的文件. 連接器不會通過搜索目錄來展開通配
符.
如果一個文件名匹配多于一個通配符, 或者如果一個文件名顯式出現(xiàn)同時(shí)又匹配了一個通配符, 連接器會使用
第一次匹配到的連接腳本. 比如, 下面的輸入節(jié)描述序列很可能就是錯誤的,因?yàn)?data.o'規(guī)則沒有被使用:
.data : { *(.data) }
.data1 : { data.o(.data) }
通常, 連接器會把匹配通配符的文件和節(jié)按在連接中被看到的順序放置. 你可以通過'SORT'關(guān)鍵字改變它, 它
出現(xiàn)在括號中的通配符之前(比如, 'SORT(.text*)'). 當(dāng)'SORT'關(guān)鍵字被使用時(shí), 連接器會在把文件和節(jié)放到
輸出文件中之前按名字順序重新排列它們.
如果你對于輸入節(jié)被放置到哪里去了感到很困惑, 那可以使用'-M'連接選項(xiàng)來產(chǎn)生一個位圖文件. 位圖文件會
精確顯示輸入節(jié)是如何被映射到輸出節(jié)中的.
這
個例子顯示了通配符是如何被用來區(qū)分文件的. 這個連接腳本指示連接器把所有的'.text'節(jié)放到'.text'中,
把所有的'.bss'節(jié)放到'.bss'. 連接器會把所有的來自文件名以一個大寫字母開始的文件中的'.data'節(jié)放進(jìn)'.DATA'節(jié)中;
對于所有其他文件, 連接器會把'.data'節(jié)放進(jìn)'.data'節(jié)中.
SECTIONS {
.text : { *(.text) }
.DATA : { [A-Z]*(.data) }
.data : { *(.data) }
.bss : { *(.bss) }
}
輸入節(jié)中的普通符號.
-----------------------------------
對于普通符號,需要一個特殊的標(biāo)識, 因?yàn)樵诤芏嗄繕?biāo)格式中, 普通符號沒有一個特定的輸入節(jié). 連接器會把
普通符號處理成好像它們在一個叫做'COMMON'的節(jié)中.
你可能像使用帶有其他輸入節(jié)的文件名一樣使用帶有'COMMON'節(jié)的文件名。你可以通過這個把來自一個特定輸
入文件的普通符號放入一個節(jié)中,同時(shí)把來自其它輸入文件的普通符號放入另一個節(jié)中。
在大多數(shù)情況下,輸入文件中的普通符號會被放到輸出文件的'.bss'節(jié)中。比如:
.bss { *(.bss) *(COMMON) }
有些目標(biāo)文件格式具有多于一個的普通符號。比如,MIPS ELF目標(biāo)文件格式區(qū)分標(biāo)準(zhǔn)普通符號和小普通符號。
在這種情況下,連接器會為其他類型的普通符號使用一個不同的特殊節(jié)名。 在MIPS ELF的情況中, 連接器
為標(biāo)準(zhǔn)普通符號使用'COMMON',并且為小普通符號使用'.common'。這就允許你把不同類型的普通符號映射到
內(nèi)存的不同位置。
在一些老的連接腳本上,你有時(shí)會看到'[COMMON]'。這個符號現(xiàn)在已經(jīng)過時(shí)了, 它等效于'*(COMMON)'。
輸入節(jié)和垃圾收集
---------------------------------------
當(dāng)連接時(shí)垃圾收集正在使用中時(shí)('--gc-sections'),這在標(biāo)識那些不應(yīng)該被排除在外的節(jié)時(shí)非常有用。這
是通過在輸入節(jié)的通配符入口外面加上'KEEP()'實(shí)現(xiàn)的,比如'KEEP(*(.init))'或者'KEEP(SORT(*)(.sorts))
'。
輸入節(jié)示例
---------------------
接下來的例子是一個完整的連接腳本。它告訴連接器去讀取文件'all.o'中的所有節(jié),并把它們放到輸出節(jié)
'outputa'的開始位置處, 該輸出節(jié)是從位置'0x10000'處開始的。 從文件'foo.o'中來的所有節(jié)'.input1'
在同一個輸出節(jié)中緊密排列。 從文件'foo.o'中來的所有節(jié)'.input2'全部放入到輸出節(jié)'outputb'中,后面
跟上從'foo1.o'中來的節(jié)'.input1'。來自所有文件的所有余下的'.input1'和'.input2'節(jié)被寫入到輸出節(jié)
'outputc'中。
SECTIONS {
outputa 0x10000 :
{
all.o
foo.o (.input1)
}
outputb :
{
foo.o (.input2)
foo1.o (.input1)
}
outputc :
{
*(.input1)
*(.input2)
}
}
輸出節(jié)數(shù)據(jù)
-------------------
你可以通過使用輸出節(jié)命令'BYTE','SHORT','LONG','QUAD',或者'SQUAD'在輸出節(jié)中顯式包含幾個字節(jié)的數(shù)據(jù)
每一個關(guān)鍵字后面都跟上一個圓括號中的要存入的值。表達(dá)式的值被存在當(dāng)前的定位計(jì)數(shù)器的值處。
‘BYTE’,‘SHORT’,‘LONG’‘QUAD’命令分別存儲一個,兩個,四個,八個字節(jié)。存入字節(jié)后,定位計(jì)
數(shù)器的值加上被存入的字節(jié)數(shù)。
比如,下面的命令會存入一字節(jié)的內(nèi)容1,后面跟上四字節(jié),其內(nèi)容是符號'addr'的值。
BYTE(1)
LONG(addr)
當(dāng)使用64位系統(tǒng)時(shí),‘QUAD’和‘SQUAD’是相同的;它們都會存儲8字節(jié),或者說是64位的值。而如果軟硬件
系統(tǒng)都是32位的,一個表達(dá)式就會被作為32位計(jì)算。在這種情況下,‘QUAD’存儲一個32位值,并把它零擴(kuò)展
到64位, 而‘SQUAD’會把32位值符號擴(kuò)展到64位。
如果輸出文件的目標(biāo)文件格式有一個顯式的endianness,它在正常的情況下,值就會被以這種endianness存儲
當(dāng)一個目標(biāo)文件格式?jīng)]有一個顯式的endianness時(shí), 值就會被以第一個輸入目標(biāo)文件的endianness存儲。
注意, 這些命令只在一個節(jié)描述內(nèi)部才有效,而不是在它們之間, 所以,下面的代碼會使連接器產(chǎn)生一個錯
誤信息:
SECTIONS { .text : { *(.text) } LONG(1) .data : { *(.data) } }
而這個才是有效的:
SECTIONS { .text : { *(.text) ; LONG(1) } .data : { *(.data) } }
你可能使用‘FILL’命令來為當(dāng)前節(jié)設(shè)置填充樣式。它后面跟有一個括號中的表達(dá)式。任何未指定的節(jié)內(nèi)內(nèi)存
區(qū)域(比如,因?yàn)檩斎牍?jié)的對齊要求而造成的裂縫)會以這個表達(dá)式的值進(jìn)行填充。一個'FILL'語句會覆蓋到
它本身在節(jié)定義中出現(xiàn)的位置后面的所有內(nèi)存區(qū)域;通過引入多個‘FILL’語句,你可以在輸出節(jié)的不同位置
擁有不同的填充樣式。
這個例子顯示如何在未被指定的內(nèi)存區(qū)域填充'0x90':
FILL(0x90909090)
‘FILL’命令跟輸出節(jié)的‘=FILLEXP’屬性相似,但它只影響到節(jié)內(nèi)跟在‘FILL’命令后面的部分,而不是
整個節(jié)。如果兩個都用到了,那‘FILL’命令優(yōu)先。
輸出節(jié)關(guān)鍵字
-----------------------
有兩個關(guān)鍵字作為輸出節(jié)命令的形式出現(xiàn)。
`CREATE_OBJECT_SYMBOLS'
這個命令告訴連接器為每一個輸入文件創(chuàng)建一個符號。而符號的名字正好就是相關(guān)輸入文件的名字。
而每一個符號的節(jié)就是`CREATE_OBJECT_SYMBOLS'命令出現(xiàn)的那個節(jié)。
這個命令一直是a.out目標(biāo)文件格式特有的。 它一般不為其它的目標(biāo)文件格式所使用。
`CONSTRUCTORS'
當(dāng)使用a.out目標(biāo)文件格式進(jìn)行連接的時(shí)候, 連接器使用一組不常用的結(jié)構(gòu)以支持C++的全局構(gòu)造函
數(shù)和析構(gòu)函數(shù)。當(dāng)連接不支持專有節(jié)的目標(biāo)文件格式時(shí), 比如ECOFF和XCOFF,連接器會自動辯識C++
全局構(gòu)造函數(shù)和析構(gòu)函數(shù)的名字。對于這些目標(biāo)文件格式,‘CONSTRUCTORS’命令告訴連接器把構(gòu)造
函數(shù)信息放到‘CONSTRUCTORS’命令出現(xiàn)的那個輸出節(jié)中。對于其它目標(biāo)文件格式,‘CONSTRUCTORS’
命令被忽略。
符號`__CTOR_LIST__'標(biāo)識全局構(gòu)造函數(shù)的開始,而符號`__DTOR_LIST'標(biāo)識結(jié)束。這個列表的第一個
WORD是入口的數(shù)量,緊跟在后面的是每一個構(gòu)造函數(shù)和析構(gòu)函數(shù)的地址,再然后是一個零WORD。編譯
器必須安排如何實(shí)際運(yùn)行代碼。對于這些目標(biāo)文件格式,GNU C++通常從一個`__main'子程序中調(diào)用
構(gòu)造函數(shù),而對`__main'的調(diào)用自動被插入到`main'的啟動代碼中。GNU C++通常使用'atexit'運(yùn)行
析構(gòu)函數(shù),或者直接從函數(shù)'exit'中運(yùn)行。
對于像‘COFF’或‘ELF’這樣支持專有節(jié)名的目標(biāo)文件格式,GNU C++通常會把全局構(gòu)造函數(shù)與析構(gòu)
函數(shù)的地址值放到'.ctors'和'.dtors'節(jié)中。把下面的代碼序列放到你的連接腳本中去,這樣會構(gòu)建
出GNU C++運(yùn)行時(shí)代碼希望見到的表類型。
__CTOR_LIST__ = .;
LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2)
*(.ctors)
LONG(0)
__CTOR_END__ = .;
__DTOR_LIST__ = .;
LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2)
*(.dtors)
LONG(0)
__DTOR_END__ = .;
如果你正使用GNU C++支持來進(jìn)行優(yōu)先初始化,那它提供一些可以控制全局構(gòu)造函數(shù)運(yùn)行順序的功能,
你必須在連接時(shí)給構(gòu)造函數(shù)排好序以保證它們以正確的順序被執(zhí)行。當(dāng)使用'CONSTRUCTORS'命令時(shí),
替代為`SORT(CONSTRUCTORS)'。當(dāng)使用'.ctors'和'dtors'節(jié)時(shí),使用`*(SORT(.ctors))'和
`*(SORT(.dtors))' 而不是`*(.ctors)'和`*(.dtors)'。
通常,編譯器和連接器會自動處理這些事情,并且你不必親自關(guān)心這些事情。但是,當(dāng)你正在使用
C++,并自己編寫連接腳本時(shí),你可能就要考慮這些事情了。
輸出節(jié)的丟棄。
-------------------------
連接器不會創(chuàng)建那些不含有任何內(nèi)容的輸出節(jié)。這是為了引用那些可能出現(xiàn)或不出現(xiàn)在任何輸入文件中的輸入
節(jié)時(shí)方便。比如:
.foo { *(.foo) }
如果至少在一個輸入文件中有'.foo'節(jié),它才會在輸出文件中創(chuàng)建一個'.foo'節(jié)
如果你使用了其它的而不是一個輸入節(jié)描述作為一個輸出節(jié)命令,比如一個符號賦值,那這個輸出節(jié)總是被
創(chuàng)建,即使沒有匹配的輸入節(jié)也會被創(chuàng)建。
一個特殊的輸出節(jié)名`/DISCARD/'可以被用來丟棄輸入節(jié)。任何被分配到名為`/DISCARD/'的輸出節(jié)中的輸入
節(jié)不包含在輸出文件中。
輸出節(jié)屬性
-------------------------
上面,我們已經(jīng)展示了一個完整的輸出節(jié)描述,看下去就象這樣:
SECTION [ADDRESS] [(TYPE)] : [AT(LMA)]
{
OUTPUT-SECTION-COMMAND
OUTPUT-SECTION-COMMAND
...
} [>REGION] [AT>LMA_REGION] [:PHDR :PHDR ...] [=FILLEXP]
我們已經(jīng)介紹了SECTION, ADDRESS, 和OUTPUT-SECTION-COMMAND. 在這一節(jié)中,我們將介紹余下的節(jié)屬性。
輸出節(jié)類型
...................
每一個輸出節(jié)可以有一個類型。類型是一個放在括號中的關(guān)鍵字,已定義的類型如下所示:
`NOLOAD'
這個節(jié)應(yīng)當(dāng)被標(biāo)式詎不可載入,所以當(dāng)程序運(yùn)行時(shí),它不會被載入到內(nèi)存中。
`DSECT'
`COPY'
`INFO'
`OVERLAY'
支持這些類型名只是為了向下兼容,它們很少使用。它們都具有相同的效果:這個節(jié)應(yīng)當(dāng)被標(biāo)式詎不
可分配,所以當(dāng)程序運(yùn)行時(shí),沒有內(nèi)存為這個節(jié)分配。
連接器通?;谟成涞捷敵龉?jié)的輸入節(jié)來設(shè)置輸出節(jié)的屬性。你可以通過使用節(jié)類型來重設(shè)這個屬性,
比如,在下面的腳本例子中,‘ROM’節(jié)被定址在內(nèi)存地址零處,并且在程序運(yùn)行時(shí)不需要被載入。
‘ROM’節(jié)的內(nèi)容會正常出現(xiàn)在連接輸出文件中。
SECTIONS {
ROM 0 (NOLOAD) : { ... }
...
}
輸出節(jié)LMA
..................
每一個節(jié)有一個虛地址(VMA)和一個載入地址(LMA);出現(xiàn)在輸出節(jié)描述中的地址表達(dá)式設(shè)置VMS
連接器通常把LMA跟VMA設(shè)成相等。你可以通過使用‘AT’關(guān)鍵字改變這個。跟在關(guān)鍵字‘AT’后面的表達(dá)式
LMA指定節(jié)的載入地址。或者,通過`AT>LMA_REGION'表達(dá)式, 你可以為節(jié)的載入地址指定一個內(nèi)存區(qū)域。
這個特性是為了便于建立ROM映像而設(shè)計(jì)的。比如,下面的連接腳本創(chuàng)建了三個輸出節(jié):一個叫做‘.text’
從地址‘0x1000’處開始,一個叫‘.mdata’,盡管它的VMA是'0x2000',它會被載入到'.text'節(jié)的后面,最
后一個叫做‘.bss’是用來放置未初始化的數(shù)據(jù)的,其地址從'0x3000'處開始。符號'_data'被定義為值
'0x2000', 它表示定位計(jì)數(shù)器的值是VMA的值,而不是LMA。
SECTIONS
{
.text 0x1000 : { *(.text) _etext = . ; }
.mdata 0x2000 :
AT ( ADDR (.text) + SIZEOF (.text) )
{ _data = . ; *(.data); _edata = . ; }
.bss 0x3000 :
{ _bstart = . ; *(.bss) *(COMMON) ; _bend = . ;}
}
這個連接腳本產(chǎn)生的程序使用的運(yùn)行時(shí)初始化代碼會包含象下面所示的一些東西,以把初始化后的數(shù)據(jù)從ROM
映像中拷貝到它的運(yùn)行時(shí)地址中去。注意這節(jié)代碼是如何利用好連接腳本定義的符號的。
extern char _etext, _data, _edata, _bstart, _bend;
char *src = &_etext;
char *dst = &_data;
/* ROM has data at end of text; copy it. */
while (dst < &_edata) {
*dst++ = *src++;
}
/* Zero bss */
for (dst = &_bstart; dst< &_bend; dst++)
*dst = 0;
輸出節(jié)區(qū)域
.....................
你可以通過使用`>REGION'把一個節(jié)賦給前面已經(jīng)定義的一個內(nèi)存區(qū)域。
這里有一個簡單的例子:
MEMORY { rom : ORIGIN = 0x1000, LENGTH = 0x1000 }
SECTIONS { ROM : { *(.text) } >rom }
輸出節(jié)Phdr
...
|