2010-02-08 26 views

回答

5

这个问题取决于所用变量的数量。既然你没有指定什么编译器或语言,甚至操作系统,这是一个难以确定的问题!这一切都取决于负责应用程序内存管理的操作系统。总之,这个问题没有明确的答案,想想这个问题,编译器/链接器在运行时,请求操作系统分配一块内存,分配取决于有多少变量,它们有多大,变量的范围和用法。例如,这个简单的C程序,在一个名为simpletest.c

 
#include <stdio.h> 
int main(int argc, char **argv){ 
    int num = 42; 
    printf("The number is %d!\n", num); 
    return 0; 
} 

假设是基于环境的Unix/Linux和编译如下:

 
gcc -o simpletest simpletest.c 

如果你发出objdumpnm在二进制图像simpletest上,您将看到可执行文件的各个部分,在本例中为'bss','text'。请记下这些部分的大小,现在在上面的代码中添加一个int var[100];,重新编译并重新发布objdumpnm,您会发现data部分已出现 - 为什么?因为我们添加了一个int数组类型的变量,其中包含100个元素。

这个简单的练习将证明部分增长,因此二进制变得更大,并且它还将证明,由于运行时实现因编译器和编译器以及操作而异,因此无法预先确定将分配多少内存系统到操作系统。

总之,操作系统调用内存管理镜头!

1

,你可以得到所有的信息编译程序

# gcc -o hello hello.c // you might compile with -static for simplicity 

然后readelf:

# readelf -l hello 
Elf file type is EXEC (Executable file) 
Entry point 0x80480e0 
There are 3 program headers, starting at offset 52 

Program Headers: 
    Type   Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align 
    LOAD   0x000000 0x08048000 0x08048000 0x55dac 0x55dac R E 0x1000 
    LOAD   0x055dc0 0x0809edc0 0x0809edc0 0x01df4 0x03240 RW 0x1000 
    NOTE   0x000094 0x08048094 0x08048094 0x00020 0x00020 R 0x4 

Section to Segment mapping: 
    Segment Sections... 
    00  .init .text .fini .rodata __libc_atexit __libc_subfreeres .note.ABI-tag 
    01  .data .eh_frame .got .bss 
    02  .note.ABI-tag 

输出显示打招呼的整体结构。第一个程序头对应于进程的代码段,该代码段将从偏移量为0x000000的文件加载到将映射到地址为0x08048000的进程地址空间的内存区域中。代码段的大小为0x55dac字节,并且必须是页面对齐的(0x1000)。该段将包含前面讨论的.text和.rodata ELF段,以及链接过程中生成的其他段。正如预期的那样,它被标记为只读(R)和可执行(X),但不可写(W)。

第二个程序头对应进程的数据段。加载此分段遵循上述相同的步骤。但是请注意,段大小为0x01df4,内存0x03240。这是由于.bss部分,该部分将被清零,因此不需要存在于文件中。数据段也将与页面对齐(0x1000),并包含.data和.bss ELF段。它将被标记为可读写(RW)。第三个程序头文件来自链接过程,与此讨论无关。

如果你有一个proc文件系统,你可以检查这个,只要你得到的“Hello World”足够长的时间(提示:GDB)运行,用下面的命令:

# cat /proc/`ps -C hello -o pid=`/maps 
08048000-0809e000 r-xp 00000000 03:06 479202  .../hello 
0809e000-080a1000 rw-p 00055000 03:06 479202  .../hello 
080a1000-080a3000 rwxp 00000000 00:00 0 
bffff000-c0000000 rwxp 00000000 00:00 0 

第一映射区域是进程的代码段,第二个和第三个构建数据段(data + bss + heap),第四个在ELF文件中没有对应关系,就是堆栈。有关正在运行的hello进程的更多信息可以通过GNU time,ps和/ proc/pid/stat获得。

+0

感谢您详细的演练:

例如取自!但是,我仍然有一个难题:你如何确定第一个程序头对应进程的代码段,第二个程序头对应于它的数据段?惯例?一个是RO(闻起来像.code),另一个是RW? (如果有两个RO或两个RW部分会怎样?) – U007D 2017-08-18 18:05:20

+0

是的,这是一条规则,并且第一个段也被标记为可执行文件,所以这必须是__code__。 – 4pie0 2017-08-19 19:01:07