Pengaruh tautan statis dan dinamis pada alamat mulai

8

Saya punya program C sederhana. Saya berlari:

$ gcc Q1.c -Wall -save-temps -o Q1

Kemudian saya memeriksa executable yang dihasilkan:

$  objdump -f Q1
Q1:     file format elf32-i386
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x080483b0

Lalu saya kompilasi dengan tautan statis:

$ gcc Q1.c -Wall -save-temps -static -o Q1

dan periksa kembali file tersebut:

$ objdump -f Q1
Q1:     file format elf32-i386
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x08048e08

Apa pengaruh tautan statis dan dinamis terhadap alamat awal program? Alamat awal adalah alamat main(), bukan?

ArunMumar
sumber

Jawaban:

10

Alamat awal adalah alamat main(), bukan?

Tidak juga: Awal dari sebuah program tidak juga main(). Secara default, GCC akan menghasilkan executable yang alamat awalnya sesuai dengan _startsimbol. Anda dapat melihatnya dengan melakukan a objdump --disassemble Q1. Inilah hasil dari program sederhana saya yang hanya berlaku return 0;di main():

0000000000400e30 <_start>:
  400e30:       31 ed                   xor    %ebp,%ebp
  400e32:       49 89 d1                mov    %rdx,%r9
  400e35:       5e                      pop    %rsi
  400e36:       48 89 e2                mov    %rsp,%rdx
  400e39:       48 83 e4 f0             and    $0xfffffffffffffff0,%rsp
  400e3d:       50                      push   %rax
  400e3e:       54                      push   %rsp
  400e3f:       49 c7 c0 a0 15 40 00    mov    $0x4015a0,%r8
  400e46:       48 c7 c1 10 15 40 00    mov    $0x401510,%rcx
  400e4d:       48 c7 c7 40 0f 40 00    mov    $0x400f40,%rdi
  400e54:       e8 f7 00 00 00          callq  400f50 <__libc_start_main>
  400e59:       f4                      hlt    
  400e5a:       66 90                   xchg   %ax,%ax
  400e5c:       0f 1f 40 00             nopl   0x0(%rax)

Seperti yang dapat Anda lihat di address 400e54, _start()pada gilirannya memanggil __libc_start_main, yang menginisialisasi hal-hal yang diperlukan (pthreads, atexit, ...) dan akhirnya memanggil main()dengan argumen yang sesuai (argc, argv dan env).

Oke, tapi apa hubungannya dengan perubahan alamat awal?

Ketika Anda bertanya gccuntuk menghubungkan secara statis, itu berarti bahwa semua inisialisasi yang saya sebutkan di atas harus dilakukan menggunakan fungsi yang ada di executable. Dan memang jika Anda melihat ukuran kedua executable, Anda akan menemukan bahwa versi statis jauh lebih besar. Pada pengujian saya, versi statis adalah 800 ribu sementara versi bersama hanya 6 ribu.

Fungsi-fungsi ekstra kebetulan ditempatkan sebelumnya _start(), maka perubahan alamat mulai. Berikut tata letak dari eksekusi statis di sekitar start():

000000000049e960 r translit_from_tbl
0000000000400a76 t _i18n_number_rewrite
0000000000400bc0 t fini
0000000000400bd0 t init_cacheinfo
0000000000400e30 T _start
0000000000400e60 t deregister_tm_clones
0000000000400e90 t register_tm_clones
0000000000400ed0 t __do_global_dtors_aux

Dan inilah tata letak dari executable bersama:

00000000004003c0 T _start
00000000004003f0 t deregister_tm_clones
00000000004004b0 T main
00000000004004c0 T __libc_csu_init
00000000006008a0 B _end
0000000000400370 T _init

Akibatnya, saya mendapatkan alamat mulai yang sedikit berbeda: 0x400e30 dalam kasus statis dan 0x4003c0 dalam kasus bersama.

Frederik Deweerdt
sumber