最近,有個(gè)好學(xué)的小伙子突然問了我一個(gè)問題:
全局變量的初始值,是在哪里賦值的?
問題雖然說不是很重要,但是我很好奇。
為了給講清楚這個(gè)原理過程,我專門建立一個(gè)基于Renesas RH850的簡(jiǎn)單工程,挖一挖里面的技術(shù)細(xì)節(jié)。
我在main.c文件中定義了隨便這幾個(gè)變量
int counter, accumulator = 0, limit_value = 1000000; unsigned char str_aa55[2] = {0xAA,0x55}; unsigned int int_1122334455667788 = 0x11223344; unsigned int int_55667788 = 0x55667788; int bss_val; void main(void) { }
然后,直接仿真查看,跟你我想的一樣,在main函數(shù)之前就初始化完成了,即這些變量都自動(dòng)初始化賦值了。
讓人好奇的是,它是怎么做到的?
單片機(jī)的啟動(dòng)程序一般都是很簡(jiǎn)單的,即使匯編也沒多少行,直接翻出來看看也許會(huì)知道答案。
-- Clear local RAM mov ___ghs_ramstart, r6 -- start of local RAM mov ___ghs_ramend, r7 -- end of local RAM mov r0, r1 1: st.dw r0, 0[r6] addi 8, r6, r6 cmp r7, r6 bl 1b -- Jump to the HW initialisation function jarl ___lowinit, lp -- Jump to the initialisation functions of the library -- and from there to main() jr __start
以上這段匯編,根據(jù)旁邊的注釋其實(shí)很容易理解,前半部分就是將內(nèi)存Local RAM初始化清零,即這段匯編可以見到梳理成
RAM清零--->執(zhí)行___lowinit--->執(zhí)行__start--->進(jìn)入main函數(shù)
既然前面給RAM清零了,那么此時(shí)的全局變量應(yīng)該全是0值吧,那可以推測(cè),給全局變量賦初始值應(yīng)該是在___lowinit或__start了,但是這兩個(gè)東西是編譯環(huán)境里某個(gè)庫(kù)的,暫時(shí)看不到源碼。
但是,最終通過仿真查看變量值的方式,可以定位,給全局變量賦初始值是在__start里面。
此時(shí),雖然我知道了它在哪里給全局變量初始化了,但是并不知道是怎樣初始化的。
我還是很好奇,本著刨根問底的精神繼續(xù)挖掘。
但是我在這個(gè)RH850的代碼工程里面是找不到這個(gè)__start的源碼內(nèi)容的,仿真看匯編折騰了半天,突然想了下,為啥不換個(gè)其他工程試試,例如試試NXP S32K的?
于是,我創(chuàng)建了一個(gè)NXP S32K1xx的代碼工程,仍然定義這幾個(gè)變量
int counter, accumulator = 0, limit_value = 1000000; unsigned char str_aa55[2] = {0xAA,0x55}; unsigned int int_1122334455667788 = 0x11223344; unsigned int int_55667788 = 0x55667788; intbss_val;同樣的討論,直接翻啟動(dòng)文件的匯編代碼
/* Init .data and .bss sections */ ldr r0,=init_data_bss blx r0還是歐美的芯片簡(jiǎn)單粗暴,不像小日子做的初始化還有藏進(jìn)庫(kù)里。這不是很明顯嘛,init_data_bss就是初始化全局變量的,以下截取了部分代碼,也很容易理解。
void init_data_bss(void) { /*......*/ /* Data */ data_ram = (uint8_t *)__DATA_RAM; data_rom = (uint8_t *)__DATA_ROM; data_rom_end = (uint8_t *)__DATA_END; /*......*/ /* BSS */ bss_start = (uint8_t *)__BSS_START; bss_end = (uint8_t *)__BSS_END; /* ...... */ /* Copy initialized data from ROM to RAM */ while (data_rom_end != data_rom) { *data_ram = *data_rom; data_ram++; data_rom++; } /* ...... */ /* Clear the zero-initialized data section */ while(bss_end != bss_start) { *bss_start = 0; bss_start++; } /*......*/ }
?
data段data_ram的初始化內(nèi)容就是從data_rom來,而data_rom是從__DATA_ROM來。
那么,__DATA_ROM是什么東西,從哪里呢?
搜一搜工程里面的代碼,很簡(jiǎn)單,這是從ld文件來
/* Specify the memory areas */ MEMORY { /* … */ /* SRAM_L */ m_data (RW) : ORIGIN = 0x1FFF8000, LENGTH = 0x00008000 m_data_2(RW):ORIGIN=0x20000000,LENGTH=0x00007000 /* … */ .data : AT(__DATA_ROM) { . = ALIGN(4); __DATA_RAM = .; __data_start__ = .; /* Create a global symbol at data start. */ *(.data) /* .data sections */ *(.data*) /* .data* sections */ . = ALIGN(4); __data_end__ = .; /* Define a global symbol at data end. */ } > m_data __DATA_END = __DATA_ROM + (__data_end__ - __data_start__); __CODE_ROM = __DATA_END; /* Symbol is used by code initialization. */ /* Uninitialized data section. */ .bss : { /* This is used by the startup in order to initialize the .bss section. */ . = ALIGN(4); __BSS_START = .; __bss_start__ = .; *(.bss) *(.bss*) *(COMMON) . = ALIGN(4); __bss_end__ = .; __BSS_END = .; } > m_data_2
這里簡(jiǎn)單介紹下,帶有初始化值(非0)全局變量(例如unsigned int int_55667788 = 0x55667788;),都是定義在data段的,而未定義初始化值的全局變量,是分在bss段的(例如intbss_val;)。
到底是不是我說的這樣子,直接查看map文件中的變量名和對(duì)應(yīng)地址或段名就知道了
.data 0x1fff8400 0x42c load address 0x000009cc 0x1fff8400 . = ALIGN (0x4) 0x1fff8400 __DATA_RAM = . 0x1fff8400 __data_start__ = . *(.data) *(.data*) .data.limit_value 0x1fff8400 0x4 ./src/main.o 0x1fff8400 limit_value .data.str_aa55 0x1fff8404 0x2 ./src/main.o 0x1fff8404 str_aa55 *fill* 0x1fff8406 0x2 .data.int_11223344 0x1fff8408 0x4 ./src/main.o 0x1fff8408 int_11223344 .data.int_55667788 0x1fff840c 0x4 ./src/main.o 0x1fff840c int_55667788 .bss 0x20000000 0x28 0x20000000 . = ALIGN (0x4) 0x20000000 __BSS_START = . 0x20000000 __bss_start__ = . *(.bss) *(.bss*) .bss.accumulator 0x2000001c 0x4 ./src/main.o 0x2000001c accumulator *(COMMON) COMMON 0x20000020 0x8 ./src/main.o 0x20000020 bss_val 0x20000024 counter 0x20000028 . = ALIGN (0x4) 0x20000028 __bss_end__ = . 0x20000028__BSS_END=. 0x000009cc__DATA_ROM=.
另外,從這map文件里也可以看到,這個(gè)__DATA_ROM對(duì)應(yīng)的地址是0x000009cc,也就是說,這些
int limit_value = 1000000; unsigned char str_aa55[2] = {0xAA,0x55}; unsigned int int_1122334455667788 = 0x11223344; unsigned int int_55667788 = 0x55667788;
等等變量的的初始值是來源于0x000009cc這里。
那就直接查看生成的hex文件
是不是很巧,是不是很妙?!
不過,還是很好奇,這是怎么做到的,怎么恰巧這些值就在這個(gè)地址呢?
秘密就在于ld文件里的這個(gè)語句:.data : AT(__DATA_ROM)
意思是,定義在data段的變量對(duì)應(yīng)的初始化值,就放在__DATA_ROM中。就這么簡(jiǎn)單,剩下的交給編譯器就行了。
這里順便提一下,排查跟蹤這些信息需要掌握編譯鏈接相關(guān)知識(shí),特別是鏈接腳本和生成的map內(nèi)容,我之前也跟我身邊的很多小伙伴講過這些內(nèi)容,但是我建議系統(tǒng)地看看這些內(nèi)容。我之前是無意中從《程序員的自我修養(yǎng)》這本書學(xué)到的,最大的感受就是讓我得到了啟發(fā),在往后的編程日子里更關(guān)注MCU地址、編譯和鏈接方面的內(nèi)容,對(duì)排查底層問題相當(dāng)有幫助。
S32K1的工程很清楚了,但是RH850的呢?一根筋的程序員,還是想知道__start到底干了啥?它所在的庫(kù)又是怎么鏈接進(jìn)來的,是怎么初始化的?
對(duì)這個(gè)問題一直記在心里,是一個(gè)化不開的結(jié)。終于某一天,我居然真的無意中發(fā)現(xiàn)了__start的源碼,感嘆小日子真的有一手。
這里涉及到的內(nèi)容比較多也比較復(fù)雜,后續(xù)再寫個(gè)文章講解下GreenHills編譯器的啟動(dòng)鏈接庫(kù)到底干了什么,敬請(qǐng)關(guān)注!
審核編輯:湯梓紅
-
單片機(jī)
+關(guān)注
關(guān)注
6043文章
44623瀏覽量
638833 -
嵌入式
+關(guān)注
關(guān)注
5094文章
19184瀏覽量
307900 -
仿真
+關(guān)注
關(guān)注
50文章
4126瀏覽量
134043 -
全局變量
+關(guān)注
關(guān)注
1文章
28瀏覽量
9003
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
嵌入式C編程經(jīng)驗(yàn):全局變量和常用工具軟件【轉(zhuǎn)】
謹(jǐn)慎使用局部變量和全局變量
請(qǐng)問STM32 C++類構(gòu)造函數(shù)怎么修改才能實(shí)現(xiàn)全局變量的初始化呢?
【原創(chuàng)分享】變量的初始化技巧
RAM的局部靜態(tài)變量和全局變量消耗
qboot跳轉(zhuǎn)APP,APP聲明全局變量時(shí)無法初始化?
static的全局變量與局部變量的使用,看完你就懂了
關(guān)于單片機(jī)全局變量初始化的問題
![關(guān)于單片機(jī)<b class='flag-5'>全局變量</b><b class='flag-5'>初始化</b>的問題](https://file1.elecfans.com//web2/M00/A6/F0/wKgZomUMQVuASH9GAAAmmv0u2SA610.png)
淺談變量在MCU中存儲(chǔ)位置
![淺談<b class='flag-5'>變量</b>在MCU中存儲(chǔ)位置](https://file1.elecfans.com//web2/M00/A7/46/wKgZomUMQ3uAa7DXAAAyT7A6vHU442.png)
在51平臺(tái)下初始化文件的引入導(dǎo)致全局變量無法初始化的問題如何解決
![在51平臺(tái)下<b class='flag-5'>初始化</b>文件的引入導(dǎo)致<b class='flag-5'>全局變量</b>無法<b class='flag-5'>初始化</b>的問題如何解決](https://file.elecfans.com/web1/M00/A4/1F/pIYBAF1bWr6AW1IIAAqjwPD92Tk888.png)
評(píng)論