"The C calling convention on x86 systems specifies that callees need to save certain registers."
Practically speaking is this the prologue that that C run time - crt0.o provides automatically/implicitly?
"The C calling convention on x86 systems specifies that callees need to save certain registers."
Practically speaking is this the prologue that that C run time - crt0.o provides automatically/implicitly?
crt0.o is the glue between how the kernel loads a program into memory and how main() expects things to work. it does basic setup tasks that can vary between platforms, but is generally things like collecting command line arguments and setting up the stack. it will also invoke exit() if main() returns, since that's how the kernel expects the process to be destroyed
When you say "how the kernel loads a program into memory" I assume you are referring to ld-linux.so.2? Is that correct?
I imagine then that ld-linux.so.2 calls __start in crt0.o and crt0.o jumps to main(). Is this correct?
maps the executable to memory, and if an elf interpreter (/lib/ld-linux.so) is specified (which it normally is) also the elf interpreter.
It then jumps to the entry point of the raw binary or of the elf interpreter.
Its easy to sometimes conceptually think or talk about "a loader" as if its some standalone entity. However this can be misleading(at least to me anyway.) Because in reality its linked into every dynamically-linked binary, along with crt0.o which as the other poster mentioned takes care of some ABI requirements and the setting up of the stack.
For anyone else who might be interested this also an illuminating source code file to read, libc-start. Which would be part of crt0.o
http://repo.or.cz/glibc.git/blob/HEAD:/csu/libc-start.c#l105
I don't have to think this low level on any kind of regular basis but its a great thought exercise to do so from time to time.
I think your "normally" means "in case of dynamically linked executables".