RT-1052學習筆記(3 )-分散加載文件

複習MDK鏈接加載程序過程

例子:各種數據所存放的段

#define       DATA      (0x10000000)     /* RO-Data                   */ 
char const    GcChar = 5;                /* RO-Data                   */
char          GcStr[] = "string.";       /* RW-Data                   */
char          GcZero;                    /* ZI-Data                   */ 

在隨意一個MDK工程的listings文件夾中都會生成一個map文件,最底下會有鏈接信息,可知ROM會包括Code ,RO Data以及RW Data段。其中,前面兩個段容易理解,代碼段和只讀數據段自然是存放在flash中。

==============================================================================
      Code (inc. data)   RO Data    RW Data    ZI Data      Debug   
     11080       1488       2976         28       2084    2984889   Grand Totals
     11080       1488       2976         28       2084    2984889   ELF Image Totals
     11080       1488       2976         28          0          0   ROM Totals
==============================================================================
    Total RO  Size (Code + RO Data)                14056 (  13.73kB)
    Total RW  Size (RW Data + ZI Data)              2112 (   2.06kB)
    Total ROM Size (Code + RO Data + RW Data)      14084 (  13.75kB)
==============================================================================
  • 問1:但是,RW?爲什麼數據段信息也存放在flash中?
  • 答1:RW段包含所有已經在代碼中初始化的所有變量。在程序編譯的時候把數據存放到FLASH中,然後在程序運行的時候,會把RW段數據複製到在分散加載文件中指定的地址空間上
  • 問2:這個動作是怎麼發生的?誰來執行它?硬件還是軟件?什麼時候執行?
  • 答2:這個動作在啓動文件的復位中斷Reset_Handler中,在SystemInit函數執行完成之後會跳轉到_main函數執行。然後在_main函數會完成RW段的重定位以及ZI段的清零,再跳轉到main函數中運行

分散加載文件簡介

i.MX-RT開發爲什麼需要自定義分散加載文件

由於RT1052沒有內置flash,需要外界FLASH以實現程序的存放。再加上外擴RAM的存在,每個板子設計的flash和ram容量大小都不相同,使得在程序鏈接以及運行時必須根據這些信息以實現程序的鏈接以及初始化。也就是把不同的代碼數據放在不同的存儲空間,而且,在程序鏈接時,會包含有各種各樣的域,標準的,自定義的域。

需要使用到自動以分散加載文件的情況:

  • 複雜的內存映射:不同區域存放不同數據和代碼
  • 不同類型的內存:把需求不同的數據放置於不同的位置,ITCM,SDRAM,OCRAM
  • 內存映射I/O:把某些數據字節準確放置於某個內存,以便能夠訪問內存映射的外圍設備,比如初始化SDRAM
  • 位於固定位置的函數:比如一些固定屬性的函數列表
  • 使用符號標識堆和堆棧:可以在堆或者棧中定義一些自定義的符號。

加載文件語法

首先,分散加載的語法遵循 Backus-Naur Form規範.

作者:貓山王
來源:CSDN
原文:https://blog.csdn.net/PINBODEXIAOZHU/article/details/25389441
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!


巴科斯範式的內容
在雙引號中的字(“word”)代表着這些字符本身。而double_quote用來代表雙引號。
在雙引號外的字(有可能有下劃線)代表着語法部分。
尖括號( < > )內包含的爲必選項。
方括號( [ ] )內包含的爲可選項。
大括號( { } )內包含的爲可重複0至無數次的項。
豎線( | )表示在其左右兩邊任選一項,相當於"OR"的意思。
::= 是“被定義爲”的意思。

基本概念

  • 加載時域:域所在的flash地址空間
  • 運行時域:程序運行時域所在的空間

加載時域:一個加載時域可以包含多個運行時域

load_region_name (base_address | ("+" offset)) [attribute_list] [max_size]
"{"
execution_region_description+
"}"
  • load_region_name :爲本加載時域的名稱,名稱可以按照用戶意願自己定義,該名稱中只有前 31 個字符有意義
  • base_address:表示本加載時域中的對象在連接時的起始地址,地址必須是字對齊的
  • +offset:表示本加載時域中的對象在連接時的起始地址是在前一個加載時域的結束地址後偏移量 offset 字節處。本加載時域是第一個加載時域,則它的起始地址即爲 offset, offset 的值必須能被 4 整除
  • attribute_list:指定本加載時域內容的屬性
    • ABSOLUTE:絕對地址;PI:與位置無關;RELOC:可重定位;OVERLAY:覆蓋;NOCOMPRESS:不能進行壓縮
  • max_size:指定本加載時域的最大尺寸。如果本加載時域的實際尺寸超過了該值,連接器將報告錯誤, 默認取值爲 0xFFFFFFFF;
  • execution_region_description:表示運行時域,後面有個+號,表示其可以有一個或者多個運行時域

運行時域語法

exec_region_name(base_address|"+"offset)[attribute_list][max_size|" "length]
{
	input_section_description*
}
  • exec_region_name:爲本加載時域的名稱,名稱可以按照用戶意願自己定義,該名稱中只有前31個字符有意義;
  • base_address:表示本加載時域中的對象在連接時的起始地址,地址必須是字對齊的;
  • +offset:表示本加載時域中的對象在連接時的起始地址是在前一個加載時域的結束地址後偏移量offset 字節處,offset的值必須能被4整除。
  • attribute_list: 指定本加載時域內容的屬性:
    • ABSOLUTE:絕對地址;
    • PI:與位置無關;
    • RELOC:可重定位;
    • OVERLAY:覆蓋;
    • FIXED:固定地址。區加載地址和執行地址都是由基址指示符指定的,基址指示符必須是絕對基址,或者偏移爲 0。
    • ALIGNalignment:將執行區的對齊約束從4增加到alignment。alignment必須爲2的正數冪。如果執行區具有base_address,則它必須爲alignment對齊。如果執行區具有offset,則鏈接器將計算的區基址與alignment邊界對齊;
    • EMPTY:在執行區中保留一個給定長度的空白內存塊,通常供堆或堆棧使用。
    • ZEROPAD:零初始化的段作爲零填充塊寫入ELF文件,因此,運行時無需使用零進行填充;
    • PADVALUE:定義任何填充的值。如果指定 PADVALUE,則必須爲其賦值;
    • NOCOMPRESS:不能進行壓縮;
    • UNINIT:未初始化的數據。
    • max_size:指定本加載時域的最大尺寸。如果本加載時域的實際尺寸超過了該值,連接器將報告錯誤,默認取值爲0xFFFFFFFF
    • length:如果指定的長度爲負值,則將 base_address 作爲區結束地址。它通常與EMPTY 一起使用,以表示在內存中變小的堆棧。
  • input_section_description:指定輸入段的內容。

輸入段描述

module_select_pattern["("input_section_selector(","input_section_selector)*")"]
	("+" input_section_attr | input_section_pattern | input_symbol_pattern)
  • module_select_pattern:目標文件濾波器,支持使用通配符“”與“?”。其中符號“”代表零個或多個字符,符號“?”代表單個字符。進行匹配時所有字符不區分大小寫。當module_select_pattern與以下內容之一相匹配時,輸入段將與模塊選擇器模式相匹配:
    • 包含段和目標文件的名稱;
    • 庫成員名稱(不帶前導路徑名);
    • 庫的完整名稱(包括路徑名)。如果名稱包含空格,則可以使用通配符簡化搜索。例如,使用*libname.lib 匹配 C:\lib dir\libname.lib。
  • nput_section_attr:屬性選擇器與輸入段屬性相匹配。每個input_section_attr的前面有一個“+”號。如果指定一個模式以匹配輸入段名稱,名稱前面必須有一個“+”號。可以省略緊靠“+”號前面的任何逗號。 選擇器不區分大小寫。可以識別以下選擇器:
    • RO-CODE;
    • RO-DATA;
    • RO,同時選擇 RO-CODE 和 RO-DATA;
    • RW-DATA;
    • RW-CODE;
    • RW,同時選擇 RW-CODE 和 RW-DATA;
    • ZI;
    • ENTRY:即包含 ENTRY 段。
    • 可以識別以下同義詞:
      • CODE 表示 RO-CODE;
      • CONST 表示 RO-DATA;
      • TEXT 表示 RO;
      • DATA 表示 RW;
      • BSS 表示 ZI。
    • 可以識別以下僞屬性:
      • FIRST;
      • LAST。
      • 使用FIRST和LAST去標誌一個運行域的第一個段個最後一個段
  • 通過使用特殊模塊選擇器模式.ANY 可以將輸入段分配給執行區,而無需考慮其父模塊。可以使用一個或多個.ANY 模式以任意分配方式填充運行時域。在大多數情況下,使用單個.ANY 等效於使用*模塊選擇器。

分散加載文件分析

  • 目的:能看懂一個分散加載文件。

上面介紹了三個分散加載文件的語法,現在先不直接上RT1052複雜的分散加載文件,先來個簡單的STM32F103C8T6的分散加載文件,分散加載文件主要由一個加載時域和多個運行時域組成。

LR_IROM1 0x08000000 0x00010000{;定義一個加載時域,域基地址:0x08000000,大小:0x00010000
								;這個空間就是STM32flash的實際信息	
	ER_IROM1 0x08000000 0x00010000 {	;定義第一個一個運行時域,第一個運行時域必須和加載
										;時域起始地址相同,否則庫不能加載到該時域的
										;錯誤,其域大小一般也和加載時域大小相同
		*.o (RESET, +First)				;RESET在啓動文件中有定義,爲一個異常向量表
		*(InRoot$$Sections)				;MDK自動生成的段,主要在_main中執行
		.ANY (+RO)						;剩下所有代碼段
	}
	 RW_IRAM1 0x20000000 0x00005000  {;定義第二個運行時域,域基地址:0x08000000,大小:0x00005000
		.ANY (+RW +ZI)					;所有數據段
	}
}

下面來分析RT1052的分散加載文件

  • 工程配置:RT1052的分散加載文件當然是要自己寫啦。
    keil MDK中設置分散加載文件
; 外部QSPI FLASH 起始地址:0x60000000
; 存放QSPI FLASH 參數,如幾線制的 SPI Flash, SPI 的時鐘頻率, LUT 查找表, DDR/SDR 模式以及片選 CS管腳的 hold/setup time 等信息
; 0x00001000 = 4KB
#define m_flash_config_start           0x60000000
#define m_flash_config_size            0x00001000

; 存放Image Vector Table(IVT)
#define m_ivt_start                    0x60001000
#define m_ivt_size                     0x00001000

; 存放中斷向量表
#define m_interrupts_start             0x60002000
#define m_interrupts_size              0x00000400

; 程序從這裏開始存儲
#define m_text_start                   0x60002400
#define m_text_size                    0x01FFDC00


; ITCM :起始地址:0000_0000  ,大小128KB
; DTCM :起始地址:2000_0000  ,大小128KB
; OCRAM:起始地址:2020_0000  ,大小256KB

; ITCM,128KB,用來存放指令
;#define m_data_start                   0x00000000
;#define m_data_size                    0x00020000


; DTCM,128KB,用來存放數據
#define m_data_start                   0x20000000
#define m_data_size                    0x00020000


; OCRAM,256KB,用來存放數據
#define m_data2_start                  0x20200000
#define m_data2_size                   0x00040000

/* Sizes */
#if (defined(__stack_size__))
  #define Stack_Size                   __stack_size__
#else
  ; 0x0400 = 1KB  
  #define Stack_Size                   0x0400
#endif

#if (defined(__heap_size__))
  #define Heap_Size                    __heap_size__
#else
  #define Heap_Size                    0x0400
#endif



LR_m_rom_config m_flash_config_start m_flash_config_size {   ; load region size_region
	RW_m_config_text m_flash_config_start m_flash_config_size { ; load address = execution address
	* (.boot_hdr.conf, +FIRST)
	}
}

LR_m_rom_ivt m_ivt_start m_ivt_size {   ; load region size_region
	RW_m_ivt_text m_ivt_start m_ivt_size { ; load address = execution address
	* (.boot_hdr.ivt, +FIRST)
	* (.boot_hdr.boot_data)
	* (.boot_hdr.dcd_data)
	}
}

LR_m_text m_interrupts_start m_text_start+m_text_size-m_interrupts_size {   ; load region size_region
  VECTOR_ROM m_interrupts_start m_interrupts_size { ; load address = execution address
    * (RESET,+FIRST)
  }
  ER_m_text m_text_start m_text_size { ; load address = execution address
    * (InRoot$$Sections)
    .ANY (+RO)
  }
  RW_m_data m_data_start m_data_size-Stack_Size-Heap_Size { ; RW data
    .ANY (+RW +ZI)
    * (NonCacheable.init)
    * (NonCacheable)
  }
  ARM_LIB_HEAP +0 EMPTY Heap_Size { ; Heap region growing up
  }
  ARM_LIB_STACK m_data_start+m_data_size EMPTY -Stack_Size { ; Stack region growing down
  }
}

FLASH和SRAM分析

加載域 域描述
0x60000000~0x60000FFF .boot_hdr_conf 外部QSPI FLASH 起始地址:0x60000000。存放QSPI FLASH 參數,如幾線制的 SPI Flash, SPI 的時鐘頻率, LUT 查找表, DDR/SDR 模式以及片選 CS管腳的 hold/setup time 等信息
0x60001000~0x60001FFF .boot_hdr.ivt + .boot_hdr.boot_data + .boot_hdr.dcd_data 存放Image Vector Table(IVT)
0x60002000~0x600023FF RESET 存放中斷向量表
0x60002400~0x‭62000000‬ InRoot$$Sections + .ANY (+RO) 程序從這裏開始存儲
0x00000000~0x0001FFFF ITCM ITCM 128KB,用來緩存指令。因爲在程序連接時不需要,所以沒寫在scf上
0x20000000~0x2001F7FF DTCM DTCM,126KB,用來存放數據
0x2001F800~0x2001FBFF Heap Heap,1KB,系統堆區,往上增長
0x2001FC00~0x2001FFFF Stack Stack,1KB,系統棧區,往下增長

參考文獻

C:\Keil_v5\ARM\Hlp\DUI0377G_02_mdk_armlink_user_guide.pdf
分散加載文件淺析-周立功.pdf

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