MDK的編譯過程及文件類型全解——(三)

前言:

爲了方便查看博客,特意申請了一個公衆號,附上二維碼,有興趣的朋友可以關注,和我一起討論學習,一起享受技術,一起成長。

在這裏插入圖片描述


本文轉載自:第48章 MDK的編譯過程及文件類型全解—零死角玩轉STM32-F429系列


1. Listing目錄下的文件

在 Listing 目錄下包含了 .map 及 .lst 文件,它們都是文本格式的,可使用 Windows 的記事本軟件打開。其中 lst 文件僅包含了一些彙編符號的鏈接信息,這裏重點分析 map 文件。

map 文件是由鏈接器生成的,它主要包含交叉鏈接信息,查看該文件可以瞭解工程中各種符號之間的引用以及整個工程的 Code、RO-data、RW-data 以及 ZI-data 的詳細及彙總信息。它的內容中主要包含了"節區的跨文件引用"、“刪除無用節區”、“符號映像表”、“存儲器映像索引"以及"映像組件大小”,各部分介紹如下:

1.1 節區的跨文件引用

打開"多彩流水燈 .map" 文件,可看到它的第一部分——節區的跨文件引用(Section Cross References):

 Section Cross References

 startup_stm32f429_439xx.o(RESET) refers to startup_stm32f429_439xx.o(STACK) for __initial_sp

 startup_stm32f429_439xx.o(RESET) refers to startup_stm32f429_439xx.o(.text) for Reset_Handler

 startup_stm32f429_439xx.o(RESET) refers to stm32f4xx_it.o(i.NMI_Handler) for NMI_Handler

 startup_stm32f429_439xx.o(RESET) refers to stm32f4xx_it.o(i.HardFault_Handler) for HardFault_Handler

 /**...以下部分省略****/


 main.o(i.main) refers to bsp_led.o(i.LED_GPIO_Config) for LED_GPIO_Config

 main.o(i.main) refers to stm32f4xx_gpio.o(i.GPIO_ResetBits) for GPIO_ResetBits

 main.o(i.main) refers to main.o(i.Delay) for Delay

 main.o(i.main) refers to stm32f4xx_gpio.o(i.GPIO_SetBits) for GPIO_SetBits

 bsp_led.o(i.LED_GPIO_Config) refers to stm32f4xx_rcc.o(i.RCC_AHB1PeriphClockCmd) for RCC_AHB1PeriphClockCmd

 bsp_led.o(i.LED_GPIO_Config) refers to stm32f4xx_gpio.o(i.GPIO_Init) for GPIO_Init

 bsp_led.o(i.LED_GPIO_Config) refers to stm32f4xx_gpio.o(i.GPIO_ResetBits) for GPIO_ResetBits

 /**...以下部分省略****/

 ======================================================================

在這部分中,詳細列出了各個 .o 文件之間的符號引用。由於 .o 文件是由 asm 或 c/c++ 源文件編譯後生成的,各個文件及文件內的節區間互相獨立,鏈接器根據它們之間的互相引用鏈接起來,鏈接的詳細信息在這個 "Section Cross References"一一列出。

例如,開頭部分說明的是 startup_stm32f429_439xx.o 文件中的 “RESET” 節區分爲它使用的 “__initial_sp” 符號引用了同文件 “STACK” 節區。

也許我們對啓動文件不熟悉,不清楚這究竟是什麼,那我們繼續瀏覽,可看到main.o 文件的引用說明,如說明 main.o 文件的 i.main 節區爲它使用的LED_GPIO_Config 符號引用了 bsp_led.o 文件的 i.LED_GPIO_Config 節區。

同樣地,下面還有 bsp_led.o 文件的引用說明,如說明了 bsp_led.o 文件的 i.LED_GPIO_Config 節區爲它使用的 GPIO_Init 符號引用了 stm32f4xx_gpio.o 文件的 i.GPIO_Init 節區。

可以瞭解到,這些跨文件引用的符號其實就是源文件中的函數名、變量名。有時在構建工程的時候,編譯器會輸出 “Undefined symbol xxx (referred from xxx.o)” 這樣的提示,該提示的原因就是在鏈接過程中,某個文件無法在外部找到它引用的標號,因而產生鏈接錯誤。例如,見下圖,把 bsp_led.c 文件中定義的函數 LED_GPIO_Config 改名爲 LED_GPIO_ConfigABCD,而不修改 main.c 文件中的調用,就會出現 main 文件無法找到 LED_GPIO_Config 符號的提示。

在這裏插入圖片描述

1.2 刪除無用節區

map 文件的第二部分是刪除無用節區的說明 (Removing Unused input sections from the image.)。

=================================================================
 Removing Unused input sections from the image.

 Removing startup_stm32f429_439xx.o(HEAP), (512 bytes).

 Removing system_stm32f4xx.o(.rev16_text), (4 bytes).

 Removing system_stm32f4xx.o(.revsh_text), (4 bytes).

 Removing system_stm32f4xx.o(.rrx_text), (6 bytes).

 Removing system_stm32f4xx.o(i.SystemCoreClockUpdate), (136 bytes).

 Removing system_stm32f4xx.o(.data), (20 bytes).

 Removing misc.o(.rev16_text), (4 bytes).

 Removing misc.o(.revsh_text), (4 bytes).

 Removing misc.o(.rrx_text), (6 bytes).

 Removing misc.o(i.NVIC_Init), (104 bytes).

 Removing misc.o(i.NVIC_PriorityGroupConfig), (20 bytes).

 Removing misc.o(i.NVIC_SetVectorTable), (20 bytes).

 Removing misc.o(i.NVIC_SystemLPConfig), (28 bytes).

 Removing misc.o(i.SysTick_CLKSourceConfig), (28 bytes).

 Removing stm32f4xx_adc.o(.rev16_text), (4 bytes).

 Removing stm32f4xx_adc.o(.revsh_text), (4 bytes).

 Removing stm32f4xx_adc.o(.rrx_text), (6 bytes).

 Removing stm32f4xx_adc.o(i.ADC_AnalogWatchdogCmd), (16 bytes).

 Removing stm32f4xx_adc.o(i.ADC_AnalogWatchdogSingleChannelConfig), (12 bytes).

 Removing stm32f4xx_adc.o(i.ADC_AnalogWatchdogThresholdsConfig), (6 bytes).

 Removing stm32f4xx_adc.o(i.ADC_AutoInjectedConvCmd), (24 bytes).

 /**...以下部分省略****/

 ========================================================================

這部分列出了在鏈接過程它發現工程中未被引用的節區,這些未被引用的節區將會被刪除(指不加入到 .axf 文件,不是指在 .o 文件刪除),這樣可以防止這些無用數據佔用程序空間。

例如,上面的信息中說明 startup_stm32f429_439xx.o 中的 HEAP (在啓動文件中定義的用於動態分配的"堆"區)以及 stm32f4xx_adc.o 的各個節區都被刪除了,因爲在我們這個工程中沒有使用動態內存分配,也沒有引用任何 stm32f4xx_adc.c 中的內容。由此也可以知道,雖然我們把 STM32 標準庫的各個外設對應的 C 庫文件都添加到了工程,但不必擔心這會使工程變得臃腫,因爲未被引用的節區內容不會被加入到最終的機器碼文件中。

1.3 符號映像表

map 文件的第三部分是符號映像表 (Image Symbol Table),分爲 Local Symbols 局部 和 Global Symbols 全局。

Local Symbols 記錄了用 static 聲明的全局變量地址和大小,C 文件中函數的地址和用 static 聲明的函數代碼大小,彙編文件中的標號地址(作用域限本文件)。

==============================================================================

 Image Symbol Table

 Local Symbols

 Symbol Name Value Ov Type Size Object(Section)

 ../clib/microlib/init/entry.s 0x00000000 Number 0 entry.o ABSOLUTE

 ../clib/microlib/init/entry.s 0x00000000 Number 0 entry9a.o ABSOLUTE

 ../clib/microlib/init/entry.s 0x00000000 Number 0 entry9b.o ABSOLUTE

 /*...省略部分*/

 LED_GPIO_Config 0x080002a5 Thumb Code 106 bsp_led.o(i.LED_GPIO_Config)

 MemManage_Handler 0x08000319 Thumb Code 2 stm32f4xx_it.o(i.MemManage_Handler)

 NMI_Handler 0x0800031b Thumb Code 2 stm32f4xx_it.o(i.NMI_Handler)

 PendSV_Handler 0x0800031d Thumb Code 2 stm32f4xx_it.o(i.PendSV_Handler)

 RCC_AHB1PeriphClockCmd 0x08000321 Thumb Code 22 stm32f4xx_rcc.o(i.RCC_AHB1PeriphClockCmd)

 SVC_Handler 0x0800033d Thumb Code 2 stm32f4xx_it.o(i.SVC_Handler)

 SysTick_Handler 0x08000415 Thumb Code 2 stm32f4xx_it.o(i.SysTick_Handler)

 SystemInit 0x08000419 Thumb Code 62 system_stm32f4xx.o(i.SystemInit)

 UsageFault_Handler 0x08000469 Thumb Code 2 stm32f4xx_it.o(i.UsageFault_Handler)

 __scatterload_copy 0x0800046b Thumb Code 14 handlers.o(i.__scatterload_copy)

 __scatterload_null 0x08000479 Thumb Code 2 handlers.o(i.__scatterload_null)

 __scatterload_zeroinit 0x0800047b Thumb Code 14 handlers.o(i.__scatterload_zeroinit)

 main 0x08000489 Thumb Code 270 main.o(i.main)

 /*...省略部分*/

 ==============================================================================

這個表列出了被引用的各個符號在存儲器中的具體地址、佔據的空間大小等信息。如我們可以查到 LED_GPIO_Config 符號存儲在 0x080002a5 地址,它屬於 Thumb Code 類型,大小爲 106 字節,它所在的節區爲 bsp_led.o 文件的 i.LED_GPIO_Config 節區。

Global Symbols 記錄了全局變量的地址和大小,C 文件中函數的地址及其代碼大小,彙編文件中的標號地址(作用域全工程)。


    Symbol Name                              Value     Ov Type        Size  Object(Section)

    BuildAttributes$$THM_ISAv4$P$D$K$B$S$PE$A:L22UL41UL21$X:L11$S22US41US21$IEEE1$IW$USESV6$~STKCKD$USESV7$~SHL$OSPACE$ROPI$EBA8$MICROLIB$REQ8$PRES8$EABIv2 0x00000000   Number         0  anon$$obj.o ABSOLUTE
    __ARM_use_no_argv                        0x00000000   Number         0  main.o ABSOLUTE
    _printf_a                                0x00000000   Number         0  stubs.o ABSOLUTE
    _printf_c                                0x00000000   Number         0  stubs.o ABSOLUTE
    _printf_charcount                        0x00000000   Number         0  stubs.o ABSOLUTE
    _printf_d                                0x00000000   Number         0  stubs.o ABSOLUTE
    _printf_e                                0x00000000   Number         0  stubs.o ABSOLUTE
    _printf_f                                0x00000000   Number         0  stubs.o ABSOLUTE
    _printf_flags                            0x00000000   Number         0  stubs.o ABSOLUTE
    _printf_fp_dec                           0x00000000   Number         0  stubs.o ABSOLUTE
    //省略。。。。。。。。。。。。。。。。。
       bsp_RunPer1ms                            0x08000665   Thumb Code     2  bsp.o(i.bsp_RunPer1ms)
    main                                     0x08000667   Thumb Code    14  main.o(i.main)
    Region$$Table$$Base                      0x08000674   Number         0  anon$$obj.o(Region$$Table)
    Region$$Table$$Limit                     0x08000694   Number         0  anon$$obj.o(Region$$Table)
    g_iRunTime                               0x20000008   Data           4  bsp_timer.o(.data)
    __initial_sp                             0x20009978   Data           0  startup_stm32f10x_hd.o(STACK)



==============================================================================

各字段解釋:

名稱 解釋
Symbol Name 符號名稱,分爲 Local,Global
Value 存儲對應地址,0x0800xxxx 指存儲在 FLASH 裏面的代碼、變量等;0x2000xxxx 指存儲在內存 RAM 中的變量 Data 等
Ov Type 符號對應的類型:Number、Section、Thumb Code、Data 等幾種;可以發現全局、靜態變量等位於 0x2000xxxx 的內存 RAM 中。
Size 存儲大小
Object(Section) 當前符號所在段名,對應函數、變量所在的源文件

1.4 存儲器映像索引

map 文件的第四部分是存儲器映像索引 (Memory Map of the image)。

映像文件可以分爲加載域(Load Region)和運行域(Execution Region)。

加載域:反映了 ARM 可執行映像文件的各個段存放在存儲器中的位置關係,映像中的入口點就是程序開始執行的位置。

運行域:反映了 ARM 可執行映像文件各個段真正執行時在存儲器中的位置關係。

加載域就是程序在 Flash 中的實際存儲,而運行域是芯片上電後的運行狀態。因爲 MCU 沒上電時 RAM 中沒有數據,所以此時所有的東西(包括代碼、變量、初始值等)都是存放在 Flash 中的,當上電後又要把變量等複製到 RAM 中才能正常運行。

==============================================================================

 Memory Map of the image

 Image Entry point : 0x080001ad

 Load Region LR_IROM1 (Base: 0x08000000, Size: 0x000005b0, Max: 0x00100000, ABSOLUTE)



7 Execution Region ER_IROM1 (Base: 0x08000000, Size: 0x000005b0, Max: 0x00100000, ABSOLUTE)

 Base Addr Size Type Attr Idx E Section Name Object

 0x08000000 0x000001ac Data RO 3 RESET startup_stm32f429_439xx.o

 /*..省略部分*/

 0x0800020c 0x00000012 Code RO 5161 i.Delay main.o

 0x0800021e 0x0000007c Code RO 2046 i.GPIO_Init stm32f4xx_gpio.o

 0x0800029a 0x00000004 Code RO 2053 i.GPIO_ResetBits stm32f4xx_gpio.o

 0x0800029e 0x00000004 Code RO 2054 i.GPIO_SetBits stm32f4xx_gpio.o

 0x080002a2 0x00000002 Code RO 5196 i.HardFault_Handler stm32f4xx_it.o

 0x080002a4 0x00000074 Code RO 5269 i.LED_GPIO_Config bsp_led.o

 0x08000318 0x00000002 Code RO 5197 i.MemManage_Handler stm32f4xx_it.o

 /*..省略部分*/

 0x08000488 0x00000118 Code RO 5162 i.main main.o

 0x080005a0 0x00000010 Data RO 5309 Region$$Table anon$$obj.o

 Execution Region RW_IRAM1 (Base: 0x20000000, Size: 0x00000400, Max: 0x00030000, ABSOLUTE)

 Base Addr Size Type Attr Idx E Section Name Object

 0x20000000 0x00000400 Zero RW 1 STACK startup_stm32f429_439xx.o

 ==============================================================================

本工程的存儲器映像索引分爲 ER_IROM1 及 RW_IRAM1 部分,它們分別對應STM32 內部 FLASH 及 SRAM 的空間。相對於符號映像表,這個索引表描述的單位是節區,而且它描述的主要信息中包含了節區的類型及屬性,由此可以區分 Code、RO-data、RW-data 及 ZI-data。

例如,從上面的表中我們可以看到 i.LED_GPIO_Config 節區存儲在內部 FLASH 的 0x080002a4 地址,大小 爲0x00000074,類型爲 Code,屬性爲 RO。而程序的 STACK 節區(棧空間)存儲在 SRAM 的 0x20000000 地址,大小爲 0x00000400,類型爲 Zero,屬性爲 RW(即RW-data)。

1.5 映像組件大小

map 文件的最後一部分是包含映像組件大小的信息 (Image component sizes),這也是最常查詢的內容。

==============================================================================

 Image component sizes

4 Code (inc. data) RO Data RW Data ZI Data Debug Object Name

 116 10 0 0 0 578 bsp_led.o

 298 10 0 0 0 1459 main.o

 36 8 428 0 1024 932 startup_stm32f429_439xx.o

 132 0 0 0 0 2432 stm32f4xx_gpio.o

 18 0 0 0 0 3946 stm32f4xx_it.o

 28 6 0 0 0 645 stm32f4xx_rcc.o

 292 34 0 0 0 253101 system_stm32f4xx.o


 ----------------------------------------------------------------------

 926 68 444 0 1024 263093 Object Totals

 0 0 16 0 0 0 (incl. Generated)

 6 0 0 0 0 0 (incl. Padding)


 /*...省略部分*/

 ==============================================================================

 Code (inc. data) RO Data RW Data ZI Data Debug


 1012 84 444 0 1024 262637 Grand Totals

 1012 84 444 0 1024 262637 ELF Image Totals

 1012 84 444 0 0 0 ROM Totals

 ==============================================================================

 Total RO Size (Code + RO Data) 1456 ( 1.42kB)

 Total RW Size (RW Data + ZI Data) 1024 ( 1.00kB)

 Total ROM Size (Code + RO Data + RW Data) 1456 ( 1.42kB)

 ==============================================================================

這部分包含了各個使用到的 .o 文件的空間彙總信息、整個工程的空間彙總信息以及佔用不同類型存儲器的空間彙總信息,它們分類描述了具體佔據的 Code、RO-data、RW-data 及 ZI-data 的大小,並根據這些大小統計出佔據的 ROM 總空間。

我們僅分析最後兩部分信息,如 Grand Totals 一項,它表示整個代碼佔據的所有空間信息,其中 Code 類型的數據大小爲1012字節,這部分包含了 84 字節的指令數據 (inc .data) 已算在內,另外 RO-data 佔 444 字節,RW-data 佔 0 字節,ZI-data 佔 1024 字節。在它的下面兩行有一項 ROM Totals 信息,它列出了各個段所佔據的 ROM 空間,除了 ZI-data 不佔 ROM 空間外,其餘項都與 Grand Totals 中相等 (RW-data 也佔據 ROM 空間,只是本工程中沒有 RW-data 類型的數據而已)。

最後一部分列出了只讀數據 (RO)、可讀寫數據 (RW) 及佔據的 ROM 大小。其中只讀數據大小爲 1456 字節,它包含 Code 段及 RO-data 段; 可讀寫數據大小爲 1024 字節,它包含 RW-data 及 ZI-data 段;佔據的 ROM 大小爲 1456 字節,它除了 Code 段和 RO-data 段,還包含了運行時需要從 ROM 加載到 RAM 的 RW-data 數據。

綜合整個 map 文件的信息,可以分析出,當程序下載到 STM32 的內部 FLASH 時,需要使用的內部 FLASH 是從 0x0800 0000 地址開始的大小爲 1456 字節的空間;當程序運行時,需要使用的內部 SRAM 是從 0x20000000 地址開始的大小爲 1024 字節的空間。

粗略一看,發現這個小程序竟然需要 1024 字節的 SRAM,實在說不過去,但仔細分析 map 文件後,可瞭解到這 1024 字節都是 STACK 節區的空間(即棧空間),棧空間大小是在啓動文件中定義的,這 1024 字節是默認值 (0x00000400)。它是提供給 C 語言程序局部變量申請使用的空間,若我們確認自己的應用程序不需要這麼大的棧,完全可以修改啓動文件,把它改小一點,查看前面講解的 htm 靜態調用圖文件可瞭解靜態的棧調用情況,可以用它作爲參考。

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