開始アドレスはのアドレス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です。