免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2616 | 回复: 1
打印 上一主题 下一主题

ELF 可执行文件VMA 布局 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-04-09 13:48 |只看该作者 |倒序浏览
本帖最后由 jixuyang 于 2012-04-09 15:02 编辑

    近来看<<程序员的自我修养>>的6.4.1小节,看到静态链接的可执行文件sectionmapping.elf的两个LOAD segment的地址
连续,且以0x1000的方式对齐,其segment输入信息如下:

program header:
    Type          Offset          Virtual Address          Physical Address          FileSiz          MemSiz          Flg          Align
    LOAD         0x000000    0x08048000              0x08048000               0x709e5      0x709e5         RE          0x1000
    LOAD         0x0709e8    0x080b99e8              0x080b99e8                0x00798      0x02280        RW         0x1000

    这里第2个Segment的虚拟地址为0x080b99e8,作者的书中已经描述清楚了:为了节省物理内存,OS会在物理页面上连续存放
第一个LOAD segment和第二个LOAD segment,但是在虚拟地址上以0x1000的方式来对齐这两个segment。为此,这就会让两个
不同的虚拟地址映射到相同的物理页面,即系统会在第一个LOAD segment的最后一个物理页面同时存放第一个LOAD segment的尾巴,
同时会存放第二个LOAD segment的开头部分,但是会使用两组虚拟地址[0x80b89e5, 0x80b9000]和[0x80b9000, 0x80ba000]来
映射到这个相同的物理页面。对于第二个映射,因为前面部分已经存放第一个LOAD segment的尾巴,所以其真正的起始地址为0x08048000 + 0x709e5
= 0x80b89e5 => 0x80b89e8(4字节对齐的原则)。

    我对这里书中的描述,没有疑问。但是,当我使用新版本GCC来编译这个程序时,发现当前版本产生的可执行文件的segment已经与书中描述的不同,
请看我在ubuntu 11.04 (gcc-4.5.2, gas-2.21.0.20110327, ld-2.21.0.20110327) 上编译相同的源代码所输出的segment布局:

program header:
    Type          Offset          Virtual Address          Physical Address          FileSiz          MemSiz          Flg          Align
    LOAD         0x000000    0x08048000              0x08048000               0x86aa1      0x86aa1         RE          0x1000
    LOAD         0x0709e8    0x080cff8c                 0x080cff8c                 0x007d4      0x02384         RW        0x1000

    按照书中的描述,第二个LOAD segment的地址应该为0x08048000 + 0x86aa1 = 0x80ceaa1 => 0x80ceaa4,但是上面输出的地址确是
0x080cff8c,确实让人想不通。通过readelf -S sectionmapping.elf,我们能得到下面的结果(看不到0x80ceaa4 ~ 0x080cff8c之间是什么东西):
Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .note.ABI-tag     NOTE            080480f4 0000f4 000020 00   A  0   0  4
  [ 2] .note.gnu.build-i NOTE            08048114 000114 000024 00   A  0   0  4
  [ 3] .rel.plt          REL             08048138 000138 000028 08   A  0   5  4
  [ 4] .init             PROGBITS        08048160 000160 000030 00  AX  0   0  4
  [ 5] .plt              PROGBITS        08048190 000190 000050 00  AX  0   0  4
  [ 6] .text             PROGBITS        080481e0 0001e0 0668dc 00  AX  0   0 16
  [ 7] __libc_freeres_fn PROGBITS        080aeac0 066ac0 000b21 00  AX  0   0 16
  [ 8] .fini             PROGBITS        080af5e4 0675e4 00001c 00  AX  0   0  4
  [ 9] .rodata           PROGBITS        080af600 067600 019000 00   A  0   0 32
  [10] __libc_subfreeres PROGBITS        080c8600 080600 00002c 00   A  0   0  4
  [11] __libc_atexit     PROGBITS        080c862c 08062c 000004 00   A  0   0  4
  [12] .eh_frame         PROGBITS        080c8630 080630 006300 00   A  0   0  4
  [13] .gcc_except_table PROGBITS        080ce930 086930 000171 00   A  0   0  1
  [14] .tdata            PROGBITS        080cff8c 086f8c 000010 00 WAT  0   0  4

  [15] .tbss             NOBITS          080cff9c 086f9c 000018 00 WAT  0   0  4
  [16] .ctors            PROGBITS        080cff9c 086f9c 00000c 00  WA  0   0  4
  [17] .dtors            PROGBITS        080cffa8 086fa8 00000c 00  WA  0   0  4
  [18] .jcr              PROGBITS        080cffb4 086fb4 000004 00  WA  0   0  4
  [19] .data.rel.ro      PROGBITS        080cffb8 086fb8 000030 00  WA  0   0  4
  [20] .got              PROGBITS        080cffe8 086fe8 00000c 04  WA  0   0  4
  [21] .got.plt          PROGBITS        080cfff4 086ff4 000020 04  WA  0   0  4
  [22] .data             PROGBITS        080d0020 087020 000740 00  WA  0   0 32
  [23] .bss              NOBITS          080d0760 087760 001b98 00  WA  0   0 32
  [24] __libc_freeres_pt NOBITS          080d22f8 087760 000018 00  WA  0   0  4
  [25] .comment          PROGBITS        00000000 087760 00002a 01  MS  0   0  1
  [26] .shstrtab         STRTAB          00000000 08778a 000110 00      0   0  1
  [27] .symtab           SYMTAB          00000000 087d24 008170 10     28 929  4
  [28] .strtab           STRTAB          00000000 08fe94 007566 00      0   0  1


    通过objdump -D sectionmapping.elf命令,我们能得到下面的结果,但是看起来0x80ceaa4 ~ 0x080cff8c之间
好像为真空,没有任何的代码或数据。

Disassembly of section .gcc_except_table:

080ce930 <.gcc_except_table>:
80ce930:       ff                      (bad)  
80ce931:       ff 01                   incl   (%ecx)
80ce933:       2e                      cs
===============
忽略中间的一些代码
===============
80cea99:       c0 02 00                rolb   $0x0,(%edx)
80cea9c:       f3                      repz
80cea9d:       02                      .byte 0x2
80cea9e:       05                      .byte 0x5
        ...

Disassembly of section .tdata:

080cff8c <_nl_current_LC_NUMERIC+0x80cff80>:
80cff8c:       a0 06 0d 08 a0          mov    0xa0080d06,%al
80cff91:       06                      push   %es
80cff92:       0d 08 b0 06 0d          or     $0xd06b008,%eax
80cff97:       08                      .byte 0x8
80cff98:       a4                      movsb  %ds%esi),%es%edi)
80cff99:       06                      push   %es
80cff9a:       0d                      .byte 0xd

    ld --version输出的链接脚本布局为:
  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
  .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
  /* Adjust the address for the data segment.  We want to adjust up to
     the same address within the page on the next page up.  */
  . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
  /* Exception handling  */
  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }
  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
  /* Thread Local Storage sections  */
  .tdata          : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
  .tbss           : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }


    为此,这里的疑问是:与老版本GCC相比(4.1.2),新版本GCC(4.5.2)产生的静态版本可执行文件的两个segment地址为何不连续
从上面的链接脚本来看,alignment会使用MAXPAGESIZE进行对齐,但是怎么会让第二个segment的起始地址为0x80cff8c呢?敬请高手指点指点,谢谢。

论坛徽章:
0
2 [报告]
发表于 2012-04-16 14:12 |只看该作者
本帖最后由 jixuyang 于 2012-04-16 14:13 编辑

通过readefl和objdump工具进行分析,得到其ELF 文件的布局如下:
                ELF header                                                (0x34)
                Program header entries
                Other Section                                        (until to .comment section)
                        program segment one                 (section 1 to 13)
                        black area                                  (namely the black area between section 13 and 14)
                        program segment two                 (section 14 to 24)
                .comment section                                (0x87760, 0x2a)
                .shstrtab section                                (0x8778a, 0x110)
                section header entries
                .symtab section                                        (0x87d24, 0x8170)
                .strtab section                                        (0x8fe94, 0x7566)
                EOF                                                        (end of file)
通过二进制工具查看可执行文件的0x86aa1(0x86930 + 0x171,.gcc_except_table section末尾)到0x86fc8之间的区域,发现
全被填充为0,为何会如此呢?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP