UP | HOME

Source to Process
Compilers
COP-3402

How your C program gets run

source_to_process.svg

The five steps:

cat > hello.c << EOT
#include <stdio.h>
int main() { printf("hello, world!\n"); }
EOT
gcc -E hello.c -o hello.i
gcc -S hello.i -o hello.s
as hello.s -o hello.o
ld /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/libc.so hello.o -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o hello
./hello

The five steps, with commands to inspect the outputs:

cat hello.c
gcc -E hello.c -o hello.i
cat hello.i
gcc -S hello.i -o hello.s
cat hello.s
as hello.s -o hello.o
objdump -d hello.o
objdump -t hello.o
ld /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/libc.so hello.o -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o hello
objdump -d hello
objdump -t hello

The five steps, but with static linking:

cat > hello.c << EOT
#include <stdio.h>
int main() { printf("hello, world!\n"); }
EOT
gcc -E hello.c -o hello.i
gcc -S hello.i -o hello.s
as hello.s -o hello.o
# gcc -v -static -o hello hello.o
ld -static -o hello /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/13/crtbeginT.o -L/usr/lib/gcc/x86_64-linux-gnu/13 -L/usr/lib/x86_64-linux-gnu -L/usr/lib -L/lib/x86_64-linux-gnu -L/lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/13/../../.. hello.o --start-group -lgcc -lgcc_eh /usr/lib/x86_64-linux-gnu/libc.a --end-group /usr/lib/gcc/x86_64-linux-gnu/13/crtend.o /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crtn.o
./hello

Separate compilation

Preprocessing

  • Caller
  • Callee
  • Header files

Linking

objdump -t

C runtime

  • main vs. _start

Application binary interface

Application binary interface (ABI)

  • Calling conventions and stack frame layout
    • How to pass parameters
    • Layout of data in the stack frame
    • How to return values
    • Caller and callee responsbilities
  • Architecture- and OS-dependent

Parameter passing

  • Registers and/or stack
  • Registers are faster, but limited in number
  • May need to save them before making call

Stack frame (or activation record)

  • Holds all information needed to "freeze" state of function
    • Parameters and local variables
    • Return address
    • Caller's stack frame (nested calls)

Intel x86-64 support for functions

  • %rbp - base pointer points to the current function's stack frame
  • %rsp - stack pointer points to the top of the stack
  • push/pop - push to and pop from the stack (move data and update %rsp)
  • call - saves next instruction address (%rip) onto stack and branches to function's address
  • ret - pops the caller's next instruction address and branches to it

Recall that "points to" just means that the register holds an address

Writing and calling ABI-compatible functions

Recall that compiler is printing out instructions that will implement the stack at runtime, not actually creating the stack while compiling.

# https://github.com/longld/peda
# for C compile with -g for debug symbols
# run gdb
gdb example
b main # break at main
si # step instruction, assembly instructions (intead of code)
info file # get address of rodata
x/8xb 0x0000555555556000 # print memory, 8 he(x) (b)ytes
x/i addr # print as instruction

# dump symtab
objdump -s test

gdb resources:

https://sourceware.org/gdb/onlinedocs/gdb/Memory.html

https://sourceware.org/gdb/onlinedocs/gdb/Registers.html#Registers

https://visualgdb.com/gdbreference/commands/set_disassembly-flavor

http://dbp-consulting.com/tutorials/debugging/basicAsmDebuggingGDB.html

https://github.com/longld/peda

https://sourceware.org/gdb/onlinedocs/gdb/Auto-Display.html#Auto-Display https://sourceware.org/gdb/onlinedocs/gdb/Continuing-and-Stepping.html https://sourceware.org/binutils/docs-2.16/as/index.html https://sourceware.org/binutils/docs/as/i386_002dMemory.html

Further reading

Author: Paul Gazzillo

Created: 2025-03-10 Mon 08:07

Validate