CodeWarrior的map文件詳解

版權聲明:本文爲博主(http://blog.csdn.net/lin_strong)原創文章,轉載請標明出處並事先取得博主同意 https://blog.csdn.net/lin_strong/article/details/79759080

最近各種忙着碼代碼,遇到了各種各樣的坑,對CodeWarrior工程中的這個map文件的理解也越來越深了。閒來無事,和大家分享下對這個map文件的理解。可能還有不對之處,敬請指出。


前言

map文件保存了你的整個程序編譯鏈接後的各種信息,包括編譯器鏈接器信息,內存分配信息,對象依賴等,每次編譯鏈接程序後,這個文件都會被覆蓋重新生成。
對我來說,它最主要的作用是它詳盡的描述了整個程序最終在內存中的分佈情況,有助於我們工程師完全掌控每一個對象(函數/變量/常量/棧……),以及對象間的相互關係,加深對編譯鏈接過程的理解。
其內容爲文本形式,可以使用任意文本編輯器打開查看。

文件解釋

就隨便拿個最近在寫的程序作爲例子。默認的map文件名如上爲Project.map。

打開後最上面 PROGRAM後跟着是項目abs文件的地址信息。

TARGET SECTION(編譯目標)

裏頭列出了使用的處理器,鏈接器文件格式(ELF),使用的鏈接器的版本(CodeWarrior默認使用的是SmartLinker),地址模型。
地址模型主要分爲:SMALL、BANKED、LARGE。差別主要是其默認的地址分配和尋址方式不同,想要詳細瞭解的話可以參考https://blog.csdn.net/lin_strong/article/details/78127072 裏的相關介紹。

FILE SECTION(文件清單)

裏頭列舉了用到的.o 文件,因爲map是鏈接器生成的說明文件,對鏈接器來說它直接使用的是已經編譯過的ELF格式的.o文件而不是最初的源代碼.c文件。
三列分別是:文件名, 此文件用到的地址模型, 使用的語言(如:C語言:ANSI-C;彙編:Assembler)。


STARTUP SECTION

描述了程序啓動相關的函數和變量:

起始地址(Entry point)是程序的啓動入口,這裏是_Startup函數,在Start12.c中,是工程自動創建的,在其中會完成程序啓動前的一系列初始化工作,然後纔會跳轉到我們熟知的C語言入口main函數。
而_startupData這個初始化用的結構體則保存了初始化時用到的一些參數:
nofZeroOut描述了後面數組的大小,如這裏可以看出pZeroOut指向的三個區域;
pZeroOut指向的區域會在初始化時被全部初始化爲0,對應於C語言中的全局變量,觀察下一個區塊就可以看出他們之間的聯繫。
toCopyDownBeg則保留着要初始化的RAM變量的初始化值,它們保存在非易失內存中。在_Startup中會把初始值拷貝到對應的變量處完成初始化。

  • 注:這裏蠻提一個坑。可以看到第二個要清零的地址是24bit的,因爲它們是放在分頁區的向量,而在banked地址模型中默認的這個地址指針是16位的,所以要是直接編譯的話就會看到0xF01000這個值變成了0x1000,那就變成從0x1000這個地址開始清零3204個字節了;因此如果使用了分頁區的RAM的話要記得在編譯器中添加-D__FAR_DATA選項,這樣指針就會變成24bit的了。

SECTION-ALLOCATION SECTION(區塊分配)

描述了每個數據段的名字、大小、類型(R只讀、N/I不初始化、R/W可讀寫)、在存儲器中的起始和結束地址、以及對應的分區(segment)。

我們可以看到.data、.bss和.common被連續分配到了RAM這個名字的分區中,對應這pZeroOut的第一個指針,在這幾個段內的變量對應C語言中的全局變量。而PAGED_RAM被分配到了RAM_F0中,RAM_F1_744對應RAM_F1,分別對應pZeroOut的另兩個指針,它們中是被分配到分頁RAM中的全局變量。
.stack則是棧的位置,上例中從0x2006到0x2105,大小爲256字節。
.abs_section_XXXX是編譯器自動生成的段名,對應着程序中使用@直接定位地址的變量。
如:.abs_section_8對應的是MC9S12XEP100.h中的這一行

extern volatile PORTESTR _PORTE @(REG_BASE + 0x00000008UL);

這個塊的最後我們可以看到一個summary,裏頭總結了各種類型的數據段實際佔用的內存大小。

注:

代碼量的計算並不是根據你文件編譯出來的大小來確定的,鏈接器並不會鏈接那些沒有用到的對象(除非用了某些語法強制進行鏈接),這些沒用到的對象是不計入代碼量的。所以程序實際上的大小並沒有你在第一個圖中看到的那個數字那麼大。CodeWarrior 的試用版對代碼量有限制指的就是這個最終的代碼量。換句話說,不管你加再多代碼,再多庫到項目中;只要你不去用它們,一點代碼量都不會增加。

VECTOR-ALLOCATION SECTION(中斷向量分配)

描述了復位向量地址、初始值、以及具體的ISR函數名。
由於我這個工程內直接使用的向量表,而不是在prm文件中使用VECTOR 0 _Startup這樣來定義ISR的,所以這邊沒有列出。


OBJECT-ALLOCATION SECTION (對象分配)

這個部分直接按照模塊(C語言中就是不同的.c文件)把程序中的具體對象的詳細信息列出。
包括對象的名字、所處模塊、所在地址、十六進制表示的大小(hSize)、十進制表示的大小(dSize)、被引用次數、所在的段名。如果使用了reloacate把Flash上的程序重分配到了RAM中,還會跟上對應在新地址中的地址。

我們可以看到第一個對象就是剛剛舉的那個地址在0x8處的變量的例子。其實際名字叫_PORTE,大小爲1個字節,程序中沒有任何地方直接使用到這個變量,但是因爲他使用的是絕對定位,並沒有被編譯器優化掉。

同樣的,地址如果是24bit的則說明使用了分頁地址,16bit的說明使用的本地地址。

MODULE STATISTIC(模塊統計)

列出不同模塊的統計信息,包括 變量、代碼、常量 的個數。

SECTION USE IN OBJECT-ALLOCATION SECTION

列出每個區塊中分配的對象。

OBJECT LIST SORTED BY ADDRESS(地址順序的對象清單)

類似OBJECT-ALLOCATION SECTION,但是是按地址升序排列的,方便按地址查找。

UNUSED-OBJECTS SECTION(未使用對象)

列出不同模塊中未使用的對象。這些對象不會佔用實際內存。

COPYDOWN SECTION

變量初始化相關信息。

OBJECT-DEPENDENCIES SECTION (對象依賴表)

列出每個對象依賴於(或說引用了)哪些對象。

DEPENDENCY TREE(依賴樹狀圖)

用樹狀圖的方式形象的表示出來對象間的相互依賴關係。

注:

一個對象每被另一個對象依賴,它在OBJECT-ALLOCATION SECTION中的Ref計數就會加1。然後你比如就可以到這個樹狀體中查找到底它是被哪個對象使用了。

STATISTIC SECTION

一些統計信息

結語

以上就是對整個map文件的介紹。熟悉map文件,可以使我們更好的掌控自己的程序,快速定位各種問題,良好地分配有限的MCU內存資源。希望這篇文章可以對各位朋友有一定的幫助。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章