鏈接腳本(1)

鏈接腳本(1)

分類: 鏈接腳本、Makefile 1126人閱讀 評論(0) 收藏 舉報
1、什麼是ld?它有什麼作用?
 
    ld是GNU binutils工具集中的一個,是衆多Linkers(鏈接器)的一種。完成的功能自然也就是鏈接器的基本功能:把各種目標文件和庫文件鏈接起來,並重定向它們的數據,完成符號解析。Linking其實主要就是完成四個方面的工作:storage allocation、symbol management、libraries、relocation。
 
    ld可以識別一種Linker command Language表示的linker scriopt文件來顯式的控制鏈接的過程。通過BFD(Binary Format Description)庫,ld可以讀取和操作COFF(common object file format)、ELF(executable and linking format)、a.out等各種格式的目標文件。
 
2、常用的選項
 
-b TARGET  設置目標文件的文件格式
-e ADDRESS 設置目標文件的開始地址
-EB  鏈接big-endian的目標文件
-EL  鏈接small-endian的目標文件
-l LIBNAME    創建執行程序時要鏈接的庫文件(比如某個庫爲test,則可以爲-ltest)
-L DIRECTORY  尋找要鏈接的庫文件時搜索的文件路徑
-o FILE  設置輸出文件的名字
-s  去除輸出文件中的所有符號信息
-S  去除輸出文件中的調試符號信息
-T FILE  讀取鏈接描述腳本,以確定符號等的定位地址
-v  輸出ld的版本信息
-x  去除所有的局部符號信息
-X  去除臨時的局部符號信息,默認情況下會設置這個選項
-Bstatic   創建的輸出文件鏈接靜態鏈接庫
-Bdynamic  創建的輸出文件鏈接動態鏈接庫
-Tbss ADDRESS  設置section bss的起始地址
-Tdata ADDRESS 設置section data的起始地址
-Ttext ADDRESS 設置section text的起始地址
 
3、鏈接描述腳本
 
    鏈接描述腳本描述了各個輸入文件的各個section如何映射到輸出文件的各section中,並控制輸出文件中section和符號的內存佈局。
 
    目標文件中每個section都有名字和大小,而且可以標識爲loadable(表示該section可以加載到內存中)、allocatable(表示必須爲這個section開闢一塊空間,但是沒有實際內容下載到這裏)。如果不是loadable或者allocatable,則一般含有調試信息。
 
    每個有loadable或allocatable標識的輸出section有兩種地址,一種是VMA(Virtual Memory Address),這種地址是輸出文件運行時section的運行地址;一種是LMA(Load Memory Address),這種地址是加載輸出文件時section的加載地址。一般,這兩種地址相同。但在嵌入式系統中,經常存在執行地址和加載地址不一致的情況。如把輸出文件加載到開發板的flash存儲器中(地址由LMA指定),但運行時,要把flash存儲器中的輸出文件複製到SDRAM中運行(地址有 VMA指定)。
在鏈接腳本中使用註釋,可以用“/*...*/”。
 
    每個目標文件有許多符號,每個符號有一個名字和一個地址,一個符號可以是定義的,也可以是未定義的。對於普通符號,需要一個特殊的標識,因爲在目標文件中,普通符號沒有一個特定的輸入section。鏈接器會把普通符號處理成好像它們都在一個叫做COMMON的section中。
下面給出vivi的ld script的內容及分析。
(1)[Makefile]
 

LINKFLAGS = -Tarch/vivi.lds -Bstatic

 
    可見,鏈接的腳本是arch/vivi.lds,而且鏈接靜態庫。但是在arch下沒有vivi.lds,而是有vivi.lds.in。看了一下vivi.lds.in的內容,
 

SECTIONS {
  . = TEXTADDR;
  .text : { *(.text) }
  .data ALIGN(4) : { *(.data) }
  .bss ALIGN(4) : { *(.bss) *(COMMON) }
}

 
    很明顯,這個就是原始的vivi的鏈接腳本。但是存在一個變量TEXTADDR沒有賦值,也就是說,這個量根據配置的不同是不同的,所以肯定就在Makefile中執行了生成方法。下一步就要看[arch/Makefile]
 
(2)[arch/Makefile]
 

LDSCRIPT = arch/vivi.lds.in

 

ifeq ($(CONFIG_ARCH_S3C2410),y)
MACHINE = s3c2410
  ifeq ($(CONFIG_S3C2410_NAND_BOOT),y)
    TEXTADDR = 0x33f00000
  else
    TEXTADDR = 0x00000000
  endif
endif

 

vivi: $(HEAD) arch/vivi.lds

arch/vivi.lds: $(LDSCRIPT)
        @sed s/TEXTADDR/$(TEXTADDR)/ $(LDSCRIPT) >$@

 
    很明顯,這步主要完成的工作就是要把vivi.lds.in文件中的TEXTADDR用配置後的實際值來代替。根據我的配置,這裏我的TEXTADDR就是0x33f00000.
 
 

SECTIONS {
  . = 0x33f00000;
  .text : { *(.text) }
  .data ALIGN(4) : { *(.data) }
  .bss ALIGN(4) : { *(.bss) *(COMMON) }
}

    SECTIONS表示段。第一行表示當前地址爲0x33f00000,就是VMA,同時也是text段的起始地址。第二行用了通配符*表示所有字符,這裏的意思就是說指定的每個目標文件的text section的內容都放到同一個.text中。第三行表示指定的每個目標文件的data section的內容都放到同一個.data中,而且要四字節邊界對齊。第四行表示指定的每個目標文件的bss section的內容都放到同一個.bss中,所有的普通符號都放到COMMON中,而且要四字節邊界對齊。

    這算是最爲簡單的ld scripts,不過也夠用了。如果不考慮對齊等因素,則可以直接在命令行中指定-Ttext 0x33f00000,就可以完成了。當然,對Linux kernel等,ld scripts要處理複雜的內存分配等操作,相應的要複雜一些,讀那些的方法就是查閱using ld手冊,同時還要研究MCU的內存分配,這樣才能作出合理的安排



發佈了15 篇原創文章 · 獲贊 15 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章