欧美性猛交xxxx免费看_牛牛在线视频国产免费_天堂草原电视剧在线观看免费_国产粉嫩高清在线观看_国产欧美日本亚洲精品一5区

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

嵌入式全局變量的初始化原理詳解

嵌入式軟件實(shí)戰(zhàn)派 ? 來源: 嵌入式軟件實(shí)戰(zhàn)派 ? 2023-10-27 10:15 ? 次閱讀

最近,有個(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文件

f4fe89f4-746a-11ee-939d-92fbcf53809c.png



是不是很巧,是不是很妙?!

不過,還是很好奇,這是怎么做到的,怎么恰巧這些值就在這個(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)注!


審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 單片機(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
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    嵌入式C編程經(jīng)驗(yàn):全局變量和常用工具軟件【轉(zhuǎn)】

    嵌入式C編程經(jīng)驗(yàn):全局變量和常用工具軟件【轉(zhuǎn)】
    發(fā)表于 07-31 13:17

    謹(jǐn)慎使用局部變量全局變量

    取代連線板或用其訪問順序結(jié)構(gòu)中每一幀中的數(shù)值,可能在VI中導(dǎo)致不可預(yù)期的行為。濫用局部變量全局變量,如用來避免程序框圖間的過長(zhǎng)連線或取代數(shù)據(jù)流,將會(huì)降低執(zhí)行速度。 局部變量全局變量
    發(fā)表于 01-30 10:58

    請(qǐng)問STM32 C++類構(gòu)造函數(shù)怎么修改才能實(shí)現(xiàn)全局變量初始化呢?

    全部為0)。 當(dāng)把全局變量改為函數(shù)內(nèi)部的臨時(shí)變量時(shí),是有效的。猜想是因?yàn)槌绦驅(qū)懙紽LASH上去了,全局變量都為0,而不考慮對(duì)應(yīng)類的構(gòu)造函數(shù)。需要怎么修改才能實(shí)現(xiàn)全局變量
    發(fā)表于 10-10 08:45

    【原創(chuàng)分享】變量初始化技巧

    由于在嵌入式系統(tǒng)中必須考慮程序規(guī)模的問題,因此,對(duì)程序中的變量初始化也需要進(jìn)行慎重的考慮。在C語言中,基本數(shù)據(jù)結(jié)構(gòu)(字符型、整型)的初始化相對(duì)簡(jiǎn)單;數(shù)組、結(jié)構(gòu)體屬于C語言中的構(gòu)造類型
    發(fā)表于 09-08 15:28

    RAM的局部靜態(tài)變量全局變量消耗

    因?yàn)樵谶B接時(shí),全局變量和局部靜態(tài)變量都是在data區(qū),所以在這里給放一起討論了。在原文中自己的表述犯了一個(gè)錯(cuò)誤,就是初始化全局變量或者局部靜態(tài)變量
    發(fā)表于 11-03 08:54

    qboot跳轉(zhuǎn)APP,APP聲明全局變量時(shí)無法初始化?

    1、程序添加了kawaii_mqtt軟件包2、聲明全局變量時(shí)進(jìn)行初始化,程序無法跳轉(zhuǎn)3、聲明全局變量時(shí)不初始化,在函數(shù)中初始化,則程序正常跳
    發(fā)表于 03-06 10:32

    static的全局變量與局部變量的使用,看完你就懂了

    函數(shù)體內(nèi)聲明的自動(dòng)變量的值是隨機(jī)的,除非它被顯初始化,而在函數(shù)體外被聲明的自動(dòng)變量也會(huì)被初始化為 0); (3)靜態(tài)
    發(fā)表于 06-27 08:54

    關(guān)于單片機(jī)全局變量初始化的問題

    變量分為局部與全局,局部變量又可稱之為內(nèi)部變量。由某對(duì)象或某個(gè)函數(shù)所創(chuàng)建的變量通常都是局部變量,
    發(fā)表于 11-22 15:16 ?5450次閱讀
    關(guān)于單片機(jī)<b class='flag-5'>全局變量</b><b class='flag-5'>初始化</b>的問題

    淺談變量在MCU中存儲(chǔ)位置

    全局區(qū)(靜態(tài)區(qū))(static)—,全局變量和靜態(tài)變量的存儲(chǔ)是放在一塊的,初始化全局變量和靜態(tài)變量
    發(fā)表于 05-07 17:49 ?4207次閱讀
    淺談<b class='flag-5'>變量</b>在MCU中存儲(chǔ)位置

    在51平臺(tái)下初始化文件的引入導(dǎo)致全局變量無法初始化的問題如何解決

    本文檔的主要內(nèi)容詳細(xì)介紹的是在51平臺(tái)下初始化文件的引入導(dǎo)致全局變量無法初始化的問題如何解決。
    發(fā)表于 08-20 17:31 ?0次下載
    在51平臺(tái)下<b class='flag-5'>初始化</b>文件的引入導(dǎo)致<b class='flag-5'>全局變量</b>無法<b class='flag-5'>初始化</b>的問題如何解決

    分析如何遠(yuǎn)離漫天飛舞的全局變量

    來源:嵌入式大雜燴 前篇 《由static來談?wù)勀K封裝》 基本實(shí)現(xiàn)了對(duì)外隱藏屬性,隱藏局部模塊函數(shù),開放接口的功能。對(duì)于這個(gè)話題還有些點(diǎn)沒有深入探討:為什么要這樣做?以及這樣做的好處。或許很多
    的頭像 發(fā)表于 09-15 13:49 ?1704次閱讀

    C語言中局部變量全局變量

    全局變量也稱為外部變量,它是在函數(shù)外部定義的變量。它不屬于哪一個(gè)函數(shù),它屬于一個(gè)源程序文件。其作用域是整個(gè)源程序。在函數(shù)中使用全局變量,一般應(yīng)作全局
    的頭像 發(fā)表于 10-15 10:48 ?5663次閱讀

    鴻蒙內(nèi)核源碼:內(nèi)核空間是怎么初始化的?

    data段 該段用于存儲(chǔ)初始化全局變量,初始化為0的全局變量出于編譯優(yōu)化的策略還是被保存在BSS段。
    的頭像 發(fā)表于 04-26 14:43 ?1927次閱讀
    鴻蒙內(nèi)核源碼:內(nèi)核空間是怎么<b class='flag-5'>初始化</b>的?

    詳解LABVIEW中的局部變量全局變量

    本文檔的主要內(nèi)容詳細(xì)介紹的是LABVIEW初級(jí)教程之局部變量全局變量的詳細(xì)資料說明。
    發(fā)表于 03-29 15:00 ?26次下載

    嵌入式C編程中全局變量問題分享

    嵌入式特別是單片機(jī)os-less的程序,最易范的錯(cuò)誤是全局變量滿天飛。這個(gè)現(xiàn)象在早期匯編轉(zhuǎn)型過來的程序員以及初學(xué)者中常見,這幫家伙幾乎把全局變量當(dāng)作函數(shù)形參來用。
    發(fā)表于 07-17 16:53 ?774次閱讀