2013-03-14 115 views
2

我正在使用binutils-2.21.53.0.1-6.fc16.x86_64ld連接器腳本產生巨大的二進制文件

我有一個小的目標文件,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 

這已經不管我的鏈接腳本的內容發生。任何想法發生了什麼?

+0

你還有符號表嗎? – 2013-03-14 08:06:35

+0

你可以看到有一個'.symtab'節,它的長度與這個問題無關。 – 2013-03-15 02:31:01

回答

5

默認ld頁面對齊輸入部分。由於您的內核執行超級頁面(2MB = 0x200000字節的頁面),因此您的.text部分在偏移量0x200000處對齊。這似乎是在ld一個錯誤,因爲它應該使用偏移0x0000000代替(參見下面編輯一個可能的解釋)

爲了防止這種對準它創建了一個更大的文件,你可以使用--nmagic標誌LD以防止頁面 - 儘管它有副作用(它也會禁止鏈接到共享庫),所以請對齊.text部分。請小心,但要將其他部分(.data.rodata,...)與2M頁面對齊,因爲它們不能與.text生活在同一頁面,因爲所有這些部分都需要不同的訪問位。編輯:思考它,我們都期望訪問虛擬地址0x00000000來生成異常(段錯誤)。爲此,我看到兩種可能性:內核映射沒有訪問權限(r/w/x)的頁面或(更可能)它沒有映射任何內容(沒有頁面映射=>段錯誤)並且鏈接器必須不知怎的......這可以解釋爲什麼ld跳過地址爲零的第一頁。這是TBC。

+2

感謝你們--nmagic',這是漫長旅程的結束。 – rpjohnst 2014-11-09 00:55:55

5

今天我在學習鏈接器腳本時遇到了同樣的問題。 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 documentation,這個函數返回的輸出文件的頭的大小。手動設置偏移包括頭的大小也產生一個568字節的可執行文件:

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

如果我提出的.text進一步下降,可執行開始擴大。下面產生一個65984字節的可執行文件:

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

所以基本上,從我可以告訴,看來:

  • 第一輸出部分似乎與輸出文件頭共享一個內存頁。如果第一部分與標題重疊,則LD在輸出第一部分之前發出整頁填充字節以避免衝突
  • 要解決此問題,請將第一個輸出部分的輸出地址設置爲X + SIZEOF_HEADERS。這就是內置的LD連接腳本不(您可以通過運行「LD --verbose」看看)
3

試着用LD(或GCC)以下命令行選項:

-z max-page-size=0x1000 
相關問題