L'adresse de départ est l'adresse de main()
, non?
Pas vraiment: le début d'un programme ne l'est pas vraiment main()
. Par défaut, GCC produira des exécutables dont l'adresse de début correspond au _start
symbole. Vous pouvez le voir en faisant un objdump --disassemble Q1
. Voici le résultat sur un programme simple à moi qui ne fait que return 0;
dans 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)
Comme vous pouvez le voir à l'adresse 400e54
, _start()
invoque à son tour __libc_start_main
, ce qui initialise les éléments nécessaires (pthreads, atexit, ...) et appelle finalement main()
avec les arguments appropriés (argc, argv et env).
D'accord, mais qu'est-ce que cela a à voir avec le changement d'adresse de départ?
Lorsque vous demandez un gcc
lien statique, cela signifie que toute l'initialisation que j'ai mentionnée ci-dessus doit être effectuée à l'aide de fonctions qui sont dans l'exécutable. Et en effet, si vous regardez la taille des deux exécutables, vous constaterez que la version statique est beaucoup plus grande. Sur mon test, la version statique est 800K tandis que la version partagée n'est que 6K.
Les fonctions supplémentaires se trouvent être placées avant _start()
, d'où le changement d'adresse de départ. Voici la disposition de l'exécutable statique autour 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
Et voici la disposition de l'exécutable partagé:
00000000004003c0 T _start
00000000004003f0 t deregister_tm_clones
00000000004004b0 T main
00000000004004c0 T __libc_csu_init
00000000006008a0 B _end
0000000000400370 T _init
Par conséquent, j'obtiens des adresses de départ légèrement différentes: 0x400e30 dans le cas statique et 0x4003c0 dans le cas partagé.