關於 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 段

    /* .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 段

/* stack section */
    .stack_dummy (NOLOAD):
    {
  *(.stack)
    } > BD_RAM

 __StackTop = ORIGIN(BD_RAM) + LENGTH(BD_RAM);
 __StackLimit = __StackTop - SIZEOF(.stack_dummy);
 PROVIDE(__stack = __StackTop);
heap 段

.heap (NOLOAD):
    {
        __end__ = .;
        end = __end__;
        *(.heap*)
        __HeapLimit = .;
    } > BD_RAM
有沒有發現 bss/stack/heap 有一個 NOLOAD 參數.
這是因為這些沒有初始化值, 只需要變數位置. 所以並不需要真正寫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/




留言

熱門文章