C
靜態和動態連結對起始地址的影響
我有一個簡單的 C 程序。我跑:
$ gcc Q1.c -Wall -save-temps -o Q1
然後我檢查生成的執行檔:
$ objdump -f Q1 Q1: file format elf32-i386 architecture: i386, flags 0x00000112: EXEC_P, HAS_SYMS, D_PAGED start address 0x080483b0
然後我用靜態連結編譯它:
$ gcc Q1.c -Wall -save-temps -static -o Q1
並再次檢查文件:
$ objdump -f Q1 Q1: file format elf32-i386 architecture: i386, flags 0x00000112: EXEC_P, HAS_SYMS, D_PAGED start address 0x08048e08
靜態連結和動態連結對程序的起始地址有什麼影響?起始地址是 的地址
main()
,對吧?
起始地址是 的地址
main()
,對吧?不是真的:程序的開始不是真的
main()
。預設情況下,GCC 將生成起始地址與_start
符號對應的執行檔。您可以通過執行objdump --disassemble Q1
. 這是我的一個簡單程序的輸出,它只return 0;
在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)
正如您在 address 看到的那樣
400e54
,_start()
依次呼叫__libc_start_main
,它初始化必要的東西(pthreads,atexit,…),最後main()
使用適當的參數(argc,argv 和 env)進行呼叫。好的,但它與起始地址更改有什麼關係?
當您要求
gcc
靜態連結時,這意味著我上面提到的所有初始化都必須使用執行檔中的函式完成。實際上,如果您查看兩個執行檔的大小,您會發現靜態版本要大得多。在我的測試中,靜態版本是800K,而共享版本只有6K。額外的函式恰好放在 之前
_start()
,因此起始地址發生了變化。這是周圍的靜態執行檔的佈局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
這是共享執行檔的佈局:
00000000004003c0 T _start 00000000004003f0 t deregister_tm_clones 00000000004004b0 T main 00000000004004c0 T __libc_csu_init 00000000006008a0 B _end 0000000000400370 T _init
結果,我得到的起始地址略有不同:靜態情況下的 0x400e30 和共享情況下的 0x4003c0。