在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

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

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

詳解C語言程序內存分區(qū)

STM32嵌入式開發(fā) ? 來源:STM32嵌入式開發(fā) ? 2023-06-11 17:29 ? 次閱讀

每一個C語言源程序,都將最終經過這一處理而得到相應的目標文件。目標文件中所存放的也就是與源程序等效的目標的機器語言代碼。目標文件由段組成。通常一個目標文件中至少有兩個段(segment):

代碼段:該段中所包含的主要是程序的指令。該段一般是可讀和可執(zhí)行的,但一般卻不可寫。

數(shù)據段:主要存放程序中要用到的各種全局變量或靜態(tài)的數(shù)據。一般數(shù)據段都是可讀,可寫,可執(zhí)行的。

1 目標文件結構

目標文件是源代碼編譯但未鏈接的中間文件(Windows的.obj和Linux的.o),Windows的.obj采用 PE 格式,Linux 采用 ELF 格式,兩種格式均是基于通用目標文件格式(COFF,Common Object File Format)變化而來,所以二者大致相同。

目標文件一般包含編譯后的機器指令代碼、數(shù)據、調試信息,還有鏈接時所需要的一些信息,比如重定位信息和符號表等,而且一般目標文件會將這些不同的信息按照不同的屬性,以“節(jié)(section)”也叫“段(segment)”的形式進行存儲。


#include 
#include 


int gInitVar = 1;           // .data   加載階段加載
int gUninitVar;             // .bss    加載階段加載
const int gConstVar = 2;    // .rdata  加載階段加載
// extern可以修飾const用于擴展文件鏈接性,const默認是文件內鏈接的
// static修飾全局變量可以限制其文件鏈接性,其存儲屬性不變
void foo(int i)             // .text   加載階段加載
{
    static int staticLocalInitVar = 3;  // .data  加載階段加載
    static int staticLocalUninitVar;    // .bss   加載階段加載
    int stack_localVar = 4;             // 棧幀(每個程序運行時會加載1-2M棧空間)
    const int LocalConstVar = 5;        // 棧幀(運行時自動分配)
    staticLocalUninitVar = LocalConstVar + gConstVar;
    gUninitVar = staticLocalInitVar + gInitVar;
    int *dynamic_heapData = (int*)malloc(sizeof(int)*10000000);
    dynamic_heapData[10000000-1] = 9;   // 堆區(qū)(運行時動態(tài)申請)
    i += stack_localVar + staticLocalUninitVar + gUninitVar; 
    printf("%d
",i+dynamic_heapData[10000000-1]);// .rdata,加載階段加載"%d
"
    free(dynamic_heapData);             // 堆內存需要顯式釋放
}                                       // 棧內存在超出作用域后自動釋放
int main()
{
    foo(6);
    getchar();
    return 0;
}                                       // 加載階段加載的內存要等到程序結束才釋放


文件的內容分割為不同的區(qū)塊(Setion,又稱區(qū)段,節(jié)等),區(qū)段中包含代碼數(shù)據,各個區(qū)塊按照頁邊界來對齊,區(qū)塊沒有限制大小,是一個連續(xù)的結構。每塊都有他自己在內存中的屬性,比如:這個塊是否可讀可寫,或者只讀等等。

①.text代碼段

代碼段存放程序的機器指令;

② .data已初始化數(shù)據段

初始化數(shù)據段存放已初始化的全局變量與局部靜態(tài)變量;

③ .bss未初始化數(shù)據段

未初始化局部靜態(tài)變量(或初始化為0的局部靜態(tài)變量)放到.bss段,對于未初始化全局變量(或初始化為0的全局變量),不同語言與編譯器的實現(xiàn)有不同的處理,有的只是在.baa段預留一個未定義的全局變量符號,等到最終鏈接成可執(zhí)行文件的時候再在 .bss 段分配空間。編譯器會把未初始化的全局變量標記為一個 COMMON 符號,不為其在 .bss 段分配空間的原因是現(xiàn)在的編譯器和鏈接器支持弱符號機制,即允許同一個弱符號定義在多個目標文件中,因為未初始化的全局變量屬于弱符號,編譯時無法確定符號大小,所以此時無法在 .bss 段為未初始化的全局變量分配空間。

④ .rdata或.rodata只讀數(shù)據段

只讀數(shù)據段存放程序中只讀變量,如const修飾的常量和字符串常量;

單獨設立.rodata段的好處有很多,比如語義上支持了C的const常量,而且操作系統(tǒng)在加載的時候可以將.rodata段的內容映射為只讀區(qū),這樣對于這個段的任何修改都會被判為非法,保證了程序的安全性。

⑤ .symtab符號表段

.symtab段用于存符號表。每個目標文件都有一個相應的符號表(Symbol Table),記錄了目標文件中用到的所有符號。每個符號都有一個對應的值,叫做符號值(Symbol Value),符號值可以是符號所對應的數(shù)據在段中的偏移量,也可以是該符號的對齊屬性。

鏈接過程的本質就是要把多個不同的目標文件之間像拼圖一樣拼起來,相互拼合實際上是目標文件之間對地址的引用,即對函數(shù)和變量的地址的引用。比如目標文件B用到了目標文件A中的函數(shù)foo,那么稱目標文件A定義了函數(shù)foo,目標文件B引用了函數(shù)foo。定義與引用這兩個概念同樣適用于變量。每個函數(shù)和變量都有自己獨一的名字,才能避免鏈接過程中不同變量和函數(shù)之間的混淆。在鏈接中,我們將函數(shù)和變量統(tǒng)稱為符號(Symbol),函數(shù)或變量名就是符號名(Symbol Name)。

符號是鏈接的粘合劑,沒有符號就無法完成鏈接。每一個目標文件都會有一個相應的符號表(Symbol Table),這個表里記錄了目標文件中所用到的所有符號。每個定義的符號有一個對應的值叫做符號值(Symbol Value),對于變量和函數(shù)來說,符號值就是它們的地址。

除了函數(shù)和變量之外,還存在其它幾種不常用到的符號。符號表中的符號可分為全局符號、局部符號、段名、行號等,對于鏈接而言,只關心全局符號。

⑥.strtab字符串表

因為字符串的長度往往是不定的,所以用固定的結構來表示它比較困難。一種很常見的做法是把字符串集中起來存放到一個表,然后使用字符串在表中的偏移來引用字符串(在匯編中使用offset)。


7:        char * stringLiteral = "stringLiteral";
00401038   mov         dword ptr [ebp-4],offset string "stringLiteral" (004230c0)


⑦.rela.text代碼段重定位表

重定位表,也叫作重定位段,用于鏈接器在處理目標文件時,重定位代碼段中那些對絕對地址的引用的位置。比如 .text 段中對外部 printf() 函數(shù)的調用。每個要被重定位的地方叫重定位入口(Relocation Entry),OFFSET 表示該入口在所在段中的偏移位置,TYPE 表示重定位入口的類型,VALUE 表示重定位入口的符號名稱。

2 加載與執(zhí)行

項目全部相關文件最終會由鏈接器鏈接到一起形成一個可執(zhí)行文件,Linux 系統(tǒng)中的每個可執(zhí)行文件都運行在一個進程上下文中,有自己的虛擬地址空間。當shell 運行一個程序時,父shell 進程生成一個子進程,它是父進程的一個復制。

子進程通過系統(tǒng)調用啟動加載器。加載器刪除子進程現(xiàn)有的虛擬內存段,并創(chuàng)建一組新的代碼、數(shù)據、堆和棧段。新的棧和堆段被初始化為零。通過將虛擬地址空間中的頁映射到可執(zhí)行文件的頁大小的片(chunk), 新的代碼和數(shù)據段被初始化為可執(zhí)行文件的內容。最后,加載器跳轉到_start地址,它最終會調用應用程序的main 函數(shù)。

1a43e22c-0837-11ee-962d-dac502259ad0.png

一個系統(tǒng)中的進程是與其他進程共享CPU和主存資源的。然而,共享主存會形成一些特殊的挑戰(zhàn)。如果太多的進程需要太多的內存,那么它們中的一些就根本無法運行。當一個程序沒有空間可用時,那就是它運氣不好了。內存還很容易被破壞。如果某個進程不小心寫了另一個進程使用的內存,它就可能以某種完全和程序邏輯無關的令人迷惑的方式失敗。

為了更加有效地管理內存并且少出錯,現(xiàn)代系統(tǒng)提供了一種對主存的抽象概念,叫做虛擬內存(VM)。虛擬內存是硬件異常、硬件地址翻譯、主存、磁盤文件和內核軟件的完美交互,它為每個進程提供了一個大的、一致的和私有的地址空間。通過一個很清晰的機制,虛擬內存提供了三個重要的能力:

1) 它將主存看成是一個存儲在磁盤上的地址空間的高速緩存,在主存中只保存活動區(qū)域,并根據需要在磁盤和主存之間來回傳送數(shù)據,通過這種方式,它高效地使用了主存。

2) 它為每個進程提供了一致的地址空間,從而簡化了內存管理。

3) 它保護了每個進程的地址空間不被其他進程破壞。

虛擬內存是計算機系統(tǒng)最重要的概念之一。它成功的一個主要原因就是因為它是沉默地、自動地工作的,不需要應用程序員的任何干涉。

1a6a8ee0-0837-11ee-962d-dac502259ad0.png

3 匯編代碼分析

看以下源代碼與匯編代碼的對應,以及數(shù)據(變量)對應的地址值:


1:    #include 
2:    #include 
3:
4:    int gInitVar = 1;           // .data   加載階段加載,所以這里無匯編對應
5:    int gUninitVar;             // .bss    加載階段加載
6:    const int gConstVar = 2;    // .rdata  加載階段加載
7:
8:    void foo(int i)             // .text   加載階段加載
9:    {
00401020   push        ebp
00401021   mov         ebp,esp
00401023   sub         esp,4Ch
00401026   push        ebx
00401027   push        esi
00401028   push        edi
00401029   lea         edi,[ebp-4Ch]
0040102C   mov         ecx,13h
00401031   mov         eax,0CCCCCCCCh
00401036   rep stos    dword ptr [edi]
10:       static int staticLocalInitVar = 3;  // .data  加載階段加載,所以這里無匯編對應
11:       static int staticLocalUninitVar;    // .bss   加載階段加載
12:       int stack_localVar = 4;             // 棧幀(每個程序運行時會加載若干M棧空間)
00401038   mov         dword ptr [ebp-4],4 // 局部變量保存在棧上,由ebp及其偏移表示
13:       const int LocalConstVar = 5;        // 棧幀(運行時自動分配)
0040103F   mov         dword ptr [ebp-8],5 // 局部常量放在棧區(qū)
14:       staticLocalUninitVar = LocalConstVar + gConstVar;
00401046   mov         dword ptr [gUninitVar+4 (00428e40)],7
15:       gUninitVar = staticLocalInitVar + gInitVar;
00401050   mov         eax,[global_data+4 (00425a34)]
00401055   add         eax,dword ptr [gInitVar (00425a30)]
0040105B   mov         [gUninitVar (00428e3c)],eax
16:       int *dynamic_heapData = (int*)malloc(sizeof(int)*10000000);
00401060   push        2625A00h
00401065   call        malloc (00401190)
0040106A   add         esp,4
0040106D   mov         dword ptr [ebp-0Ch],eax
17:       dynamic_heapData[10000000-1] = 9;   // 堆區(qū)(運行時動態(tài)申請)
00401070   mov         ecx,dword ptr [ebp-0Ch]
00401073   mov         dword ptr [ecx+26259FCh],9
18:       i += stack_localVar + staticLocalUninitVar + gUninitVar;
0040107D   mov         edx,dword ptr [ebp-4]
00401080   add         edx,dword ptr [gUninitVar+4 (00428e40)]
00401086   add         edx,dword ptr [gUninitVar (00428e3c)]
0040108C   mov         eax,dword ptr [ebp+8]
0040108F   add         eax,edx
00401091   mov         dword ptr [ebp+8],eax
19:       printf("%d
",i+dynamic_heapData[10000000-1]);// .rdata,加載階段加載"%d
"
00401094   mov         ecx,dword ptr [ebp-0Ch]
00401097   mov         edx,dword ptr [ebp+8]
0040109A   add         edx,dword ptr [ecx+26259FCh]
004010A0   push        edx
004010A1   push        offset string "xd4xcbxd0xd0xbdxd7xb6xcexa3xbaxb6xafxccxacxc9xeaxc7xeb
004010A6   call        printf (00403110)
004010AB   add         esp,8
20:       free(dynamic_heapData);             // 堆內存需要顯式釋放
004010AE   mov         eax,dword ptr [ebp-0Ch]
004010B1   push        eax
004010B2   call        free (00401c10)
004010B7   add         esp,4
21:   }                                       // 棧內存在超出作用域后自動釋放





審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • Linux系統(tǒng)

    關注

    4

    文章

    595

    瀏覽量

    27451
  • C語言
    +關注

    關注

    180

    文章

    7614

    瀏覽量

    137257
  • 虛擬機
    +關注

    關注

    1

    文章

    919

    瀏覽量

    28325
  • 類加載器
    +關注

    關注

    0

    文章

    6

    瀏覽量

    937

原文標題:理解C語言程序內存分區(qū)

文章出處:【微信號:c-stm32,微信公眾號:STM32嵌入式開發(fā)】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    一文詳解C語言內存管理

    C語言內存管理指對系統(tǒng)內存的分配、創(chuàng)建、使用這一系列操作。
    發(fā)表于 07-26 16:04 ?720次閱讀
    一文<b class='flag-5'>詳解</b><b class='flag-5'>C</b><b class='flag-5'>語言</b><b class='flag-5'>內存</b>管理

    C語言程序設計中動態(tài)內存分配如何實現(xiàn)

    C語言程序設計中,動態(tài)內存分配如何實現(xiàn),需要注意哪些問題?
    發(fā)表于 09-28 16:53 ?1421次閱讀

    C語言內存管理詳解

    C語言內存管理詳解,很不錯的一份資料.
    發(fā)表于 08-06 23:14

    C語言指針詳解

    ];//指針的類型是 int(*)[3] (5)int*(*ptr)[4];//指針的類型是int*(*)[4] 怎么樣?找出指針的類型的方法是不是很簡單? 完整的C語言指針詳解pdf格式文檔電子發(fā)燒友下載地址(共12
    發(fā)表于 07-04 03:34

    c語言指針詳解

    被回收了,則這個數(shù)據就“消亡了”。C語言中的程序數(shù)據會按照他們定義的位置,數(shù)據的種類,修飾的關鍵字等因素,決定他們的生命周期特性。實質上我們程序使用的
    發(fā)表于 03-26 09:51

    單片機C語言程序與數(shù)據存儲的相關資料分享

    目錄:一、五大內存分區(qū)二、C語言程序的存儲區(qū)域三、C語言
    發(fā)表于 11-30 06:48

    程序設計之內存管理

    使用C語言編程時,關于程序設計之內存管理。
    發(fā)表于 05-20 17:01 ?0次下載

    ARM_C語言程序設計詳解

    ARM_C語言程序設計詳解
    發(fā)表于 10-27 15:39 ?32次下載
    ARM_<b class='flag-5'>C</b><b class='flag-5'>語言</b><b class='flag-5'>程序</b>設計<b class='flag-5'>詳解</b>

    C語言的精髓——指針詳解

    C語言的精髓——指針詳解
    發(fā)表于 11-30 14:43 ?17次下載

    存儲器的分區(qū)內存管理與分區(qū)存儲管理

    內存固定地劃分為若干個大小不等的分區(qū)供各個程序使用,每個分區(qū)的大小和位置都固定,系統(tǒng)運行期間不再重新劃分。
    發(fā)表于 05-26 10:28 ?3167次閱讀
    存儲器的<b class='flag-5'>分區(qū)內存</b>管理與<b class='flag-5'>分區(qū)</b>存儲管理

    使用單片機實現(xiàn)62256擴展內存C語言程序免費下載

    本文檔的主要內容詳細介紹的是使用單片機實現(xiàn)62256擴展內存C語言程序免費下載。
    發(fā)表于 03-16 14:39 ?12次下載

    單片機C語言程序與數(shù)據存儲

    目錄:一、五大內存分區(qū)二、C語言程序的存儲區(qū)域三、C語言
    發(fā)表于 11-20 20:36 ?12次下載
    單片機<b class='flag-5'>C</b><b class='flag-5'>語言</b><b class='flag-5'>程序</b>與數(shù)據存儲

    C語言程序編譯后內存地址的分配

    本文目的是簡要介紹C語言編譯得到的可執(zhí)行文件加載到內存運行時不同變量分配的存儲位置,并通過在Ubuntu 18.04系統(tǒng)和STM32系統(tǒng)上進行編程驗證C
    發(fā)表于 01-13 14:23 ?1次下載
    <b class='flag-5'>C</b><b class='flag-5'>語言</b><b class='flag-5'>程序</b>編譯后<b class='flag-5'>內存</b>地址的分配

    C語言內存問題如何解決

    大家好,我是雜燴君。 C 語言內存問題,難在于定位,定位到了就好解決了。 這篇筆記我們來聊聊踩內存。踩內存,通過字面理解即可。本來是操作這一
    的頭像 發(fā)表于 06-22 11:37 ?472次閱讀
    <b class='flag-5'>C</b><b class='flag-5'>語言</b><b class='flag-5'>內存</b>問題如何解決

    C語言內存泄漏問題原理

    內存泄漏問題只有在使用堆內存的時候才會出現(xiàn),棧內存不存在內存泄漏問題,因為棧內存會自動分配和釋放。C
    發(fā)表于 03-19 11:38 ?557次閱讀
    <b class='flag-5'>C</b><b class='flag-5'>語言</b><b class='flag-5'>內存</b>泄漏問題原理
    主站蜘蛛池模板: 性欧美大战久久久久久久| 性福利视频| 丁香六月啪啪| 操熟逼| 欧美一区二区三区不卡免费观看| 午夜.dj高清在线观看免费8| 男校霸把男校草玩出水男男| 伊人久久综合网站| 四虎国产精品永久地址49| 秋霞一级特黄真人毛片| 毛片韩国| ww欧洲ww在线视频免费观看| 天天曰天天干天天操| 国产夜夜操| 美女免费视频是黄的| 久久综合久久久| 操操久久| 色天天天天| 国产成人啪午夜精品网站| 精品国产麻豆免费人成网站| 婷婷久久综合网| 看天堂| 永久免费看片| 久操久操| 亚洲日本一区二区三区在线不卡| 亚洲综合成人在线| 最好看的2019中文字幕免费高清| 亚洲色图图片区| 亚洲成网| 亚洲3级| 你懂在线| 中文永久免费看电视网站入口| 啊用力太猛了啊好深视频免费| 天天干天天色综合网| 午夜aa| 一级做a爰片久久毛片图片| 欧美一级特黄啪啪片免费看| 爱婷婷视频在线观看| 国产综合13p| 狠狠色噜噜狠狠狠狠五月婷| 如色网|