天天看點

c語言編譯後生成elf,C源檔案到ELF的編譯過程

You can download from site:

預備知識,閱讀文章“as中常見僞指令.word .align .balign[lw] .macro .globl”

C源檔案到ELF可執行檔案的生成過程

1. 編譯器的預處理

2. C源代碼轉換為彙編代碼

3. 生成目标檔案

4. 将目标檔案連結為ELF可執行檔案

ELF檔案類型共有4種類型

1. 可重定位檔案relocatable file

執行file xx.o,其中xx表示編譯過程生成的目标檔案

傳回ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped

2. 可執行檔案executable file

執行file /bin/sh

ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped

3. 共享目标檔案share object file

執行file /lib/libmemusage.so

/lib/libmemusage.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, stripped

4. 核心轉儲檔案core dump file

執行file /proc/kcore

ELF 32-bit LSB core file Intel 80386, version 1 (SYSV), SVR4-style, from '-3b3e-428f-91d0-1a730571'

編寫C代碼

現在通過舉例說明整個編譯過程,首先建立show.c和mian.c檔案,其中show.c檔案的内容如下

#include

void show()

{

printf ("this program is used to test ld\n");

}

mian.c的内容如下

extern void show();

int main()

{

show();

return 0;

}

C源代碼轉換為彙編代碼

用gcc加上-save-temps選項編譯完成以後,可以看到彙編檔案show.s内容如下

.file  "show.c"

.section    .rodata

.align 4

.LC0:

.string      "this program is used to test ld"

.text

.globl show

.type         show, @function

show:

pushl         %ebp

movl          %esp, %ebp

subl  $24, %esp

movl          $.LC0, (%esp)

call   puts

leave

ret

.size show, .-show

.ident        "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"

.section    .note.GNU-stack,"",@progbits

從彙編檔案show.s裡可以發現彙編檔案裡包含了很多的僞指令,其中align4表示16位元組對齊,globl是的show符号對ld可見,即全局的。所有彙編檔案.text section最後都會放在ELF檔案的.text section

生成目标檔案

對show.o進行反彙編(objdump –d show.o)

Disassembly of section .text:

00000000 :

0:        55                                push   %ebp

1:        89 e5                           mov    %esp,%ebp

3:        83 ec 18                      sub    $0x18,%esp

6:        c7 04 24 00 00 00 00                movl   $0x0,(%esp)

d:        e8 fc ff ff ff                                 call    e

12:       c9                               leave

13:       c3                               ret

對main.o進行反彙編(objdump –d main.o)

Disassembly of section .text:

00000000 :

0:        55                              push   %ebp

1:        89 e5                         mov    %esp,%ebp

3:        83 e4 f0                     and    $0xfffffff0,%esp

6:        e8 fc ff ff ff                           call   7

b:        b8 00 00 00 00                    mov    $0x0,%eax

10:        89 ec                         mov    %ebp,%esp

12:        5d                              pop    %ebp

13:        c3                              ret

而目标檔案的生成也很簡單,隻是把彙編檔案進行編譯為對應機器碼。該過程沒有按照僞指令進行對齊邊界,也沒有進行的位址修正,對需要修正的位址隻是在目前位址上+1.

将目标檔案連結為ELF可執行檔案

連結器最後将所有的目标檔案連結為ELF可執行檔案,對ELF檔案反彙編内容如下

080483e4 :

80483e4:        55                             push   %ebp

80483e5:        89 e5                        mov    %esp,%ebp

80483e7:        83 e4 f0                    and    $0xfffffff0,%esp

80483ea:        e8 09 00 00 00         call        80483f8

80483ef:         b8 00 00 00 00         mov    $0x0,%eax

80483f4:         89 ec                         mov    %ebp,%esp

80483f6:         5d                             pop    %ebp

80483f7:         c3                              ret

080483f8 :

80483f8:         55                                 push   %ebp

80483f9:         89 e5                            mov    %esp,%ebp

80483fb:         83 ec 18                       sub    $0x18,%esp

80483fe:         c7 04 24 d0 84 04 08   movl   $0x80484d0,(%esp)

8048405:        e8 0e ff ff ff                   call   8048318

804840a:        c9                                 leave

804840b:        c3                                 ret

804840c:        90                                 nop

804840d:        90                                nop

804840e:        90                                nop

804840f:         90                                nop

在連結器連結完成以後可以看出main函數調用show函數的位址和show函數對printf函數的位址都變成絕對位址,而且程式在最後加入了4條nop操作,使得以16位元組對齊。