前言
想讀懂uboot的鏈接腳本,以及瞭解鏈接腳本的使用方法,需要掌握以下基本知識。
1、gcc程序段介紹
一個可執行程序主要包含text段(代碼),data段(初始化的全局變量),以及bss段(未初始化的全局變量)。局部變量是在運行過程中分配的,不佔用可執行程序的大小。下面舉一個例子說明
#include <stdio.h>
#include <string.h>
int a = 0; //全局未初始化變量,系統默認賦值成0,bss段,4個字節
int b = 5, c = 6; //全局已初始化變量, data段,8個字節
int main()
{
int i = 0; //局部變量
i++;
a++;
printf("i = %d, a = %d\n", i, a);
return 0;
}
將上面代碼保存成main.c,並將其編譯成.o文件:arm-fsl-linux-gnueabi-gcc -c main.c
,-c參數說明只進行編譯不進行鏈接。然後使用以下命令查看各種段的大小
root@silent:/home/lianxi/test# arm-fsl-linux-gnueabi-size main.o
text data bss dec hex filename
120 8 4 132 84 main.o
root@silent:/home/lianxi/test#
可以看到代碼段大小120個字節,data段大小8個字節(變量b和c的大小),bss段的大小4個字節(變量a的大小),可執行程序的總大小爲120+8+4=132。局部變量i,是在代碼運行的時候分配的,不影響bin文件的大小!
2、鏈接腳本的使用
爲了說明uboot的編譯及鏈接過程,這裏寫兩個簡單的彙編源文件,然後使用自己寫的鏈接腳本將它們鏈接起來。兩個源文件分別是mystart.s,mylowlevel_init.s,鏈接腳本是myboot.lds,其內容及註釋如下。
mystart.s彙編文件內容如下:
b reset
b reset
b reset
b reset
b reset
b reset
b reset
b reset
reset:
mov r0, r1
bl mytest /*在另一個文件中定義*/
mov r1, r2
mov r2, r3
mov r3, r4
loop:
b loop
mylowlevel_init.s彙編文件內容如下:
.global mytest
mytest:
mov r0, r1
mov r1, r2
mov pc, lr
myboot.lds鏈接腳本內容如下:
SECTIONS
{
/********************************************
*編譯地址從0地址開始,
*這個地址可以使用連接器的-Ttext參數重新修改,
*在uboot裏面是重新定位到了TEXT_BASE這個內存地址。
********************************************/
. = 0x00000000;
/******************************************
*代碼段,把mystart.o放在最前面,其他.o的順序
*不管,使用* (.text)通配!
******************************************/
.text : {
mystart.o
* (.text)
}
/*****************************************
*已經初始化的全局變量
******************************************
.data : {
* (.data)
}
/****************************************
*未初始化全局變量,這裏放兩個標號bss_start
*和bss_end,在程序中可以引用,比如可以用來
*計算整個二進制文件的大小。
****************************************/
.bss_start = .;
.bss : {
* (.bss)
}
.bss_end = .;
}
然後使用如下命令就可以對以上兩個源文件進行編譯和鏈接:
root@silent:/home/lianxi/uboot_lds# arm-fsl-linux-gnueabi-gcc -c mystart.s
root@silent:/home/lianxi/uboot_lds# arm-fsl-linux-gnueabi-gcc -c mylowlevel_init.s
root@silent:/home/lianxi/uboot_lds# arm-fsl-linux-gnueabi-ld -Tmyboot.lds -o myboot mylowlevel_init.o mystart.o //使用鏈接腳本進行鏈接
root@silent:/home/lianxi/uboot_lds# ls
myboot myboot.bin myboot.lds mylowlevel_init.o mylowlevel_init.s mystart.o mystart.s
root@silent:/home/lianxi/uboot_lds#
鏈接完成後生成myboot文件,該文件格式爲ELF,需要使用如下命令將其轉換成bin文件
arm-fsl-linux-gnueabi-objcopy -O binary myboot myboot.bin
可以使用hexdump命令查看myboot.bin和其他.o文件的內容,如:hexdump -C myboot.bin
,對比鏈接前後的差異。如果想在開發板上跑起來,還需要根據具體的cpu,將myboot.bin製作成相應的格式(一般在前面加個一個頭),cpu的類型千千萬萬種,這裏不說了,具體格式應該查看該cpu的datasheet。