程序的下載(燒錄到存儲器中)通常是按照程序文件分段(Code段、RO_data段、RW_data段、ZI_data段)的方式存儲的,但運行時內存的布局會按照程序進程分段(TEXT段、DATA段、BSS段、堆棧段)進行組織。以下是具體分析:
1. 下載時的存儲方式(文件分段)
程序在編譯鏈接后生成的二進制文件(如ELF、Hex、Bin等)是按文件分段存儲的,主要包括:
- Code段:存儲機器指令(代碼)。
- RO_data段:存儲只讀常量(如字符串常量、const變量)。
- RW_data段:存儲已初始化且非零的全局/靜態變量。
- ZI_data段:存儲未初始化或初始化為零的全局/靜態變量(實際下載時可能不占用空間,僅記錄大小)。
下載時的特點:
- 文件中的
ZI_data段
通常不會直接存儲零值數據,而是通過鏈接腳本記錄其大小,運行時由啟動代碼(如startup.s
)在內存中初始化為零。 - 下載到Flash/ROM時,僅包含
Code
、RO_data
和RW_data
的初始值,ZI_data
僅保留大小信息。
2. 運行時的內存布局(進程分段)
程序運行時,會根據進程分段加載到內存中:
- TEXT段:對應文件中的
Code段
和RO_data段
,通常加載到只讀內存(如Flash或ROM)。 - DATA段:對應文件中的
RW_data段
,需從Flash拷貝到可讀寫內存(如RAM),因為運行時可能需要修改這些變量。 - BSS段:對應文件中的
ZI_data段
,由啟動代碼在RAM中初始化為零。 - HEAP和STACK:在運行時動態分配,不占用下載文件空間。
關鍵區別:
RW_data段
在文件中存儲初始值,但運行時需要復制到RAM的DATA段
(因為Flash不可寫)。ZI_data段
在文件中僅記錄大小,運行時在RAM的BSS段
中分配并清零。
3. 為什么下載按文件分段?
- 存儲效率:Flash/ROM空間有限,避免存儲全零的
ZI_data
數據。 - 執行效率:啟動時只需從Flash中拷貝
RW_data
的初始值到RAM,并快速清零BSS段
。
4. 鏈接腳本的作用
鏈接腳本(如ld
文件)會明確指定:
- 哪些段屬于Flash(
Code
、RO_data
、RW_data
的初始值)。 - 哪些段屬于RAM(
RW_data
的運行地址、BSS段
的分配)。
示例鏈接腳本片段:
MEMORY {FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 256KRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
}SECTIONS {.text : { *(.text*) } > FLASH /* Code段 */.rodata : { *(.rodata*) } > FLASH /* RO_data段 */.data : { *(.data*) } > RAM AT > FLASH /* RW_data段:RAM中運行,Flash中存儲初始值 */.bss : { *(.bss*) } > RAM /* ZI_data段 */
}
5. 總結
- 下載時:按文件分段(Code、RO_data、RW_data、ZI_data)存儲到Flash/ROM。
- 運行時:按進程分段(TEXT、DATA、BSS、堆棧)組織內存,其中
RW_data
和ZI_data
需從Flash初始化到RAM。
這種設計平衡了存儲空間和運行時效率,是嵌入式系統和裸機程序的典型實現方式。