分类: Linux 711人阅读 评论(0) 收藏 举报
    return 0;
}

我们用gcc -c test.c -o test.o生成目标文件。这个ELF文件是可重定位的,用readelf -S ./test.o可以看到类似如下的输出:
  [ 1] .text             PROGBITS        00000000 000034 000097 00  AX  0   0  4
  [ 2] .rel.text         REL             00000000 0004a0 000070 08      9   1  4
  [ 3] .data             PROGBITS        00000000 0000cc 000004 00  WA  0   0  4
  [ 4] .bss              NOBITS          00000000 0000d0 000004 00  WA  0   0  4
  [ 5] .rodata           PROGBITS        00000000 0000d0 00009f 00   A  0   0  4
  ...
我们可以看到所有目标文件的各种基地址都是从0x0开始,只是偏移不一样。.rel.text中记录了哪些是需要重定位的,如上面的printf,malloc。这些函数定义都需要链接的时候从相应的库中找到,并重定位。

然后我们用gcc test.o -o test生成可执行的ELF文件。用readelf -S ./test 可以看到类似如下的输出:
  [ 9] .rel.dyn          REL             080482b8 0002b8 000008 08   A  5   0  4
  [10] .rel.plt          REL             080482c0 0002c0 000020 08   A  5  12  4
  [11] .init             PROGBITS        080482e0 0002e0 000017 00  AX  0   0  4
  [12] .plt              PROGBITS        080482f8 0002f8 000050 04  AX  0   0  4
  [13] .text             PROGBITS        08048350 000350 0001dc 00  AX  0   0 16
  [14] .fini             PROGBITS        0804852c 00052c 00001c 00  AX  0   0  4
  [15] .rodata           PROGBITS        08048548 000548 0000a7 00   A  0   0  4
  ...
  [23] .data             PROGBITS        080496f0 0006f0 000010 00  WA  0   0  4
  [24] .bss              NOBITS          08049700 000700 000008 00  WA  0   0  4
  ...
我们看到经过链接后,目标文件的的基地址都发生了变化,都是唯一的逻辑地址了。其中.rel.dyn,.rel.plt等段中记录了哪些是需要运行时,由动态链接器加载重新定位的, 链接只是做了个标记,这些函数应该从哪个动态链接库中去找。如printf,malloc。  

我们运行./test程序,可以看到输出:
    Address of main (Text):0x80483f4
    Address of init_var (Data):0x80496fc
    Address of uninit_var (BSS):0x8049704
    Address of stack_var (Stack):0xbfcc6a4c
    Address of heap_var (Heap):0x804a008
即main函数的逻辑地址是0x80483f4,比对上面readelf -S ./test的输出,可以看到它位于.text段中
  初始化的static变量init_var的逻辑地址是0x80496fc, 位于.data段中
  未初始化的static变量uninit_var的逻辑地址是0x8049704,位于.bss段中
  栈上的变量stack_var的逻辑地址是0xbfcc6a4c,从用户态空间的高地址(0xBFFFFFFF)向低地址增加
  堆上的变量heap_var的逻辑地址是0x804a008,从用户态空间的低地址向高地址增加

所以用户程序进程在虚拟内存中的大致分布是:
    0xFFFFFFFF
                 内核空间(1G)
    0xBFFFFFFF
        栈
        .
        .
        .        用户空间(3G)
        堆
        BSS
        数据段
        代码段
    0x00000000
当然这只是一个示意简图,只画出了主要的区段,其实虚存中还有其他的区段,包括内核空间也有自己的堆栈,还有ELF文件格式中区/段的区别,这里我就不详述了。感兴趣的同学可以去查看ELF文件格式说明等资料。

这一次,我们分析出了用户进程的虚存布局,下一次,我们将来研究,这些虚存是如何使用,如何被分配回收的。以及相应的物理内存又是怎么被分配回收的。

Pthread 08/01/21

相关文章:

  • 2021-08-11
  • 2021-06-23
  • 2021-07-15
  • 2021-04-24
  • 2021-10-23
  • 2022-01-16
猜你喜欢
  • 2021-10-30
  • 2022-01-14
  • 2022-02-08
  • 2021-09-15
  • 2021-04-26
  • 2022-01-28
  • 2021-05-29
相关资源
相似解决方案