The start address is the address of main()
, right?
Not really: The start of a program isn't really main()
. By default, GCC will produce executables whose start address corresponds to the _start
symbol. You can see that by doing a objdump --disassemble Q1
. Here's the output on a simple program of mine that only does return 0;
in 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)
As you can see at address 400e54
, _start()
in turn invokes __libc_start_main
, which initializes the necessary stuff (pthreads, atexit,...) and finally calls main()
with the appropriate arguments (argc, argv and env).
Okay, but what does it have to do with the start address changing?
When you ask gcc
to link statically, it means that all the initialization that I mentioned above has to be done using functions that are in the executable. And indeed if you look at the sizes of both executables, you'll find that the static version is way larger. On my test, the static version is 800K while the shared version is only 6K.
The extra functions happen to be placed before _start()
, hence the change in start address. Here's the layout of the static executable around 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
And here's the layout of the shared executable:
00000000004003c0 T _start
00000000004003f0 t deregister_tm_clones
00000000004004b0 T main
00000000004004c0 T __libc_csu_init
00000000006008a0 B _end
0000000000400370 T _init
As a result, I get slightly different start addresses: 0x400e30 in the static case and 0x4003c0 in the shared case.