2017-09-02 36 views
2

從類似的問題here我看到不斷變量必須在程序的進程內存文本段,如果我理解一切正確的 - 這真的是:C - 常量位於進程的內存中?

int main() { 

    static const char somedata[8192] = "somedata"; 

    while (1) { 
     printf("\tAddress of main: %p\n", main); 
     printf("\tMy process ID : %d\n", getpid()); 
     printf("\tArray Some first address: %p\n", &somedata[1]); 
     sleep(10); 
    }; 

    return 0; 
} 

這給了我結果:

Address of main: 0x4bc38b971a 
My process ID : 633 
Array Some first address: 0x4bc38b9881 

它運行後 - /proc/maps證實了這一點:

$ cat /proc/633/maps 
4bc38b9000-4bc38bc000 r-xp 00000000 fe:01 19664256 

0x4bc38b9881是12月,0x4bc38b9000 - 0x4bc38bc000325403250688-325403262976和是這些邊界之間,一切看起來是正確的。

size還告訴它在text

$ size mem_lay_inc_text_print 
    text data  bss  dec  hex filename 
    10097  608  8 10713 29d9 mem_lay_inc_text_print 

this(和很多類似的)話題說 - 不變初始化數據段而不是在Code segment

初始化的數據存儲所有全球性的,靜態的,不斷

所以 - 其中的道理是什麼?或者我只是誤解了一些東西?

也許4bc38b9000-4bc38bc000包含Init。數據文本段?

不,這不:

... 
static int i = 100; 

while (1) { 
    printf("Address of main: %p\n", main); 
    printf("My process ID : %d\n", getpid()); 
    printf("Array Some first address: %p\n", &somedata[1]); 
    printf("Int I address: %p\n", &i); 
... 

現在從size的結果我看到data成爲(從第一個結果data 612代替608)更大,maps也表示相同的:

... 
Int I address: 0xea335af040 
... 

and maps

$ cat /proc/8859/maps 
ea333ac000-ea333af000 r-xp 00000000 fe:01 19664256 
ea335ae000-ea335af000 r--p 00002000 fe:01 19664256 
ea335af000-ea335b0000 rw-p 00003000 fe:01 19664256 

0xea335af040是在ea335af000-ea335b0000rw-p,這是data ...

真的在這裏感到困惑......

$ gcc --version 
gcc (GCC) 7.1.1 20170630 

所以問題是:常量的存儲位置 - 初始化數據還是文本段?或者它取決於編譯器/操作系統?

+0

實際問題是什麼?常量將位於鏈接器放置它們的位置。 – tilz0R

+0

@ tilz0R常量存儲 - 初始化數據或文本段? – setevoy

+1

基本上它取決於編譯器。我不再關注這個東西 - 這是編譯器的工作,爲什麼要擔心它? - 但我相信現在在文本段中放置'const'字符串(可能還包括字符串文字),以及初始化數據段中的可寫字符串是很常見的。 –

回答

0

由於空間和格式限制,我更願意在此處撰寫擴展評論,而不是評論。

首先,http://www.developerinsider.in/memory-layout-representation-of-c-program/中的內存佈局鏈接沒有錯;它只是沒有提及它正在嘗試對所有操作系統進行全面的泛化討論。這四個佈局概念是通用的:1)代碼,2)在構建時分配的數據(這會變得混亂)以及兩種類型的動態數據:3)堆棧和4)堆。如圖所示。它沒有提及動態鏈接環境所需的許多實際機制,例如全局偏移表(.got)。

我相信OP的一個重要區別是模糊的是可執行文件佈局與正在運行的進程內存佈局。可執行文件佈局(如ELF)是磁盤上包含進程藍圖的潛在位。在此討論所有具體的部分以及objdump工具適用的位置。 objdump -h foo實際上將顯示30個部分。

Linux內核中的可執行程序加載器將這些很多部分映射到幾個內存區域以最小化管理內存的複雜性和開銷。

下一個重要的區別是廣義的Unix行爲與Linux的具體情況之間的區別,至少在概念上,廉價硬件的性能優於優雅並堅持清晰的分離。因此,在所引用的鏈接:

出於這個原因,所述.RODATA部分,包含只讀 初始化的數據,被打包到包含 .text段相同的段。

這是不幸的,因爲只讀初始化的數據具有完全不必要的執行權限附。幾乎可以肯定的是,Linux的硬化變體不會以犧牲輕微的內存或CPU浪費爲代價。

這裏是我的代碼(我注意到你正在使用基於陣列1 - 哎呀,這不是C是如何工作的!) - 它試圖展現出只讀和讀寫映射:

#include <stdio.h> /* printf */ 
#include <sys/types.h> /* getpid */ 
#include <unistd.h> /* getpid */ 
#include <sys/select.h> 

const char small_ro_global[ 16] = "small ro global"; 
char  small_rw_global[ 16] = "small ro global"; 
const char big_ro_global[8192] = " big ro global"; 
char   big_rw_global[8192] = " big rw global"; 

int main(int argc, char *argv[]) { 
    /* small_ro_global[1] = 'b'; compile error */ 
    small_rw_global[1] = 'c'; /* ensure writable */ 

    printf("Address of main: %p\n", main); 
    printf("My process ID : %d\n", getpid()); 

    printf("small_ro_global: %p big_ro_global: %p small_rw_global: %p big_rw_global: %p\n", 
     small_ro_global, big_ro_global, small_rw_global, big_rw_global); 

    /* waits forever */ 
    select(0, NULL, NULL, NULL, NULL); 

    return 0; 
} 

GCC:訴4.8.4 GNU/Linux分發:Ubuntu的15.10設備:Intel 64位 輸出:

Address of main: 0x4005cd 
My process ID : 5788 
small_ro_global: 0x400700 big_ro_global: 0x400720 small_rw_global: 0x603060 big_rw_global: 0x603080 

/proc/5788/maps摘錄。注意,在第一次什麼土地與第3節,但沒有在第2節登陸:

00400000-00403000 r-xp 00000000 ca:01 1947        /root/foo 
00602000-00603000 r--p 00002000 ca:01 1947        /root/foo 
00603000-00606000 rw-p 00003000 ca:01 1947        /root/foo 

最後感謝該鏈接剛剛得知readelf -l這給下面。具體請參見02段包含.text和.rodata部分。

Section to Segment mapping: 
    Segment Sections... 
    00  
    01  .interp 
    02  .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame 
    03  .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss 
    04  .dynamic 
    05  .note.ABI-tag .note.gnu.build-id 
    06  .eh_frame_hdr 
    07  
    08  .init_array .fini_array .jcr .dynamic .got 

從上proc文檔(5)我們知道,在內存段第二(權限:只讀,不可執行),並關聯與objdump,是過程力學:動態鏈接和異常處理。它包含部分:.eh_frame_hdr,.eh_frame,.init_array,.fini_array, .jcr,.dynamic.got

所以,你的代碼中沒有任何東西可以顯示在那個區域。