4

我正在使用binutils-2.21.53.0.1-6.fc16.x86_64.

我有一个小目标文件,hello.o只有足够的“东西”来包含所有部分的内容:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         0000000000000000  00000040
       000000000000005d  0000000000000000  AX       0     0     4
  [ 2] .rela.text        RELA             0000000000000000  00000808
       0000000000000060  0000000000000018          15     1     8
  [ 3] .data             PROGBITS         0000000000000000  000000a0
       0000000000000000  0000000000000000  WA       0     0     4
  [ 4] .bss              NOBITS           0000000000000000  000000a0
       0000000000000053  0000000000000000  WA       0     0     32
  [ 5] .rodata           PROGBITS         0000000000000000  000000a0
       000000000000000f  0000000000000000   A       0     0     1
  [ 6] .data.rel.local   PROGBITS         0000000000000000  000000b0
       0000000000000008  0000000000000000  WA       0     0     8
  [ 7] .rela.data.rel.lo RELA             0000000000000000  00000868
       0000000000000018  0000000000000018          15     6     8
  [ 8] .data.rel         PROGBITS         0000000000000000  000000b8
       0000000000000008  0000000000000000  WA       0     0     8
  [ 9] .rela.data.rel    RELA             0000000000000000  00000880
       0000000000000018  0000000000000018          15     8     8
  [10] .comment          PROGBITS         0000000000000000  000000c0
       000000000000002d  0000000000000001  MS       0     0     1
  [11] .note.GNU-stack   PROGBITS         0000000000000000  000000ed
       0000000000000000  0000000000000000           0     0     1
  [12] .eh_frame         PROGBITS         0000000000000000  000000f0
       0000000000000058  0000000000000000   A       0     0     8
  [13] .rela.eh_frame    RELA             0000000000000000  00000898
       0000000000000030  0000000000000018          15    12     8
  [14] .shstrtab         STRTAB           0000000000000000  00000148
       0000000000000085  0000000000000000           0     0     1
  [15] .symtab           SYMTAB           0000000000000000  00000610
       00000000000001b0  0000000000000018          16    11     8
  [16] .strtab           STRTAB           0000000000000000  000007c0
       0000000000000045  0000000000000000           0     0     1

如果我使用-pie并且没有链接器脚本,则结果与预期一致:

$ ld -pie -Map hello_pie.map -o hello_pie.elf hello.o 

$ ll hello_pie.elf 
-rwxrwx---. 1 jreinhart jreinhart 3453 Mar 13 23:44 hello_pie.elf

但是,如果我包含任何类型的链接器脚本,输出大小会爆炸:

$ cat 1.ld 
SECTIONS
{

}
$ ld -T 1.ld -pie -Map hello_pie.map -o hello_pie.elf hello.o 
$ ll hello_pie.elf 
-rwxrwx---. 1 jreinhart jreinhart 2100070 Mar 13 23:45 hello_pie.elf

如您所见,这个文件变得很大。

请注意,这似乎是因为该.text部分坚持从文件中的偏移量 0x200000 开始:

$ readelf -l -S hello_pie.elf 
There are 19 section headers, starting at offset 0x200400:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         0000000000000000  00200000  <--- Why?
       000000000000005d  0000000000000000  AX       0     0     4
  [ 2] .rodata           PROGBITS         000000000000005d  0020005d
       000000000000000f  0000000000000000   A       0     0     1
  [ 3] .eh_frame         PROGBITS         0000000000000070  00200070
       0000000000000058  0000000000000000   A       0     0     8
  [ 4] .interp           PROGBITS         00000000000000c8  002000c8
       000000000000000f  0000000000000000   A       0     0     1
  [ 5] .dynsym           DYNSYM           00000000000000d8  002000d8
       0000000000000078  0000000000000018   A       6     2     8
  [ 6] .dynstr           STRTAB           0000000000000150  00200150
       0000000000000014  0000000000000000   A       0     0     1
  [ 7] .hash             HASH             0000000000000168  00200168
       0000000000000028  0000000000000004   A       5     0     8
  [ 8] .rela.dyn         RELA             0000000000000190  00200190
       0000000000000078  0000000000000018   A       5     0     8
  [ 9] .data.rel.local   PROGBITS         0000000000000208  00200208
       0000000000000008  0000000000000000  WA       0     0     8
  [10] .data.rel         PROGBITS         0000000000000210  00200210
       0000000000000008  0000000000000000  WA       0     0     8
  [11] .dynamic          DYNAMIC          0000000000000218  00200218
       00000000000000f0  0000000000000010  WA       6     0     8
  [12] .got              PROGBITS         0000000000000308  00200308
       0000000000000018  0000000000000008  WA       0     0     8
  [13] .got.plt          PROGBITS         0000000000000320  00200320
       0000000000000018  0000000000000008  WA       0     0     8
  [14] .bss              NOBITS           0000000000000340  00200338
       0000000000000053  0000000000000000  WA       0     0     32
  [15] .comment          PROGBITS         0000000000000000  00200338
       000000000000002c  0000000000000001  MS       0     0     1
  [16] .shstrtab         STRTAB           0000000000000000  00200364
       000000000000009a  0000000000000000           0     0     1
  [17] .symtab           SYMTAB           0000000000000000  002008c0
       0000000000000258  0000000000000018          18    19     8
  [18] .strtab           STRTAB           0000000000000000  00200b18
       000000000000004e  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), l (large)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

Elf file type is DYN (Shared object file)
Entry point 0x0
There are 5 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000200040 0x0000000000000000
                 0x0000000000000118 0x0000000000000118  R E    8
  INTERP         0x00000000002000c8 0x00000000000000c8 0x00000000000000c8
                 0x000000000000000f 0x000000000000000f  R      1
      [Requesting program interpreter: /lib/ld64.so.1]
  LOAD       --> 0x0000000000200000 0x0000000000000000 0x0000000000000000
                 0x0000000000000338 0x0000000000000393  RWE    200000
  DYNAMIC        0x0000000000200218 0x0000000000000218 0x0000000000000218
                 0x00000000000000f0 0x00000000000000f0  RW     8
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     8

无论我的链接描述文件的内容如何,​​这种情况一直在发生。有什么想法吗?

4

3 回答 3

7

我今天在学习链接器脚本时遇到了同样的问题。SIZEOF_HEADERS 是解决它的灵丹妙药。这是我构建要链接的对象的简单源文件:

    .section .text
    .global _start
_start:
    mov $1, %eax
    mov $8, %ebx
    int $0x80

使用以下链接器脚本,我得到一个 2+ MB 的可执行文件:

SECTIONS
{
    . = 0x400000;
    .text : { *(.text) }
}

如果我添加 +SIZEOF_HEADERS,如下所示,我会得到一个 568 字节的可执行文件:

SECTIONS
{
    . = 0x400000 + SIZEOF_HEADERS;
    .text : { *(.text) }
}

根据LD 文档,此函数返回输出文件标题的大小。手动设置偏移量以包含标头大小也会产生一个 568 字节的可执行文件:

SECTIONS
{
    . = 0x400078;
    .text : { *(.text) }
}

如果我将 .text 进一步向下移动,则可执行文件开始扩展。以下产生一个 65984 字节的可执行文件:

SECTIONS
{
    . = 0x410000;
    .text : { *(.text) }
}

所以基本上,据我所知,似乎:

  • 第一个输出部分似乎与输出文件头共享一个内存页面。如果第一部分与标题重叠,LD 在输出第一部分之前发出一整页的填充字节以避免冲突
  • 要解决此问题,请将第一个输出部分的输出地址设置为 X + SIZEOF_HEADERS。这就是 LD 的内置链接器脚本所做的(您可以通过运行“ld --verbose”来查看)
于 2015-06-14T03:54:12.587 回答
6

使用 ld(或 gcc)尝试以下命令行选项:

-z max-page-size=0x1000
于 2016-01-23T21:51:35.313 回答
5

默认情况下ld,页面对齐输入部分。由于您的内核强制执行超级页面(2MB 的页面 = 0x200000 字节),因此您的.text部分在偏移量 0x200000 处对齐。这似乎是一个错误,ld因为它应该使用偏移量 0x0000000 代替(请参阅下面的编辑以获取可能的解释)

为了防止这种对齐会创建一个更大的文件,您可以使用--nmagicld 标志来防止它对您的 .text 部分进行页面对齐,尽管它有副作用(它也禁用与共享库的链接)。但要小心将其他部分(.data, .rodata,...)与 2M 页对齐,因为它们不能与 .text 位于同一页中,因为所有这些部分都需要不同的访问位。

编辑:考虑一下,我们都希望访问虚拟地址 0x00000000 会产生异常(段错误)。为此,我看到了两种可能性:内核映射一个没有访问权限(r/w/x)的页面,或者(更有可能)它根本不映射任何东西(没有映射页面=> segfault)并且链接器必须以某种方式知道...这可以解释为什么 ld 跳过地址为零的第一页。这是待定。

于 2014-09-09T23:41:56.370 回答