User Tools

Site Tools

prog:codewarrior:20240815-001:index

CodeWarrior的map檔案詳解 (2024-08-15)

前言

  • map檔案保存了你的整個程式編譯連結後的各種信息,包括編譯器連結器信息,記憶體分配信息,物件依賴等,每次編譯連結程式後,這個檔案都會被覆蓋重新生成。
  • 它最主要的作用是它詳盡的描述了整個程式最終在記憶體中的分佈情況,有助於我們工程師完全掌控每一個對象(函數/變數/常數/堆疊…),以及對象間的相互關係,加深對編譯連結過程的理解。
  • 其內容為文字形式,可以使用任意文字編輯器開啟檢視。

文件解釋

  • 就隨便拿個最近在寫的程式作為例子。預設的map檔名如上為Project.map。
  • 開啟後最上面PROGRAM後跟著是專案abs檔的位址資訊。

TARGET SECTION (編譯目標)

  • 裡面列出了使用的處理器,連結器檔案格式(ELF),使用的連結器的版本(CodeWarrior預設使用的是SmartLinker),位址模型。
  • 地址模型主要分為:SMALL、BANKED、LARGE。差異主要是其預設的位址分配和定址方式不同,想要詳細了解的話可以參考

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記憶體資源。希望這篇文章可以對各位朋友有一定的幫助。
Permalink prog/codewarrior/20240815-001/index.txt · Last modified: 2024/08/15 13:43 by jethro

oeffentlich