关于嵌入式系统内存地址空间的一些疑问(.text、.data、.bass、堆\栈空间)
深入淺出了解(.text、.data、.bss、堆空間、棧空間)的含義
接下來所說的是嵌入式系統(tǒng)的內(nèi)存地址空間的布局,簡單的說就是我們寫好的代碼,在編譯過程種中,把代碼里不同的變量、函數(shù)相應(yīng)的保存在每個(gè)段中(.text、.data、.bss),至于堆空間、棧空間是代碼在芯片上運(yùn)行時(shí)才存在的。
那么問題1,什么樣的數(shù)據(jù)會(huì)保存在.text段里?.data段?.bss段?棧空間?堆空間?
答:下面舉例說明:
unsigned char gvCh;//全局變量,沒有初值,放在.bss段中 unsigned short gvShort;// 全局變量,沒有初值,放在.bss段中 unsigned int gvInt = 0x12345678;//全局變量,有初值,放在.data段中 unsigned long gvLong = 0x87654321; //全局變量,有初值,放在.data段中int main(void)//main函數(shù)在經(jīng)過編譯以后得到的機(jī)器代碼,存放在.text代碼段當(dāng)中 {unsigned char arry[10],*p;//局部變量,存放在棧當(dāng)中p = malloc(10*sizeof(char));//p指針變量指向的空間,存放在堆當(dāng)中while(1); }補(bǔ)充:上面定義的全局變量沒有在代碼上引用,這里只是舉例,如果在實(shí)際應(yīng)用中,它們會(huì)被編譯器優(yōu)化掉,那么它們根本就不會(huì)占用內(nèi)存空間。
問題2,上面的例子可能只是給你解開了一部分疑惑,如果用上變量修飾詞static、const,那么它們又是怎么存儲(chǔ)的呢?
答:下面舉例說明:
static unsigned char gvCh;//全局變量,只能在本文件內(nèi)引用,沒有初值,放在.bss段中 const unsigned short gvShort;//全局變量,不可修改(只讀),放在.data段中。實(shí)際不會(huì)定義無初值的const變量 static unsigned int gvInt = 0x12345678;//全局變量,只能在本文件內(nèi)引用,有初值,放在.data段中 const unsigned long gvLong = 0x87654321;//全局變量,不可修改(只讀),放在.data段中。int main(void) {static unsigned char lvCh;//加上static的局部變量,只能在本函數(shù)內(nèi)引用,函數(shù)結(jié)束回時(shí)不會(huì)消失,沒有初值,放在.bss段中const unsigned short lvShort;//加上const的局部變量,不可修改(只讀),放在.data段中。實(shí)際不會(huì)定義無初值的const變量static unsigned int lvInt = 0x12345678;//加上static的局部變量,只能在本函數(shù)內(nèi)引用,函數(shù)結(jié)束回時(shí)不會(huì)消失,有初值,放在.data段中const unsigned long lvLong = 0x87654321//加上const局部變量,不可修改(只讀),放在.data段中while(1); }總結(jié),如果變量加上const,不管是全局變量還是局部變量,不管有沒有初值,都保存在.data段。如果變量加上static,不會(huì)影響變量所保存的段,static的作用是改變變量的作用域。
問題3,我們了解完怎么樣的變量該保存到什么段,或許還會(huì)有疑惑,.data段的數(shù)據(jù)和.bss段的數(shù)據(jù)有什么區(qū)別?把數(shù)據(jù)這么區(qū)分出來的作用是什么?
答:原因其實(shí)很簡單,就是為了節(jié)省編譯出來的bin文件占用的內(nèi)存大小。.data段變量的值會(huì)記錄在bin二進(jìn)制文件中,而.bss記錄的是變量的起始地址和大小,在程序運(yùn)行時(shí)初始化為零。下舉例說明:
unsigned char gvCh_init[3] = {1,2,3}; //.data段,如果數(shù)組增大100字節(jié),那么bin文件大小會(huì)也會(huì)隨之增大 unsigned char gvCh_no_init[3];//.bss段,如果數(shù)組增大為100字節(jié),那么bin文件大小不會(huì)發(fā)生變化,在bin文件里只是記錄這個(gè)數(shù)組的起始地址和大小,當(dāng)程序運(yùn)行時(shí)自動(dòng)把它的值清零。問題4,unsigned chat gvCh[100] ={0};算不算給數(shù)組gvCh設(shè)置了初值而被保存在.data段,將占用bin文件大小?
答:在IAR編譯器里,unsigned chat gvCh[100] ={0}等同于unsigned chat gvCh[100],保存于.bss段。
問題5,我們知道在芯片上有ROM存儲(chǔ)器和RAM存儲(chǔ)器,在程序bin文件燒錄到芯片上時(shí),不同的段會(huì)如何存在于在ROM和RAM里呢?
答:沒有一一對(duì)應(yīng)的關(guān)系。因?yàn)槲铱梢园裝in文件燒錄到flash(ROM)里面運(yùn)行,也可以把它燒錄到RAM里面運(yùn)行(調(diào)試時(shí)會(huì)這么做)。
通常地,我們會(huì)把編譯好的程序燒錄到flash(ROM)里面去,芯片掉電時(shí)不會(huì)消失;對(duì)于RAM存儲(chǔ)器來說,只有芯片上電代碼運(yùn)行起來,才會(huì)被分配使用(棧/堆就是在RAM開辟的)。
問題6,代碼中的變量會(huì)以什么樣的規(guī)則存在于ROM存儲(chǔ)器和RAM存儲(chǔ)器里?
答:主要根據(jù)變量在運(yùn)行時(shí)是否可修改,下面舉例說明:
unsigned char gvCh;可讀寫,存放在RAM(無初始值,.bss段) unsigned int gvInt = 0x12345678;//可讀寫,存放在RAM(有初始值,.data段) const unsigned long gvLong = 0x87654321; //只讀,存放在ROMint main1(void)//main函數(shù)在經(jīng)過編譯以后得到的機(jī)器代碼,不可修改,存放ROM {unsigned char arry[10],*p;//可讀寫,存放在棧當(dāng)中,也就是在RAM中p = malloc(10*sizeof(char));//p指針變量指向的空間,存放在堆當(dāng)中,也就是在RAM中while(1); }有初始值、并且可讀寫的全局變量gvInt存放在RAM,但我們知道在RAM的數(shù)據(jù)掉電會(huì)丟失,其實(shí)它的初始值0x12345678一開始保存在flash(ROM)里,在芯片上電時(shí),會(huì)將初始值復(fù)制到RAM里的gvInt變量(它所在RAM的地址在編譯后已經(jīng)確定)。可能我們會(huì)疑惑,自己的代碼明明沒有寫給gvInt變量賦值的過程,這一部分代碼并不需要我們做。芯片上電就會(huì)進(jìn)入Reset_Handler中斷,打開.s啟動(dòng)文件,我們可以發(fā)現(xiàn)在Reset_Handler中斷里,調(diào)用了SystemInit函數(shù),然后再調(diào)用了_main(IAR編譯器的話是__iar_program_start)函數(shù),在_main函數(shù)會(huì)進(jìn)行RW data的復(fù)制,和.bss段的初始化,以及C庫函數(shù)的初始化(比如malloc函數(shù)需要初始化才能使用),進(jìn)而調(diào)用main函數(shù)進(jìn)入我們的代碼區(qū)域。
?
總結(jié)
以上是生活随笔為你收集整理的关于嵌入式系统内存地址空间的一些疑问(.text、.data、.bass、堆\栈空间)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于IAR-stm32裸板工程,完美移植
- 下一篇: C语言实现中国象棋(Qt实现界面,源码下