天天看點

[筆記二]探究編譯與連結之目标檔案目标檔案

目标檔案

目标檔案的格式

目标檔案在Linux下面以ELF格式存儲,ELF檔案标準裡面把系統中采用ELF格式的檔案歸為以下4類:

ELF檔案類型 說明 執行個體
可重定位檔案(Relocatable File) 這類檔案包含了代碼和資料,可以被用來連結成可執行檔案或共享目标檔案,靜态連結庫也可以歸為這一類 Linux的.o檔案
可執行檔案(Executable File) 這類檔案包含了可以直接執行的程式,它的代表就是ELF可執行檔案,它們一般都沒有擴充名 比如/bin/bash檔案
共享目标檔案(Shared Object File) 這種檔案包含了代碼和資料,可以在以下兩種情況下使用,一種是連結器可以使用這種檔案跟其它的可重定位檔案和共享目标檔案連結,産生新的目标檔案。第二種是動态連結器可以将幾個這樣的共享目标檔案與可執行檔案結合,作為程序印像的一部分來運作 Linux的.so
核心轉儲檔案(Core Dump File) 當程序意外終止時,系統可以将該程序的位址空間的内容及終止時的一些其他資訊轉儲到核心轉儲檔案 Linux下的core dump

在Linux下我們檢視檔案格式的方式可以如此:

$file hello.o
hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
$file /bin/bash
/bin/bash: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, stripped
$file /lib/ld-2.12.so
/lib/ld-2.12.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, not stripped
           

目标檔案的構成

程式源代碼編譯後的機器指令經常被放在代碼段(Code Section)裡,代碼段常見的名字有“.text”或“.code”;全局變量和局部靜态變量資料經常放在資料段(Data Section),資料段的一般名字都叫“.data”。

真正了不起的程式員對自己的程式的每一個位元組都了如指掌。
                                                -共勉之
           

執行個體解析

示例代碼如下(SimpleSection.c)

int printf(const char *format, ...);

//__attribute__((section("Demon"))) int global_init_var = 84;
int global_init_var = 84;

int global_uninit_var;

void func1(int i)
{
    printf("%d\n",i);
}

int main(void)
{
    static int static_var = 85;
    static int static_var2;

    int a = 1;
    int b;
    func1(static_var + static_var2 + a + b);
    return 0;
}
           

編譯擷取.o檔案:

$gcc -c SimpleSection.c
           

我們來看看該目标檔案(SimpleSection.o)内部的結構:

$objdump -h SimpleSection.o

SimpleSection.o:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
0 .text         00000056  0000000000000000  0000000000000000  00000040  2**2
              CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data         00000008  0000000000000000  0000000000000000  00000098  2**2
              CONTENTS, ALLOC, LOAD, DATA
2 .bss          00000004  0000000000000000  0000000000000000  000000a0  2**2
              ALLOC
3 .rodata       00000004  0000000000000000  0000000000000000  000000a0  2**0
              CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .comment      00000012  0000000000000000  0000000000000000  000000a4  2**0
              CONTENTS, READONLY
5 .note.GNU-stack 00000000  0000000000000000  0000000000000000  000000b6  2**0
              CONTENTS, READONLY
6 .eh_frame     00000058  0000000000000000  0000000000000000  000000b8  2**3
              CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
           

這樣來看的話,目标檔案不隻之前提到的代碼段和資料段,還有存放未初始化變量的BSS段、隻讀資料段(.rodata)、注釋資訊段(.comment)和堆棧提示段(.note.GNU-stack)。

Size代表段的大小,File off 代表段所在的位置;

每個段的第二行中的“CONTENTS”、“ALLOC”等表示段的各種屬性,比較重要的是“CONTENTS”表示該段在檔案中存在,對比上面目标檔案的結構,你會發現.bss段沒有CONTENTS屬性,即.bss段并不會在檔案中存在。

有一個專門的指令“size”用來檢視ELF檔案的代碼段、資料段和BSS段的長度(dec表示三個段長度和的十進制,hex表示長度和的十六進制)

$size SimpleSection.o
text       data     bss     dec     hex filename
178       8       4     190      be SimpleSection.o
           

段的說明

段名 說明
.text 存放代碼片段
.date 存放初始化了的全局靜态變量和局部靜态變量
.rodata 存放的是隻讀變量,比如const修飾的變量
.bss 存放未初始化的全局變量和局部靜态變量

來檢視下目标檔案SimpleSection.o的段資訊:

$objdump -x -s -d SimpleSection.o
SimpleSection.o:     file format elf64-x86-64
SimpleSection.o
architecture: i386:x86-64, flags 0x00000011:
HAS_RELOC, HAS_SYMS
start address 0x0000000000000000

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
0 .text         00000056  0000000000000000  0000000000000000  00000040  2**2
              CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data         00000008  0000000000000000  0000000000000000  00000098  2**2
              CONTENTS, ALLOC, LOAD, DATA
2 .bss          00000004  0000000000000000  0000000000000000  000000a0  2**2
              ALLOC
3 .rodata       00000004  0000000000000000  0000000000000000  000000a0  2**0
              CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .comment      00000012  0000000000000000  0000000000000000  000000a4  2**0
              CONTENTS, READONLY
5 .note.GNU-stack 00000000  0000000000000000  0000000000000000  000000b6  2**0
              CONTENTS, READONLY
6 .eh_frame     00000058  0000000000000000  0000000000000000  000000b8  2**3
              CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 SimpleSection.c
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 l    d  .data  0000000000000000 .data
0000000000000000 l    d  .bss   0000000000000000 .bss
0000000000000000 l    d  .rodata    0000000000000000 .rodata
0000000000000004 l     O .data  0000000000000004 static_var.1713
0000000000000000 l     O .bss   0000000000000004 static_var2.1714
0000000000000000 l    d  .note.GNU-stack    0000000000000000 .note.GNU-stack
0000000000000000 l    d  .eh_frame  0000000000000000 .eh_frame
0000000000000000 l    d  .comment   0000000000000000 .comment
0000000000000000 g     O .data  0000000000000004 global_init_var
0000000000000004       O *COM*  0000000000000004 global_uninit_var
0000000000000000 g     F .text  0000000000000021 func1
0000000000000000         *UND*  0000000000000000 printf
0000000000000021 g     F .text  0000000000000035 main

Contents of section .text:
0000 554889e5 4883ec10 897dfc8b 45fc89c6  UH..H....}..E...
0010 bf000000 00b80000 0000e800 000000c9  ................
0020 c3554889 e54883ec 10c745fc 01000000  .UH..H....E.....
0030 8b150000 00008b05 00000000 01c28b45  ...............E
0040 fc01c28b 45f801d0 89c7e800 000000b8  ....E...........
0050 00000000 c9c3                        ......
Contents of section .data:
0000 54000000 55000000                    T...U...
Contents of section .rodata:
0000 25640a00                             %d..
Contents of section .comment:
0000 00474343 3a202847 4e552920 342e372e  .GCC: (GNU) 4.7.
0010 3300                                 3.
Contents of section .eh_frame:
0000 14000000 00000000 017a5200 01781001  .........zR..x..
0010 1b0c0708 90010000 1c000000 1c000000  ................
0020 00000000 21000000 00410e10 8602430d  ....!....A....C.
0030 065c0c07 08000000 1c000000 3c000000  .\..........<...
0040 00000000 35000000 00410e10 8602430d  ....5....A....C.
0050 06700c07 08000000                    .p......

Disassembly of section .text:

0000000000000000 <func1>:
0:  55                      push   %rbp
1:  48 89 e5                mov    %rsp,%rbp
4:  48 83 ec 10             sub    $0x10,%rsp
8:  89 7d fc                mov    %edi,-0x4(%rbp)
b:  8b 45 fc                mov    -0x4(%rbp),%eax
e:  89 c6                   mov    %eax,%esi
10: bf 00 00 00 00          mov    $0x0,%edi
        11: R_X86_64_32 .rodata
15: b8 00 00 00 00          mov    $0x0,%eax
1a: e8 00 00 00 00          callq  1f <func1+0x1f>
        1b: R_X86_64_PC32   printf-0x4
1f: c9                      leaveq
20: c3                      retq

0000000000000021 <main>:
21: 55                      push   %rbp
22: 48 89 e5                mov    %rsp,%rbp
25: 48 83 ec 10             sub    $0x10,%rsp
29: c7 45 fc 01 00 00 00    movl   $0x1,-0x4(%rbp)
30: 8b 15 00 00 00 00       mov    0x0(%rip),%edx        # 36 <main+0x15>
        32: R_X86_64_PC32   .data
36: 8b 05 00 00 00 00       mov    0x0(%rip),%eax        # 3c <main+0x1b>
        38: R_X86_64_PC32   .bss-0x4
3c: 01 c2                   add    %eax,%edx
3e: 8b 45 fc                mov    -0x4(%rbp),%eax
41: 01 c2                   add    %eax,%edx
43: 8b 45 f8                mov    -0x8(%rbp),%eax
46: 01 d0                   add    %edx,%eax
48: 89 c7                   mov    %eax,%edi
4a: e8 00 00 00 00          callq  4f <main+0x2e>
        4b: R_X86_64_PC32   func1-0x4
4f: b8 00 00 00 00          mov    $0x0,%eax
54: c9                      leaveq
55: c3                      retq
           

繼續閱讀