日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

Linux下C程序进程地址空间布局

發(fā)布時(shí)間:2025/3/15 linux 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux下C程序进程地址空间布局 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

我們?cè)趯W(xué)習(xí)C程序開發(fā)時(shí)經(jīng)常會(huì)遇到一些概念:代碼段、數(shù)據(jù)段、BSS段(Block Started by Symbol)?、堆(heap)和棧(stack)。先看一張教材上的示意圖(來(lái)源,《UNIX環(huán)境高級(jí)編程》一書),顯示了進(jìn)程地址空間中典型的存儲(chǔ)區(qū)域分配情況。

???????????

從圖中可以看出:

  • 從低地址到高地址分別為:代碼段、(初始化)數(shù)據(jù)段、(未初始化)數(shù)據(jù)段(BSS)、堆、棧、命令行參數(shù)和環(huán)境變量
  • 堆向高內(nèi)存地址生長(zhǎng)
  • 棧向低內(nèi)存地址生長(zhǎng)

還經(jīng)??吹较旅孢@個(gè)圖(來(lái)源,不詳):

???????????????????????????????????????????????????????????????????

?

先看一段程序。

?

view plain
  • #include?<stdio.h>??
  • #include?<stdlib.h>??
  • ??
  • int?global_init_a=1;??
  • int?global_uninit_a;??
  • static?int?static_global_init_a=1;??
  • static?int?static_global_uninit_a;??
  • const?int?const_global_a=1;??
  • ??
  • int?global_init_b=1;??
  • int?global_uninit_b;??
  • static?int?static_global_init_b=1;??
  • static?int?static_global_uninit_b;??
  • const?int?const_global_b=1;??
  • /*上面全部為全局變量,main函數(shù)中的為局部變量*/??
  • int?main()??
  • {??
  • ????int?local_init_a=1;??
  • ????int?local_uninit_a;??
  • ????static?int?static_local_init_a=1;??
  • ????static?int?static_local_uninit_a;??
  • ????const?int?const_local_a=1;??
  • ??
  • ????int?local_init_b=1;??
  • ????int?local_uninit_b;??
  • ????static?int?static_local_init_b=1;??
  • ????static?int?static_local_uninit_b;??
  • ????const?int?const_local_b=1;??
  • ??
  • ????int?*?malloc_p_a;??
  • ????malloc_p_a=malloc(sizeof(int));??
  • ??
  • ????printf("\n?????????&global_init_a=%p?\t????????????
  • ?????????global_init_a=%d\n",&global_init_a,global_init_a);???
  • ??
  • ????printf("???????&global_uninit_a=%p?\t??????????
  • ????????global_uninit_a=%d\n",&global_uninit_a,global_uninit_a);??????
  • ??
  • ????printf("??&static_global_init_a=%p?\t?????
  • ????????static_global_init_a=%d\n",&static_global_init_a,static_global_init_a);??
  • ??????
  • ????printf("&static_global_uninit_a=%p?\t???
  • ????????static_global_uninit_a=%d\n",&static_global_uninit_a,static_global_uninit_a);??
  • ??????
  • ????printf("????????&const_global_a=%p?\t???????????
  • ????????const_global_a=%d\n",&const_global_a,const_global_a);?????
  • ??
  • ??????
  • ????printf("\n?????????&global_init_b=%p?\t????????????
  • ????????global_init_b=%d\n",&global_init_b,global_init_b);????
  • ??
  • ????printf("???????&global_uninit_b=%p?\t??????????
  • ????????global_uninit_b=%d\n",&global_uninit_b,global_uninit_b);??????
  • ??
  • ????printf("??&static_global_init_b=%p?\t?????
  • ????????static_global_init_b=%d\n",&static_global_init_b,static_global_init_b);??
  • ??????
  • ????printf("&static_global_uninit_b=%p?\t???
  • ????????static_global_uninit_b=%d\n",&static_global_uninit_b,static_global_uninit_b);??
  • ??????
  • ????printf("????????&const_global_b=%p?\t???????????
  • ????????const_global_b=%d\n",&const_global_b,const_global_b);??
  • ??
  • ??????????????????
  • ??
  • ????printf("\n??????????&local_init_a=%p?\t????????????
  • ????????local_init_a=%d\n",&local_init_a,local_init_a);???
  • ??
  • ????printf("????????&local_uninit_a=%p?\t??????????
  • ????????local_uninit_a=%d\n",&local_uninit_a,local_uninit_a);??
  • ??????
  • ????printf("???&static_local_init_a=%p?\t?????
  • ????????static_local_init_a=%d\n",&static_local_init_a,static_local_init_a);??
  • ??????
  • ????printf("?&static_local_uninit_a=%p?\t???
  • ????????static_local_uninit_a=%d\n",&static_local_uninit_a,static_local_uninit_a);????
  • ??
  • ????printf("?????????&const_local_a=%p?\t???????????
  • ????????const_local_a=%d\n",&const_local_a,const_local_a);????
  • ??
  • ??????
  • ????printf("\n??????????&local_init_b=%p?\t????????????
  • ????????local_init_b=%d\n",&local_init_b,local_init_b);???
  • ??
  • ????printf("????????&local_uninit_b=%p?\t??????????
  • ????????local_uninit_b=%d\n",&local_uninit_b,local_uninit_b);??
  • ??????
  • ????printf("???&static_local_init_b=%p?\t?????
  • ????????static_local_init_b=%d\n",&static_local_init_b,static_local_init_b);??
  • ??????
  • ????printf("?&static_local_uninit_b=%p?\t???
  • ????????static_local_uninit_b=%d\n",&static_local_uninit_b,static_local_uninit_b);????
  • ??
  • ????printf("?????????&const_local_b=%p?\t???????????
  • ????????const_local_b=%d\n",&const_local_b,const_local_b);??
  • ??
  • ??
  • ????printf("?????????????malloc_p_a=%p?\t?????????????
  • ????????*malloc_p_a=%d\n",malloc_p_a,*malloc_p_a);??
  • ??????
  • ????return?0;??
  • }??
  • ?

    下面是輸出結(jié)果。

    ???????????

    先仔細(xì)分析一下上面的輸出結(jié)果,看看能得出什么結(jié)論。貌似很難分析出來(lái)什么結(jié)果。好了我們繼續(xù)往下看吧。

    ?

    接下來(lái),通過(guò)查看proc文件系統(tǒng)下的文件,看一下這個(gè)進(jìn)程的真實(shí)內(nèi)存分配情況。(我們需要在程序結(jié)束前加一個(gè)死循環(huán),不讓進(jìn)程結(jié)束,以便我們進(jìn)一步分析)。

    ??????在return 0前,增加 while(1); 語(yǔ)句

    重新編譯后,運(yùn)行程序,程序?qū)⑦M(jìn)入死循環(huán)。

    ??????

    使用ps命令查看一下進(jìn)程的pid

    ? #ps -aux | grep a.out

    查看/proc/2699/maps文件,這個(gè)文件顯示了進(jìn)程在內(nèi)存空間中各個(gè)區(qū)域的分配情況。

    ? #cat? /proc/2699/maps

    上面紅顏色標(biāo)出的幾個(gè)區(qū)間是我們感興趣的區(qū)間:

    • 08048000-08049000? r-xp? 貌似是代碼段
    • 08049000-0804a000 r--p?? 暫時(shí)不清楚,看不出來(lái)
    • 0804a000-0804b000 rw-p? 貌似為數(shù)據(jù)段
    • 08a7e000-08a9f000? rw-p? 堆
    • bff73000-bff88000???? rw-p?? 棧???

    我們把這些數(shù)據(jù)與剛才的程序運(yùn)行結(jié)果進(jìn)行比較,看看有什么結(jié)論。

    ??????????????? &global_init_a=0x804a018?????? 全局初始化:數(shù)據(jù)段??????????? ? global_init_a=1
    ????????????&global_uninit_a=0x804a04c??????全局未初始化:數(shù)據(jù)段?????? ? ?global_uninit_a=0
    ???? &static_global_init_a=0x804a01c ?? ??全局靜態(tài)初始化:數(shù)據(jù)段? ?? ?static_global_init_a=1
    &static_global_uninit_a=0x804a038 ???? 全局靜態(tài)未初始化:數(shù)據(jù)段? ?? static_global_uninit_a=0
    ???????? ??? &const_global_a=0x80487c0 ?? ?全局只讀變量:?代碼段??????? const_global_a=1

    ???? ????????? ? &global_init_b=0x804a020???????全局初始化:數(shù)據(jù)段????? global_init_b=1
    ???? ??? ?? &global_uninit_b=0x804a048?????? ?全局未初始化:數(shù)據(jù)段????? global_uninit_b=0
    ??? ?&static_global_init_b=0x804a024????? ? 全局靜態(tài)初始化:數(shù)據(jù)段??? static_global_init_b=1
    &static_global_uninit_b=0x804a03c??????? 全局靜態(tài)未初始化:數(shù)據(jù)段?? static_global_uninit_b=0
    ???????? ?? &const_global_b=0x80487c4????????全局只讀變量:?代碼段??????? ???? const_global_b=1

    ???????????? ??? &local_init_a=0xbff8600c ?? ????? 局部初始化:棧???????????????????? local_init_a=1
    ??????? ???? &local_uninit_a=0xbff86008 ?? ?????局部未初始化:棧???????????????? local_uninit_a=134514459
    ???? &static_local_init_a=0x804a028 ?? ???? 局部靜態(tài)初始化:數(shù)據(jù)段????? static_local_init_a=1
    ?&static_local_uninit_a=0x804a040??????? 局部靜態(tài)未初始化:數(shù)據(jù)段??? ?static_local_uninit_a=0
    ?????????? ? &const_local_a=0xbff86004????????局部只讀變量:棧???? const_local_a=1

    ???? ????????? ?? &local_init_b=0xbff86000????????局部初始化:棧???????? ?local_init_b=1
    ?? ???????????? &local_uninit_b=0xbff85ffc?????????局部未初始化:棧?????? ?local_uninit_b=-1074241512
    ???? ?&static_local_init_b=0x804a02c??????? 局部靜態(tài)初始化:數(shù)據(jù)段????? static_local_init_b=1
    ?&static_local_uninit_b=0x804a044??????? 局部靜態(tài)未初始化:數(shù)據(jù)段????? static_local_uninit_b=0
    ?????????? ???? &const_local_b=0xbff85ff8????????局部只讀變量:棧?????? ?const_local_b=1


    ?????????????????????????? p_chars=0x80487c8????????字符串常量:代碼段????????? p_chars=abcdef
    ????????????? ????? malloc_p_a=0x8a7e008 ?? ????malloc動(dòng)態(tài)分配:堆??????? *malloc_p_a=0

    通過(guò)以上分析我們暫時(shí)可以得到的結(jié)論如下,在進(jìn)程的地址空間中

    • 數(shù)據(jù)段中存放:全局變量(初始化以及未初始化的)、靜態(tài)變量(全局的和局部的、初始化的以及未初始化的)
    • 代碼段中存放:全局只讀變量(const)、字符串常量
    • 堆中存放:動(dòng)態(tài)分配的區(qū)域
    • 棧中存放:局部變量(初始化以及未初始化的,但不包含靜態(tài)變量)、局部只讀變量(const)

    這里我們沒(méi)有發(fā)現(xiàn)BSS段,但是我們將未初始化的數(shù)據(jù)按照地址進(jìn)行排序看一下,可以發(fā)現(xiàn)一個(gè)規(guī)律。

    ??????????????? &global_init_a=0x804a018?????? 全局初始化:數(shù)據(jù)段??????????? ? global_init_a=1
    ??? &static_global_init_a=0x804a01c ?? ??全局靜態(tài)初始化:數(shù)據(jù)段? ?? ?static_global_init_a=1
    ??????????????? &global_init_b=0x804a020???????全局初始化:數(shù)據(jù)段????? global_init_b=1
    ????&static_global_init_b=0x804a024????? ? 全局靜態(tài)初始化:數(shù)據(jù)段??? static_global_init_b=1
    ???? ? &static_local_init_a=0x804a028 ?? ???? 局部靜態(tài)初始化:數(shù)據(jù)段????? static_local_init_a=1
    ? ?????&static_local_init_b=0x804a02c??????? 局部靜態(tài)初始化:數(shù)據(jù)段????? static_local_init_b=1

    &static_global_uninit_a=0x804a038 ???? 全局靜態(tài)未初始化:數(shù)據(jù)段? ?? static_global_uninit_a=0
    &static_global_uninit_b=0x804a03c??????? 全局靜態(tài)未初始化:數(shù)據(jù)段?? static_global_uninit_b=0
    ??&static_local_uninit_a=0x804a040??????? 局部靜態(tài)未初始化:數(shù)據(jù)段??? ?static_local_uninit_a=0
    ??&static_local_uninit_b=0x804a044??????? 局部靜態(tài)未初始化:數(shù)據(jù)段????? static_local_uninit_b=0
    ?????????? &global_uninit_b=0x804a048?????? ?全局未初始化:數(shù)據(jù)段????? global_uninit_b=0
    ????????????&global_uninit_a=0x804a04c??????全局未初始化:數(shù)據(jù)段?????? ? ?global_uninit_a=0


    ??? 這里可以發(fā)現(xiàn),初始化的和未初始化的數(shù)據(jù)好像是分開存放的,因此我們可以猜測(cè)BSS段是存在的,只不過(guò)數(shù)據(jù)段是分為初始化和未初始化(即BSS段)的兩部分,他們?cè)诩虞d到進(jìn)程地址空間時(shí)是合并為數(shù)據(jù)段了,在進(jìn)程地址空間中沒(méi)有單獨(dú)分為一個(gè)區(qū)域。

    ??? 還有一個(gè)問(wèn)題,靜態(tài)數(shù)據(jù)與非靜態(tài)數(shù)據(jù)是否是分開存放的呢?請(qǐng)讀者自行分析一下。

    ?

    ?接下來(lái)我們從程序的角度看一下,這寫存儲(chǔ)區(qū)域是如何分配的。首先我們先介紹一下ELF文件格式。

    ELF(Executable and Linkable Format )文件格式是一個(gè)開放標(biāo)準(zhǔn),各種UNIX系統(tǒng)的可執(zhí)行文件都采用ELF格式,它有三種不同的類型: –可重定位的目標(biāo)文件(Relocatable,或者Object File) –可執(zhí)行文件(Executable) –共享庫(kù)(Shared Object,或者Shared Library) 下圖為ELF文件的結(jié)構(gòu)示意圖(來(lái)源,不詳):

    ?????????????????????????????????????

    ?

    一個(gè)程序編譯生成目標(biāo)代碼文件(ELF文件)的過(guò)程如下,此圖引自《程序員的自我修養(yǎng)》一書的一個(gè)圖:

    ?????????????????????????????????

    可以通過(guò)readelf命令查看EFL文件的相關(guān)信息,例如 readelf? -a? a.out? ,我們只關(guān)心各個(gè)段的分配情況,因此我們使用以下命令:

    # readelf -S?a.out ?????????????????????

    ?將這里的內(nèi)存布局與之前看到的程序的運(yùn)行結(jié)果進(jìn)行分析:

    ??????????????? &global_init_a=0x804a018?????? 全局初始化:數(shù)據(jù)段??????????? ? global_init_a=1
    ????????????&global_uninit_a=0x804a04c??????全局未初始化:BSS段?????? ? ?global_uninit_a=0
    ???? &static_global_init_a=0x804a01c ?? ??全局靜態(tài)初始化:數(shù)據(jù)段? ?? ?static_global_init_a=1
    &static_global_uninit_a=0x804a038 ???? 全局靜態(tài)未初始化:BSS段? ?? static_global_uninit_a=0
    ???????? ??? &const_global_a=0x80487c0 ?? ?全局只讀變量:?只讀數(shù)據(jù)段??????? const_global_a=1

    ???? ????????? ? &global_init_b=0x804a020???????全局初始化:數(shù)據(jù)段????? global_init_b=1
    ???? ??? ?? &global_uninit_b=0x804a048?????? ?全局未初始化:BSS段????? global_uninit_b=0
    ??? ?&static_global_init_b=0x804a024????? ? 全局靜態(tài)初始化:數(shù)據(jù)段??? static_global_init_b=1
    &static_global_uninit_b=0x804a03c??????? 全局靜態(tài)未初始化:BSS段?? static_global_uninit_b=0
    ???????? ?? &const_global_b=0x80487c4????????全局只讀變量:?只讀數(shù)據(jù)段???????????? const_global_b=1

    ???? &static_local_init_a=0x804a028 ?? ???? 局部靜態(tài)初始化:數(shù)據(jù)段????? static_local_init_a=1
    ?&static_local_uninit_a=0x804a040??????? 局部靜態(tài)未初始化:BSS段??? ?static_local_uninit_a=0

    ??????&static_local_init_b=0x804a02c??????? 局部靜態(tài)初始化:數(shù)據(jù)段????? static_local_init_b=1
    ?&static_local_uninit_b=0x804a044??????? 局部靜態(tài)未初始化:BSS段????? static_local_uninit_b=0

    ?????????????????????????? p_chars=0x80487c8????????字符串常量:只讀數(shù)據(jù)段????????? p_chars=abcdef
    ELF 文件一般包含以下幾個(gè)段 :

    • .text section:主要是編譯后的源碼指令,是只讀字段。
    • .data section :初始化后的非const的全局變量、局部static變量。
    • .bss:未初始化后的非const全局變量、局部static變量。
    • .rodata字段? 是存放只讀數(shù)據(jù)?

    分析到這以后,我們?cè)诤椭胺治龅慕Y(jié)果對(duì)比一下,會(huì)發(fā)現(xiàn)確實(shí)存在BSS段,地址為0804a030?,大小為0x20,之前我們的程序中未初始化的的確存放在這個(gè)地址區(qū)間中了,只不過(guò)執(zhí)行exec系統(tǒng)調(diào)用時(shí),將這部分的數(shù)據(jù)初始化為0后,放到了進(jìn)程地址空間的數(shù)據(jù)段中了,在進(jìn)程地址空間中就沒(méi)有必要存在BSS段了,因此都稱做數(shù)據(jù)段。同理,.rodata字段也是與text段放在一起了。

    在ELF文件中,找不到局部非靜態(tài)變量和動(dòng)態(tài)分配的內(nèi)容。

    ?

    以上有很多地方的分析,我在網(wǎng)上基本找不到很明確的結(jié)論,很多教材上也沒(méi)有描述,只是我通過(guò)程序分析得出的結(jié)論,如有不妥之處,請(qǐng)指出,歡迎交流。

    總結(jié)

    以上是生活随笔為你收集整理的Linux下C程序进程地址空间布局的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。