<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          C程序內(nèi)存布局

          共 4267字,需瀏覽 9分鐘

           ·

          2021-12-28 00:57

          作為計(jì)算機(jī)專業(yè)的來說,程序入門基本都是從C語言開始的,了解C程序中的內(nèi)存布局,對我們了解整個(gè)程序運(yùn)行,分析程序出錯(cuò)原因,會(huì)起到事半功倍的作用 。

          C程序的內(nèi)存布局包含五個(gè)段,分別是STACK(棧段),HEAP(堆段),BSS(以符號開頭的塊),DS(數(shù)據(jù)段)和TEXT(文本段)。

          每個(gè)段都有自己的讀取,寫入和可執(zhí)行權(quán)限。如果程序嘗試以不允許的方式訪問內(nèi)存,則會(huì)發(fā)生段錯(cuò)誤,也就是我們常說的coredump。

          段錯(cuò)誤是導(dǎo)致程序崩潰的常見問題。核心文件(核心轉(zhuǎn)儲文件)也與段錯(cuò)誤相關(guān)聯(lián),開發(fā)人員使用該文件來查找崩潰的根本原因(段錯(cuò)誤)。

          下面我們將深入這五個(gè)段,更加詳細(xì)的講解每個(gè)段在程序開發(fā)或者運(yùn)行中的作用。

          High?Addresses?--->?.----------------------.
          ????????????????????|??????Environment?????|
          ????????????????????|----------------------|
          ????????????????????|??????????????????????|???Functions?and?variable?are?declared
          ????????????????????|?????????STACK????????|???on?the?stack.
          base?pointer?->?????|?-?-?-?-?-?-?-?-?-?-?-|
          ????????????????????|???????????|??????????|
          ????????????????????|???????????v??????????|
          ????????????????????:??????????????????????:
          ????????????????????.??????????????????????.???The?stack?grows?down?into?unused?space
          ????????????????????.?????????Empty????????.???while?the?heap?grows?up.?
          ????????????????????.??????????????????????.
          ????????????????????.??????????????????????.???(other?memory?maps?do?occur?here,?such?
          ????????????????????.??????????????????????.????as?dynamic?libraries,?and?different?memory
          ????????????????????:??????????????????????:????allocate)
          ????????????????????|???????????^??????????|
          ????????????????????|???????????|??????????|
          ?brk?point?->???????|?-?-?-?-?-?-?-?-?-?-?-|???Dynamic?memory?is?declared?on?the?heap
          ????????????????????|??????????HEAP????????|
          ????????????????????|??????????????????????|
          ????????????????????|----------------------|
          ????????????????????|??????????BSS?????????|???Uninitialized?data?(BSS)
          ????????????????????|----------------------|???
          ????????????????????|??????????Data????????|???Initialized?data?(DS)
          ????????????????????|----------------------|
          ????????????????????|??????????Text????????|???Binary?code
          Low?Addresses?---->?'----------------------'

          • 它位于較高的地址,與堆段的增長和收縮方向正好相反。
          • 函數(shù)的局部變量存在于棧上
          • 調(diào)用函數(shù)時(shí),將在棧中創(chuàng)建一個(gè)棧幀。
          • 每個(gè)函數(shù)都有一個(gè)棧幀。
          • 棧幀包含函數(shù)的局部變量參數(shù)和返回值。
          • 函數(shù)變量在調(diào)用時(shí)被壓入棧,返回時(shí)將函數(shù)變量從棧彈出。
          • SP(棧指針)寄存器指向棧的頂部。
          #include?
          int?main(void)?{
          ????int?data;?//?局部變量,存儲在棧上
          ????return?0;
          }

          • 用于在運(yùn)行時(shí)分配內(nèi)存。
          • 由內(nèi)存管理函數(shù)(如malloc、calloc、free等)管理的堆區(qū)域,這些函數(shù)可以在內(nèi)部使用brk和sbrk系統(tǒng)調(diào)用來調(diào)整其大小。
          • 堆區(qū)域由進(jìn)程中的所有共享庫和動(dòng)態(tài)加載的模塊共享。
          • 它在堆棧的相反方向上增長和收縮。
          #include?
          int?main(void)?{
          ????char?*pStr?=?malloc(sizeof(char)*4);?//pStr指向堆地址
          ????return?0;
          }

          BSS(未初始化的數(shù)據(jù)塊)

          • 包含所有未初始化的全局和靜態(tài)變量。
          • 此段中的所有變量都由零或者空指針初始化。
          • 程序加載器在加載程序時(shí)為BSS節(jié)分配內(nèi)存。
          #include?
          int?data1;?//?未初始化的全局變量存儲在BSS段
          int?main(void)?{
          ????static?int?data2;??//?未初始化的靜態(tài)變量存儲在BSS段
          ????return?0;
          }

          DS(初始化的數(shù)據(jù)塊)

          • 包含顯式初始化的全局變量和靜態(tài)變量。
          • 此段的大小由程序源代碼中值的大小決定,在運(yùn)行時(shí)不會(huì)更改。
          • 它具有讀寫權(quán)限,因此可以在運(yùn)行時(shí)更改此段的變量值。
          • 該段可進(jìn)一步分為初始化只讀區(qū)和初始化讀寫區(qū)。
          #include?
          int?data1?=?10?;?//初始化的全局變量存儲在DS段
          int?main(void)?{
          ????static?int?data2?=?3;??//初始化的靜態(tài)變量存儲在DS段
          ????return?0;
          }

          TEXT

          • 該段包含已編譯程序的二進(jìn)制文件。
          • 該段是一個(gè)只讀段,用于防止程序被意外修改。
          • 該段是可共享的,因此對于文本編輯器等頻繁執(zhí)行的程序,內(nèi)存中只需要一個(gè)副本。

          深入

          現(xiàn)在有一個(gè)簡單的程序,代碼如下:

          #include??
          ??
          int?main(void)?{?
          ????return?0;?
          }

          我們通過如下命令進(jìn)行編譯

          gcc?-g?a.cc?-o?a

          然后通過size命令,可以看到各個(gè)段的大小

          [root@build?src]#?gcc?a.c?-o?a
          [root@build?src]#?size?a
          ???text????data?????bss?????dec?????hex?filename
          ???1040?????484??????16????1540?????604?a

          其中前三列分別為可執(zhí)行程序a的text、data以及bss段的大小,第四列為該三段大小之和,第四列為該大小的十六進(jìn)制表示,最后一列是文件名。

          增加一個(gè)未初始化的靜態(tài)變量

          #include??
          ????
          int?main(void)?{?
          ????static?int?data;
          ????return?0;?
          }

          通過size命令

          [root@build?src]#?size?a
          ???text????data?????bss?????dec?????hex?filename
          ???1040?????484??????24????1548?????60c?a

          從上面可以看出,bss段size變大

          增加一個(gè)初始化的靜態(tài)變量

          #include??
          ????
          int?main(void)?{?
          ????static?int?data?=?10;
          ????return?0;?
          }

          通過size命令

          [root@build?src]#?size?a
          ???text????data?????bss?????dec?????hex?filename
          ???1040?????488??????16????1544?????608?a

          從上面可以看出,data段size變大

          增加一個(gè)未初始化的全局變量

          #include??
          int?data;
          int?main(void)?{?
          ????return?0;?
          }

          通過size命令

          [root@build?src]#?size?a
          ???text????data?????bss?????dec?????hex?filename
          ???1040?????484??????24????1548?????60c?a

          從上面可以看出,bss段size變大

          數(shù)據(jù)段的只讀區(qū)域和讀寫區(qū)域

          #include?
          char?str[]=?"Hello?world";
          int?main(void)?{
          ????printf("%s\n",str);
          ????str[0]='K';
          ????printf("%s\n",str);
          ????return?0;
          }

          輸出

          Hello?world
          Kello?world

          可以看到上面的示例str是一個(gè)全局?jǐn)?shù)組,因此它將進(jìn)入數(shù)據(jù)段。還可以看到能夠更改該值,因此它具有讀取和寫入權(quán)限。

          現(xiàn)在查看其他示例代碼

          #include?
          char?*str=?"Hello?world";
          int?main(void)?{
          ????str[0]='K';
          ????printf("%s\n",str);
          ????return?0;
          }

          在上面的示例中,我們無法更改數(shù)組字符是因?yàn)樗俏淖肿址3A孔址粌H會(huì)出現(xiàn)在數(shù)據(jù)部分,而且所有類型的const全局?jǐn)?shù)據(jù)都將進(jìn)入該部分。

          數(shù)據(jù)塊只讀部分,通常除了const變量和常量字符串外,程序的文本部分(通常是.rodata段)也存在于數(shù)據(jù)塊的只讀部分,因?yàn)橥ǔo法通過程序進(jìn)行修改。

          瀏覽 24
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  五月婷婷操| 色色的视频在线观看 | 狠狠狠狠狠狠狠狠狠狠 | 大鸡巴无码 | 激情婷婷色色 |