Skip to content

Lesson 1 of 9 · 20m

What the Compiler Actually Throws Away

A binary is the fossil record of a program — mechanism survives, intent is erased. Learn which artifacts are still legible before you try to read them.

Every binary you open is the fossil record of a program. The compiler took source — intent, names, structure — and kept only the mechanism: instructions, data layouts, and whatever strings and symbols happened to survive. New reversers think the job is reading assembly. It isn't. The job is reconstructing intent from mechanism, and knowing exactly which parts of the fossil are still legible.

What survives compilation

  • Instructions and control flow — the mechanism, faithfully preserved, though rearranged and optimized past recognition of the source text.
  • Constants and string literals — format strings, error messages, magic numbers, crypto tables. Often the most legible artifact in the whole file.
  • Imported function names — calls into libc or WinAPI keep their names because the dynamic linker needs them at load time.
  • Sometimes, symbols — function names in .symtab, if nobody ran strip. Check before assuming the worst.

What gets erased

  • Variable names, type declarations, comments — gone entirely.
  • Function boundaries become conventions, not facts: a "function" is just a call target with a prologue-like shape.
  • if, while, for, and switch all collapse into the same primitive — compare, set flags, conditional jump.
  • Data structures dissolve into pointer arithmetic. user->name becomes mov rax, [rdi+0x18] and nothing tells you that offset 0x18 was called name.

The ELF, at rest

$ file crackme
crackme: ELF 64-bit LSB pie executable, x86-64, dynamically linked, stripped
$ readelf -S crackme | grep -E "text|rodata|data"
[13] .text     PROGBITS   0000000000001060  001060  0001a3
[15] .rodata   PROGBITS   0000000000002000  002000  000048
[23] .data     PROGBITS   0000000000004010  003010  000010

.text is code, .rodata is constants and strings, .data is initialized globals, .bss is zero-initialized globals that take no file space. A stripped, PIE, dynamically-linked binary is the default posture — assume it until proven otherwise.

What survives compilation

Field notes

  • Run file and strings before anything else — thirty seconds of triage tells you architecture, packing, and whether symbols exist.
  • Unstripped symbols are a gift, not the norm. nm -C on a C++ binary even demangles the names for you.
  • A -g debug build embeds DWARF: full line numbers, types, struct layouts. If you find one, the job just changed category — load it into the debugger, not just the disassembler.