uboot.lds链接脚本分析
?LDFLAGS += -Bstatic -T /board/smdk2410/u-boot.lds -Ttext 0x33F80000中-Ttext 0x33F80000是指定代碼段text的首地址是0x33F80000
1、鏈接腳本格式
<SECTIONS>基本命令
SECTIONS?描述輸出文件的映射圖:?->?輸出文件各段、各文件怎么放置
一個SECTIONS命令內部包含一個或多個段,段是連接腳本的基本單元,它?表示輸入文件某部分怎么放置;
格式:
SECTIONS{
? ...
secname start ALIGN(align)(NOLOAD):AT(ldadr)
{contents}>region:phdr=fill
...
}
secname:命名這個段??
contents:用來確定代碼的什么部分放在這個段
start:是這個段的重定位地址,也叫運行地址。如果代碼中有位置無關的?指令,程序在運行時必須放在這個地址上。
ALIGN(align):雖然指定了運行地址,但仍可以使用ALIGN(align)來指定?對齊的要求---這個對齊的地址才是真正的地址
(NOLOAD):來告訴加載器,在運行時不用加載這個段
AT(ldadr):指定這個段在編譯出來的映像文件中的地址——加載地址
2、程序分析
OUTPUT_FORMAT("elf32-littlearm",?"elf32-littlearm",?"elf32-littlearm")
/*指定輸出可執行文件是elf格式,32位ARM指令,小端*/
OUTPUT_ARCH(arm)
/*指定輸出可執行文件的平臺為ARM*/
ENTRY(_start)
/*指定輸出可執行文件的起始代碼段為_start*/
SECTIONS
{
/*指定可執行image文件的全局入口點,通常這個地址都放在ROM(flash)0x0位置。必須使編譯器知道這個地址,通常都是修改此處來完成*/
?.?=?0x00000000;/*;從0x0位置開始*/
?.?=?ALIGN(4);/*代碼以4字節對齊*/
?.text?:
?{
??cpu/arm920t/start.o?(.text)?
?? ?/*代碼的第一個代碼部分*/??
??*(.text)
??/*下面依次為各個text段函數*/
?}
?.?=?ALIGN(4);
/*代碼以4字節對齊*/
?.rodata?:?{?*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))?}
?/*指定只讀數據段*/
?.?=?ALIGN(4);
/*代碼以4字節對齊*/
?.data?:?{?*(.data)?}
?.?=?ALIGN(4);
/*代碼以4字節對齊*/
?.got?:?{?*(.got)?}
/*指定got段, got段是uboot自定義的一個段,?非標準段*/
?.?=?.;
?__u_boot_cmd_start?=?.;
/*把__u_boot_cmd_start賦值為當前位置,?即起始位置*/
?.u_boot_cmd?:?{?*(.u_boot_cmd)?}
?/*指定u_boot_cmd段, uboot把所有的uboot命令放在該段.*/
?__u_boot_cmd_end?=?.;
?/*把__u_boot_cmd_end賦值為當前位置,即結束位置*/
?.?=?ALIGN(4);
/*代碼以4字節對齊*/
?__bss_start?=?.;
?/*把__bss_start賦值為當前位置,即bss段的開始位置*/
?.bss?(NOLOAD)?:?{?*(.bss)?.?=?ALIGN(4);?}
/*指定bss段,告訴加載器不要加載這個段*/
?__bss_end?=?.;
/*把_end賦值為當前位置,即bss段的結束位置*/
}
3、查看反匯編文件
看完上面的解析思路本來應該是很清晰的,于是乎編譯u-boot,查看一下System.map,
30100000 T _start
30100020 t _undefined_instruction
30100024 t _software_interrupt
30100028 t _prefetch_abort
3010002c?t _data_abort
30100030 t _not_used
30100034 t _irq
30100038 t _fiq
發現?_start?的鏈接地址不是u-boot.lds中.text?的當前地址0x00000000,而是0x30100000,這就產生很多疑問了:
(1)?????為什么u-boot.lds指定的?.text?的首地址不起作用?
(2)?????0x30100000是什么地址,由誰指定.text的首地址是0x30100000的呢?
(3)?????假如有其他動作改變了?.text?的首地址,那么該動作跟u-boot.lds的優先級又是怎么決定的呢?
其實這三個問題都在Makefile的LDFLAGS?變量和u-boot.lds?中找到答案。
4、修改u-boot.lds
我們不妨試著修改一下u-boot.lds,把u-boot.lds修改成如下(紅色字體部分為修改過部分):
OUTPUT_FORMAT("elf32-littlearm",?"elf32-littlearm",?"elf32-littlearm")
/*指定輸出可執行文件是elf格式,32位ARM指令,小端*/
OUTPUT_ARCH(arm)
/*指定輸出可執行文件的平臺為ARM*/
ENTRY(_start)
/*指定輸出可執行文件的起始代碼段為_start*/
SECTIONS
{
/*指定可執行image文件的全局入口點,通常這個地址都放在ROM(flash)0x0位置。必須使編譯器知道這個地址,通常都是修改此處來完成*/
?.?=?0x30000000;/*;從0x0位置開始*/
?.?=?ALIGN(4);/*代碼以4字節對齊*/
.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
?.?=?ALIGN(4);
/*代碼以4字節對齊*/
?.text :
?{
??cpu/arm920t/start.o (.text)?
?? ?/*代碼的第一個代碼部分*/??
??*(.text)
??/*下面依次為各個text段函數*/
?}?
?/*指定只讀數據段*/
?.?=?ALIGN(4);
/*代碼以4字節對齊*/
?.data?:?{?*(.data)?}
?.?=?ALIGN(4);
/*代碼以4字節對齊*/
?.got?:?{?*(.got)?}
/*指定got段, got段是uboot自定義的一個段,?非標準段*/
?.?=?.;
?__u_boot_cmd_start?=?.;
/*把__u_boot_cmd_start賦值為當前位置,?即起始位置*/
?.u_boot_cmd?:?{?*(.u_boot_cmd)?}
?/*指定u_boot_cmd段, uboot把所有的uboot命令放在該段.*/
?__u_boot_cmd_end?=?.;
?/*把__u_boot_cmd_end賦值為當前位置,即結束位置*/
?.?=?ALIGN(4);
/*代碼以4字節對齊*/
?__bss_start?=?.;
?/*把__bss_start賦值為當前位置,即bss段的開始位置*/
?.bss?(NOLOAD)?:?{?*(.bss)?.?=?ALIGN(4);?}
/*指定bss段,告訴加載器不要加載這個段*/
?__bss_end?=?.;
/*把_end賦值為當前位置,即bss段的結束位置*/
}
上面對u-boot.lds主要做了兩點修改
(1)?????把0x00000000?改成?0x30000000。
(2)?????把?.text?和?.rodata?存放的地址調換了位置。
5、反匯編文件重查
重新編譯?u-boot,?查看System.map
30000000 R version_string
30000028 r C.27.2365
.
.
.
30100000 T _start
30100020 t _undefined_instruction
.
.
.6、 歸納
從上面的System.map部分內容可以看出:
(1)?????u-boot.lds設定的地址(0x00000000或0x30000000)是有效的。
(2)?????.text的地址仍然是30100000
跟著我們查看Makefile中的LDFLAGS變量,發現一條指令
LDFLAGS += -Ttext $(TEXT_BASE)??其中TEXT_BASE?是在u-boot根目錄的board文件夾的對應的開發板名字的子目錄下的config.mk文件中定義的
TEXT_BASE = 0x30100000
看到這里我們應該明白為什么_start,也就是.text的首地址總是等于0x30100000了,在連接的時候ld命令會把參數-Ttext指定的地址賦給.text,所以.text在u-boot.lds中的默認地址(當前地址)不起作用了。
總結
以上是生活随笔為你收集整理的uboot.lds链接脚本分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Mamba Blog 博客小程序版
- 下一篇: 360极速浏览器去广告优化版 v13.0