記錄自己所學的點點滴滴O(∩_∩)O哈哈~
makefile:
link.bin: start.o main.o
arm-linux-ld -Tlink.lds -o link.elf $^
arm-linux-objcopy -O binary link.elf link.bin
arm-linux-objdump -D link.elf > link_elf.dis
gcc mkv210_image.c -o mkmini210
./mkmini210 link.bin 210.bin
%.o : %.S
arm-linux-gcc -o $@ $< -c
%.o : %.c
arm-linux-gcc -o $@ $< -c
clean:
rm *.o *.elf *.bin *.dis mkmini210 -f
解釋:
ld:
GNU的鏈接器.
用來把一定量的目標文件跟檔案文件鏈接在一起,並重新定位它們的數據,鏈接符號引用.
一般編譯一個程序時,最后一步就是運行ld進行鏈接
每一個鏈接都被一個鏈接腳本所控制,這個腳本是用鏈接命令語言書寫的.
二、鏈接腳本
鏈接腳本的一個主要目的是描述輸入文件中的各個段(數據段,代碼段,堆,棧,bss)如何被映射到輸出文件中,並控制輸出文件的內存排布.
鏈接器總是使用鏈接腳本的,如果你不提供,則鏈接器會使用一個缺省的腳本,這個腳本是被編譯進鏈接器可執行文件的.
可以使用--verbose命令行顯示缺省的鏈接器腳本的內容.
你可以使用-T命令行來提供你自己的鏈接腳本來替換缺省的鏈接腳本.
三、簡單的鏈接腳本示例.
許多腳本是相當簡單的.
可能最簡單的腳本只含有一個命令:’SECTIONS’.
你可以使用’SECTIONS’來描述輸出文件的內存布局.
‘SECTIONS’是一個功能很強大的命令.
假設你的程序只有代碼段,初始化過的數據段,和未初始化過的數據段.這些會存在於’.text’,’data’,’bss’段中.
對於這個例子,假設代碼應該被載入到地址0x1000處,而數據應該從0x8000000開始,如下是實現這個功能的腳本:
SECTIONS
{
.=0x1000;
.text:{*(.text)}
.=0x8000000;
.data:{*(.data)}
.bss:{*(.bss)}
}
具體分析:
關鍵字’SECTIONS’開始於這個配置.后面跟有一串放在花括號中的符號賦值和輸出端描述的內容.
第一行是對一個特殊的符號’.’賦值,這是一個定位標識器.如果你沒有以其他的方式制定輸出段的地址,那地址值就會被設為定位標識器的現有值,即0x1000.
第二行定義一個輸出段,’.text’.冒號’:’是語法需要,現在可以被忽略.段后面的花括號中,應該列出所有應該放入這個輸出段中的輸入端的名字.’*’是通配符,匹配所有文件名.即將所有輸入文件中的.text段都保存在此段中.
余下的是.data和.bss段,同理,鏈接器會把所有.data段從地址0x8000000開始處放置.
最后,定位標識器的值變為0x8000000加上所有.data段的地址.此時鏈接器把所有.bss放在此處開始的地址.
四、簡單的鏈接腳本命令
設置入口點
在運行一個程序時,第一個被執行到的指令成為”入口點”.你可以使用”ENTRY”鏈接腳本命令來設置入口點.參數是一個符號名,如下:
ENTRY(SYMBOL)
有很多不同的方法來設置入口點.鏈接器會通過按順序嘗試一下方法來設置入口點,如果成功了,就會停止.
1,’-e’ 入口命令行選項
2,鏈接腳本中的ENTRY(SYMBOL)命令
3,如果定義了start,就使用start的值
4,如果存在就使用’.text’段的首地址
5,地址’0’
五、命令行設置鏈接地址
ld用於將多個obj或者so(庫)文件鏈接成可執行文件.
使用-T選項可以指定數據段,代碼段,bss段起始位置.(-T只用於鏈接bootloader、內核等沒有底層軟件支持的軟件.鏈接運行於操作系統之上的應用程序時,一般使用默認方式鏈接).
1,直接指定代碼段、數據段、bss段起始地址
如下:
-Ttext startaddr
-Tdata startaddr
-Tbss startaddr
例如:
ld –Ttext 0x00000000 –g led_on.o –o led_on_elf
2,直接使用鏈接腳本來設置起始地址
ld –Ttimer.lds –o timer_elf a.o b.o
鏈接腳本timer.lds內容如下:
SECTIONS{
.=0x30000000;
.text : {*(.text)}
.rodata ALIGN(4) : {*(.rodata)}
.data ALIGN(4) : {*(.data)}
.bss ALIGN(4) : {*(.bss) *(COMMON)}
}
一個SECTIONS命令內部包含一個或多個段,段(section)是連接腳本的基本單元,它表示輸入文件中的某部分怎么放置.
完整的鏈接腳本
arm-linux-ld 是連接器,它把一些目標和歸檔文件結合在一起,重定位數據,並連接符號引用。通常,建立一個新編譯程序的最后一步就是調用ld。
arm-linux-gcc -wall -O2 -c -o $@ $<
-o 只激活預處理,編譯,和匯編,也就是他只把程序做成obj文件
-Wall 指定產生全部的警告信息
-O2 編譯器對程序提供的編譯優化選項,在編譯的時候使用該選項,可以使生成的執行文件的執行效率提高
-c 表示只要求編譯器進行編譯,而不要進行鏈接,生成以源文件的文件名命名但把其后綴由 .c 或 .cc 變成 .o 的目標文件
-S 只激活預處理和編譯,就是指把文件編譯成為匯編代碼
arm-linux-ld 直接指定代碼段,數據段,BSS段的起始地址
-Tbss ADDRESS Set address of .bss section
-Tdata ADDRESS Set address of .data section
-Ttext ADDRESS Set address of .text section
示例:
${CROSS}ld -Ttext=0x33000000 led.o -o led.elf
使用連接腳本設置地址:
arm-linux-ld -Tbeep.lds start.o beep.o -o beep.elf
其中beep.lds 為連接腳本如下:
arm-linux-objcopy被用來復制一個目標文件的內容到另一個文件中,可用於不同源文件的之間的格式轉換
示例:
arm-linux-objcopy –o binary –S elf_file bin_file
常用的選項:
input-file , outflie
輸入和輸出文件,如果沒有outfile,則輸出文件名為輸入文件名
2.-l bfdname或—input-target=bfdname
用來指明源文件的格式,bfdname是BFD庫中描述的標准格式名,如果沒指明,則arm-linux-objcopy自己分析
3.-O bfdname 輸出的格式
4.-F bfdname 同時指明源文件,目的文件的格式
5.-R sectionname 從輸出文件中刪除掉所有名為sectionname的段
6.-S 不從源文件中復制重定位信息和符號信息到目標文件中
7.-g 不從源文件中復制調試符號到目標文件中
arm-linux-objdump
查看目標文件(.o文件)和庫文件(.a文件)信息
arm-linux-objdump -D -m arm beep.elf > beep.dis
-D 顯示文件中所有匯編信息
-m machine