Влияние статической и динамической привязки на начальный адрес

У меня простая программа на 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) 

Как вы можете видеть по адресу 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 в общем случае.