嵌入式linux開發 (二十七) 存儲管理(1)從flash到內存

  • 執行方式
嵌入式系統中代碼的執行方式主要有3種:
	1.完全映射(fully shadowed)。
		嵌入式系統程序運行時,將所有的代碼從非易失存儲器(Flash、ROM等)複製到RAM中運行。
		例子:s3c2440的nandflash和i.mx6ull的sd卡
 	2.按需分頁(demand paging)。
 		只複製部分代碼到RAM中。
 		這種方法對RAM中的頁進行導入導出管理,如果訪問位於虛存中但不在物理RAM中會產生頁錯誤,這時纔將代碼和數據映射到RAM中。
 		例子:linux系統對於可執行程序的加載
 	3.eXecute In Place (XIP)。
 		在系統啓動時,不將代碼複製到RAM,而是直接在非易失性存儲位置執行。
 		RAM中只存放需要不斷變化的數據部分
 		例子:stm32的主flash 及s3c2440的norflash
  • 問題:
代碼中有變化部分和不變化部分,所以代碼可以分割?如果可以,怎麼分割?
	代碼中 分割成 .code .ro-data .data .bss .heap .stack
	二進制文件中 分割 成 .code .ro-data .data
	內存中 分割成 .code .ro-data .data .bss .heap .stack
分割出來的代碼怎麼實現完全映射?
	.code .ro-data .data 複製到ram
	.bss 清0
	.stack 設置SP
	.heap 設置
分割出來的代碼怎麼實現XIP?
	XIP 指的是可以在 flash 取指令,然後執行,棧還是放在 ram 中的
	pc 順序指向
	調用函數時使用.stack
	

  • 爲什麼要做內存分段
方便編碼
  • hex 文件與反彙編對照
反彙編文件
87800000 <_start>:
87800000:   e10f0000    mrs r0, CPSR
87800004:   e3c0001f    bic r0, r0, #31
87800008:   e3800013    orr r0, r0, #19
8780000c:   e129f000    msr CPSR_fc, r0

在 hex文件
:020000048780F3
:10000000 00000FE1 1F00C0E3 130080E3 00F029E1 CE

高字節 e1 放在了 高地址, 小端. // dis(反彙編) 文件中也有顯示 是小端
ARM默認設置爲小端格式


led 中的段位置的放置 是有道理的
SECTIONS {
    . = 0X87800000;
    .text :
    {
        start.o
        *(.text)
    }
    .rodata ALIGN(4) : {*(.rodata)}
    .data ALIGN(4) : {*(.data)}
    __bss_start=.;
    .bss ALIGN(4) : {*(.bss) *(COMMON)}
    __bss_end=.;
}

一開始必定是 .text 段(RO)
然後還是RO的 .rodata (const修飾的全局變量)
// 兩個RO放在一起,方便一起拷貝(因爲有時候有一起拷貝的必要?)
然後 .data (在二進制文件中)

然後是.bss(.bss 不在二進制文件中,但是佔用地址,爲了不讓.bss佔二進制文件的空間,所以將其放在最後面.並省略這個段)

  • 段在文件及內存中的表現形式

-----------------在二進制文件中

.text段 爲RO,.text 段有相對地址(相對PC),.text 段中有可能有絕對地址,是因爲可能使用了地址相關彙編代碼(不是C代碼)
.rodata 段 爲RO, 緊緊挨着 .text段..text段中如果有對 const變量的引用,引用的不是地址,是 值
.data 段 爲RW, 緊緊挨着 .rodata段..text段中如果有對 data變量的引用,引用的是地址
.bss 段 爲RW , 不存在於 二進制文件中..text段中如果有對 bss變量的引用,引用的是地址,但是可以確定.bss開始與結束的地址及每個bss變量的地址

.stack 段, 不存在於二進制文件中.
.heap段, 不存在於二進制文件中.

-----------------怎麼講二進制文件拷貝到內存中,並做好內存環境配置

1. 對於.text 段. 一定要拷貝到對應的地址上去.因爲.text中有可能使用了地址相關彙編代碼
2. 對於.rodata 段.其實可以不用拷貝,因爲.rodata 的值已經在 .text 中了.
3. 對於.data 段.需要拷貝到對應的地址上去,因爲 .text 中要引用 data變量的地址
4. 對於 bss 段, 因爲二進制文件中沒有,但是.text中會對其變量地址引用 .所以 每個變量的地址,每個變量都要初始化爲0. 要在內存中,從段的起始到結束,設置爲0.

5. 對於stack 段,因爲 代碼調用 實際上被編譯成了 push pop 指令,所以函數實質就是 壓棧彈棧.雖然PC一直指向.text段,但是運行時的狀態是在.stack段.. 那麼棧空間肯定要設置.棧空間的設置只需要初始化SP指針即可. 另外,棧的類型(先增,後增,先減,後減)由具體芯片定義.

// 如果對應做菜, 可以這麼說 .text是菜譜 , .ro-data 是廚具(不變的數據) , .data和.bss 是菜,.heap段 是個大菜 ,菜譜中有攪拌的動作(類似於代碼中有出棧入棧的動作) 
// 也就是說一般菜譜中都會有攪拌的動作,也就是說一般情況下,代碼在執行過程中會有出棧入棧的動作.


6. 對於 heap 段,一般用來存儲數據.如果要使用動態內存,則肯定要用初始化heap ,,找一塊內存,將該內存用數據結構進行管理,malloc和free的時候其實本質也是對數據結構的管理

-----------------在內存中

.text段 爲RO,.text 段有相對地址(相對PC),.text 段中有可能有絕對地址,是因爲可能使用了地址相關彙編碼(不是C代碼)
.rodata 段 爲RO, 緊緊挨着 .text段..text段中如果有對 const變量的引用,引用的不是地址,是 值
.data 段 爲RW, 緊緊挨着 .rodata段..text段中如果有對 data變量的引用,引用的是地址
.bss 段 爲RW , 緊緊挨着 .data段..text段中如果有對 bss變量的引用,引用的是地址

.stack 段一般 爲 高地址->低地址 發展,.heap發展,不和.text .rodata .data .bss 段重複
.heap 段一般爲 低地址->高地址 發展,.stack發展,不和.text .rodata .data .bss 段重複


// https://www.bravegnu.org/gnu-eprog/c-startup.html

段有哪些

  • elf 文件中

$ readelf -S ledc.elf 
There are 11 section headers, starting at offset 0x8320:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        87800000 008000 000158 00  AX  0   0  4
  [ 2] .text.startup     PROGBITS        87800158 008158 0000f8 00  AX  0   0  4
  [ 3] .rodata           PROGBITS        87800250 008250 000004 00   A  0   0  4
  [ 4] .data             PROGBITS        87800254 008254 000004 00  WA  0   0  4
  [ 5] .bss              NOBITS          87800258 008258 00000c 00  WA  0   0  4
  [ 6] .comment          PROGBITS        00000000 008258 000046 01  MS  0   0  1
  [ 7] .ARM.attributes   ARM_ATTRIBUTES  00000000 00829e 000027 00      0   0  1

  [ 8] .shstrtab         STRTAB          00000000 0082c5 00005b 00      0   0  1
  [ 9] .symtab           SYMTAB          00000000 0084d8 000310 10     10  30  4
  [10] .strtab           STRTAB          00000000 0087e8 0000f2 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

  • elf 文件反匯編出來的dis文件中
.text
.text.startup
.rodata
.data
.bss
.comment
.ARM.attributes
  • bin 文件中 (最終只有bin文件被燒寫到flash中)
.text
.text.startup 
	// 和-O2 有關係 https://www.raspberrypi.org/forums/viewtopic.php?t=126964
	// 如果用-O0 或者-O1編譯,是沒有.text.startup 段的
.rodata
.data
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章