前言
在開發mcu代碼的時候經常會有些疑惑,變數是怎么在編譯之后進入單片機的ram區的呢,特別是在使用keil開發的時候,后來在接觸gcc編譯器和自研的mcu后,終于明白了這個問題,實際上變數編譯后被放在了bin檔案中代碼的后面(data存放在bin中,bss在bin里存放了長度資訊),程式運行時會主動將該區域的資料依次加載到ram區域中,
原理
寫完代碼編譯后,會把code中的data區的變數放在代碼的后面,bss區的變數僅存放長度在bin中,當然這個規則也是由鏈接檔案來決定的,示例圖如下

在程式運行后正式進入C環境前,code中會存在一段匯編代碼,主要作用就是把data區域記憶體依次復制到ram中,復制結束后,把后面和bss區描述長度一致區域的記憶體全置為0,
通過這也能夠看出為什么bss區域的值會被設定為0,因為記憶體中是沒有型別的說法,如果不全置0,無論其它哪個值都沒法確認實際型別的值,(例如設定為1的話,不同的型別就會對應不同的值,int是0x1111,short是0x11)
但是在keil中我們沒有看到這樣的代碼,keil的匯編代碼如下:
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
這段代碼執行完畢后會跳轉到__main函式里執行,主要注意的是這里并不是直接跳轉到我們撰寫的main函式里,在__main有很多的操作,其中就包括將變數加載到ram區域中,執行完畢后才會跳轉到我們自己開發的main函式中執行,
示例分析
下面這段代碼就是gcc編譯器下加載變數的代碼,其中有幾個變數,data在bin檔案中的起始地址,data在ram區的起始、結束地址,bss在ram區的起始、結束地址都是通過ld檔案中獲取的,
運行完下面的code后,程式中的所有變數都被加載到了ram區域中,
/*
* The ranges of copy from/to are specified by following symbols
* __etext: LMA of start of the section to copy from. Usually end of text
* __data_start__: VMA of start of the section to copy to
* __data_end__: VMA of end of the section to copy to
*
* All addresses must be aligned to 4 bytes boundary.
*/
lrw r1, __erodata // data在bin檔案中的起始地址
lrw r2, __data_start__ // data在ram中的起始地址
lrw r3, __data_end__ // data在ram中的結束地址
subu r3, r2 // r3為data的長度
cmpnei r3, 0 // 判斷長度是否為0
bf .L_loop0_done
.L_loop0: // 將bin檔案中資料依次移到ram中
ldw r0, (r1, 0)
stw r0, (r2, 0)
addi r1, 4
addi r2, 4
subi r3, 4
cmpnei r3, 0
bt .L_loop0
.L_loop0_done:
/*
* The BSS section is specified by following symbols
* __bss_start__: start of the BSS section.
* __bss_end__: end of the BSS section.
*
* Both addresses must be aligned to 4 bytes boundary.
*/
lrw r1, __bss_start__
lrw r2, __bss_end__
movi r0, 0
subu r2, r1
cmpnei r2, 0
bf .L_loop1_done
.L_loop1: // 將bss里的資料復制為0
stw r0, (r1, 0)
addi r1, 4
subi r2, 4
cmpnei r2, 0
bt .L_loop1
.L_loop1_done:
本文來自博客園,作者:Air-Liu,轉載請注明原文鏈接:https://www.cnblogs.com/ghost-98210/p/15744465.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/397182.html
標籤:其他
上一篇:限制惰性列中的專案
