關於 Arduino Ameba 的 100 篇 - 程式記憶體位置 - (text/data/bss/heap/stack) (6/100)
續之前
程式記憶體位置
介紹在看 C/C++ 會提到的 text/data/bss/stack/heap 觀念.
和大家介紹 Howard Chen 做的一個 不錯的投影片 - HyperC OS
( 有興趣 porting HyperC OS 的可以用這個 github -
https://github.com/ibanezchen/hyperCOS-evaluate
除了大公司之外, maker 使用和小量生產都是 royalty-free )
借用一下第四頁的這張圖, 來說明:
1. text 段 : 主要存放程式部分
2. data 段 : 存放有初始化的全域變數
3. bss 段 : 存放未初始化的全域變數
4. stack 段 : 存放 區域變數;
另外程式 呼叫進入/返回, 也會將參數存入.
PS: Ameba 是使用 ARM cortex-M3 CPU, 在 cortex-m3, 為了效能
- 前三個函式參數 會放在 r0, r1, r2 暫存器中. 後面多的參數才放在 stack
- 函式返回會存在 link register
- 有兩組 stack pointer, MSB (main stack pointer)和 PSP (process stack pointer)
( ARM doc )
5. heap 段 : 提供給動態管理機制使用的, 如這邊所用的 malloc
另外 每從 heap 要一個記憶體 (malloc), 位置值是遞增;
但從 stack 要記憶體, 位置值是遞減.
實際對應到 linker script - e.g. rlx8195.ld
data 段 -
e.g.
*(.data .data.* *.data); |
text 段 -
e.g.
*(.text .text.* *.text)
bss 段
stack 段 /* .bss section which is used for uninitialized data */
.bss (NOLOAD):
{
. = ALIGN(4);
__bss_start__ = .;
_sbss = . ;
_szero = .;
*(COMMON)
*(.sdio.rom.bss*)
*(.bss*)
. = ALIGN(4);
_ebss = . ;
_ezero = .;
__bss_end__ = .;
} > BD_RAM
/* stack section */
.stack_dummy (NOLOAD):
{
*(.stack)
} > BD_RAM
__StackTop = ORIGIN(BD_RAM) + LENGTH(BD_RAM);
__StackLimit = __StackTop - SIZEOF(.stack_dummy);
PROVIDE(__stack = __StackTop);
.heap (NOLOAD):
{
__end__ = .;
end = __end__;
*(.heap*)
__HeapLimit = .;
} > BD_RAM
這是因為這些沒有初始化值, 只需要變數位置. 所以並不需要真正寫data 到 flash.
而 C 對未初始化的變數值, 也不保證內容為何
(unknown, 如 RAM 剛上電初始啟動時, 內容值也是不保證 )
另外 C malloc 設計中, 在實際要記憶體時, 會需要一個 _sbrk(),
一般會需要自己依照嵌入式系統設計, 設計 sbrk(), 而用 default library 的,
他會參考這邊 linker script 的 end 變數, 來得到 heap 的起始位置.
也可以自行實作 _sbrk(), 例如
/*
sbrk
Increase program data space.
Malloc and related functions depend on this
*/
caddr_t _sbrk(int incr) {
extern char _ebss; // Defined by the linker
static char *heap_end;
char *prev_heap_end;
if (heap_end == 0) {
heap_end = &_ebss;
}
prev_heap_end = heap_end;
char * stack = (char*) __get_MSP();
if (heap_end + incr > stack)
{
_write (STDERR_FILENO, "Heap and stack collision\n", 25);
errno = ENOMEM;
return (caddr_t) -1;
//abort ();
}
heap_end += incr;
return (caddr_t) prev_heap_end;
}
所以 如果實作的是用其他區段而不是 heap 段時, 那 malloc 就會要到其他的位置..
只是這就會變成和一般的認知不同, 而可能在合作時產生錯誤.
PS: 補充 : 看到一篇 有關 linker script 的說明 :
http://wen00072.github.io/blog/2014/12/22/rtenv-linker-script-explained/
留言
張貼留言