正在學習嵌入式linux開發,求推薦詳細介紹makefile和鏈接腳本語法相關的書籍或者資料。?
另外,求大神們指點一下鏈接腳本內的段地址是怎麼傳給c語言的,比如uboot中cmd段的段地址是在鏈接腳本定義的,它是怎麼傳給c語言的?
【學Makefile】
看這個:GNU make這個僅需要一定的腳本基礎,但非正相關。可以以這個為基礎學習其他擴展知識【學ld script】
看這個:Using LD, the GNU linker
這個需要一定的ELF和彙編基礎,但非正相關。可以以這個為基礎學習其他擴展知識【段地址傳遞給C語言】
這個涉及很多基礎知識,先為你建立一個基本的邏輯,其他細節,自己去找資料。首先,一個C程序變成一個可執行程序,需要經過兩個步驟,首先是編譯(CC),然後是鏈接(LD)。前者把一個獨立的C文件翻譯為.o文件,後者把多個.o文件關聯在一起,形成一個完整的程序。
CC是把用C語言描述的程序翻譯成指令和數據,放到section中,數據放到一個section中很簡單,但翻譯指令這個是缺信息的,因為如果你要使用一個地址(變數或者函數都行)的時候,這個地址是多少?這取決於你把這段程序放在什麼地方,也取決於其他section放在什麼地方(當你索引的符號在本section之外)。
CC用兩種方法解決這個問題,一種是使用相對地址,函數foo1調foo2,如果兩個函數在同一個section中,只要調用一個相對當前地址多大距離的地址即可。這種情況CC自己就可以解決。
第二種是要使用其他section(本.o或者其他.o的不同段都是如此)的符號,CC對此沒有任何辦法,在這種位置上,CC只能放置一個所謂「重定位項」,等待ld去完成後續過程。
ld的工作是把所有的.o文件拼裝為一個完整的可執行程序,即把所有.o的位置放到一起,它可以根據需要把多個段拼成一個段,也可以按順序一個段一個段順序排列。這些所有的行為,都可以在ld script中描述,ld script可以制定程序從什麼地址開始,每個段放在什麼地方,哪些合併,哪些獨立排放等等。
ld script還有一個能力,可以定義任意的符號名,從而任意增加符號,並指定這個符號等於多少。
比如,你在你的.c中,說extern void * addr。CC會認為這個地址在其他.o中,它會建立一個重定位項。但你不需要在其他.o中定義它,你完全可以在ldscript中直接定義這個符號名,讓它指向某個section的首地址。這樣,這個索引的地址在ld後,就會被賦予一個地址,訪問這個地址,這個地址就指向需要的section的開頭。
uboot中的section (".u_boot_cmd")就是這樣實現的。你是說ld script,這部分看我寫的開源書籍吧,http://tinylab.org/open-c-book
http://Github.com + http://google.com
從某種程度上說,你這句話是錯誤的。這裡並沒有一個傳遞的過程。僅僅是編譯器在編譯的時候「固化」每一段的地址空間而已。
我忽然理解你的問題了,等我回去補充。-------------------------------------------------------------------------------這裡是分割線-------------------------------------------------------------------------------首先,先上一個典型的cmd參數:setenv bootcmd tftp 50008000 zImage ;bootm 50008000
需要理解的是,這句話的意思是,將一個代碼段放置在內存的50008000中,然後從50008000中執行這段代碼。又或者,有時候,可能會在u-boot中執行以下命令:tftp 50008000 xxx。。。。然後執行go 50008000運行下載到這個地址的代碼段為的是將一個代碼文件下載到內存的某一個區域。我覺得你的懷疑點就是,為什麼要將代碼段下載到這個地址,為什麼下載到其它的地址就不可以。下面,來看一個典型的裸板程序(因為假如是運行在操作系統上的程序,會由操作系統做內存的關係映射,你的疑問應該也就不再存在了)。假設有這樣一個代碼(helloworld.c):void helloworld(){
printf("helloworld");
// 需要注意的是,因為是裸板程序,其實是不能執行printf函數的
// 這裡僅僅是演示,一個類比而已
// 真實的代碼這裡應該指定某些硬體的寄存器地址等
}
假設以上就是一個最基本的嵌入式C語言代碼。和通常的桌面程序有所不同,嵌入式C語言代碼並不要求一定要存在一個main函數,只需要在編譯的時候指定代碼的起始地址就可以了。比如(helloworld.lds):
SECTIONS
{
. = 0x50008000;
.text :
{
helloworld.o (.text);
}
};
這裡就定義了由上面的C語言源文件在做鏈接的時候的代碼段的地址。所以在運行的時候需要從這裡開始運行。
(我說的和你問的是一回事嗎)之前學過編譯原理,所以連接腳本和makefile對於我來說也只是語法問題。看看GNUmake手冊足矣
光看書效果不大,還是從零開始寫一個項目的makefile比較靠譜,寫的過程中遇到什麼問題、技術一步一步學習解決:Makefile工程實踐:從零開始一步一步寫項目的Makefile視頻課程_共21課時_嵌入式_嵌入式Linux_視頻教程在線自學__51CTO學院_專業的IT技能學習平台
《跟我一起寫 Makefile》陳皓
github搜索makefile,多看幾個,不懂再google
網上有一份 左耳朵陳皓翻譯的 一份make的文件,先把那個看了再說
嵌入式前景如何?
推薦How to write makefile,有中英文版,一般都看這本
這個不需要書。
推薦閱讀:
※怎麼看待 Linus 和 Richard Stallman 對 C++ 的態度?
※Linux是否有類似於IIS統一管理網站的工具?
※最逼近Mac OS X的Linux系統有哪些?
※Linux 各個發行版與 OS X 相比哪個寫代碼更舒服?為什麼?
※vmware, visual studio, steam dota2這種需要極大內存的程序是如何分配內存的?