2017-09-02 34 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

所以,你的代码中没有任何东西可以显示在那个区域。