Here is a test reproducing the problem:
$ echo \"void whatever() {}\" > prog.c
$ gcc prog.c
This produces the following error on GCC 4.8.4:<
main
is not the start of program as you originally thought, c lib has a starter program (crt1.o
) which has a _start
program which will invoke our main
and do cleaning job after main
ELF has two headers, as following shows:
Here we only focus on section header structure:
mapping
// and special cases
mapping
Every program is compiled separately, which means address allocation is similar (In the early version of linux, every compiled program start with same virtual address -- 0x08000000
, and many attacks can make use of this, so it changes to adding some random delta to address to alleviate the problem), so there may exists some overlay area. This is why address relocation needed.
The relocation info (offset, value etc) is stored in .rel.*
section:
Relocation section '.rel.text' at offset 0x7a4 contains 2 entries:
Offset Info Type Sym.Value Sym. Name
0000000d 00000e02 R_386_PC32 00000000 main
00000015 00000f02 R_386_PC32 00000000 exit
Relocation section '.rel.debug_info' at offset 0x7b4 contains 43 entries:
Offset Info Type Sym.Value Sym. Name
00000006 00000601 R_386_32 00000000 .debug_abbrev
0000000c 00000901 R_386_32 00000000 .debug_str
When the linker want to set the address of main
in the process of relocation, it can't find a symbol in your compiled elf file, so it complains that and stop the linking process.
Here is the simplified version of os implementations, start.c corresponds to crt1.o
's source code:
int entry(char *); // corresponds to main
void _start(char *args) {
entry(args);
exit();
}