Disassembly — objdump, reading assembly
WHY does disassembly exist?
WHY you care (the 80/20):
- A crash gives you a faulting address, not a line of C. Disassembly bridges that gap.
- Optimizers reorder/delete your code. The only ground truth is the emitted instructions.
- Security/reverse engineering: you often have no source, only the binary.
The full pipeline:
Disassembly runs that arrow backwards from the .o or executable.
HOW to invoke objdump
WHY two syntaxes exist: historical. GNU defaults to AT&T (mov %eax, %ebx
means ebx = eax, src→dst, registers prefixed %, immediates $). Intel
(mov ebx, eax means ebx = eax, dst←src) reads like math assignment. We use Intel
because it matches how you think: dst = src.
WHAT a disassembly line looks like

A single line has four columns:
1149: 48 83 ec 08 sub rsp, 0x8
^addr ^raw bytes ^mnemonic ^operands
- address
1149: offset/virtual address of this instruction. - raw bytes
48 83 ec 08: the actual machine code (variable length on x86). - mnemonic
sub: the operation. - operands
rsp, 0x8: what it operates on.
Reading a real function from scratch (DERIVATION)
Source:
int add(int a, int b) {
return a + b;
}Compile: gcc -O0 -g -c add.c then objdump -d -M intel add.o:
0000000000000000 <add>:
0: 55 push rbp ; save caller's frame ptr
1: 48 89 e5 mov rbp, rsp ; set up new frame
4: 89 7d fc mov [rbp-0x4], edi ; spill arg a (edi) to stack
7: 89 75 f8 mov [rbp-0x8], esi ; spill arg b (esi) to stack
a: 8b 55 fc mov edx, [rbp-0x4] ; load a
d: 8b 45 f8 mov eax, [rbp-0x8] ; load b
10: 01 d0 add eax, edx ; eax = b + a
12: 5d pop rbp ; restore frame
13: c3 ret ; return (result in eax)Reading it line-by-line — Why this step?
push rbp / mov rbp,rsp— Why? Standard function prologue: saves the old base pointer and establishes a stable reference frame for locals.mov [rbp-0x4], edi— Why? The System V x86-64 calling convention passes arg 1 inedi, arg 2 inesi. At-O0the compiler immediately spills them to stack.add eax, edx— Why eax? The convention returns integers in==rax/eax==. So the compiler arranges the result there.ret— pops the return address and jumps to it.
Control flow: how if/loops look
Common mistakes
Flashcards
What does objdump -d do?
.text) sections of an object file/binary into assembly.What does the -M intel flag change?
%/$ sigils).In Intel syntax, what does mov rbp, rsp mean?
rbp = rsp (destination first, source second).What are the 4 columns of an objdump line?
Why are x86 instructions variable length?
48 = 64-bit operand).Where is an integer return value placed (System V x86-64)?
rax/eax.Which registers hold the first two integer args (System V x86-64)?
rdi (arg1) and rsi (arg2); 32-bit views edi, esi.What is the standard function prologue?
push rbp then mov rbp, rsp to save/establish the stack frame.What does cmp a, b actually do?
a - b, discards the result, but sets the CPU flags so a following conditional jump can use them.Why does lea eax, [rdi+rsi] appear instead of an add?
lea's address arithmetic to add two registers in one instruction with no flag side effects.What flag interleaves C source with assembly?
-S (requires the binary compiled with -g debug info).Difference between objdump -d and -D?
-d disassembles only executable sections; -D disassembles ALL sections (data may show as garbage instructions).Recall Feynman: explain to a 12-year-old
A recipe written in English (your code) gets turned into a secret number-code that the
robot chef (CPU) understands. Once it's numbers, you can't read it anymore.
Disassembly is a decoder ring: it turns those numbers back into short English-ish
words like "add", "jump", "copy" so you can check the robot is cooking what you wanted —
not pizza when you asked for cake. objdump is that decoder ring.
Connections
- Compilation Pipeline — disassembly is the reverse of the assemble step.
- Calling Conventions (System V x86-64) — explains
rdi,rsi,raxusage. - Stack Frames & The Stack Pointer — prologue/epilogue
push rbp/sub rsp. - Compiler Optimization Levels —
-O0vs-O2and what the asm reveals. - Debugging with GDB —
disassembleandlayout asmuse the same decoding. - ELF Object Files & Sections —
.text,.data, relocations that-rshows. - CISC vs RISC — why x86 encodings are variable length.
Concept Map
Hinglish (regional understanding)
Intuition Hinglish mein samjho
Dekho, jab tum .c file likhte ho, woh sirf humans ke liye hai. CPU ko sirf bytes
(machine code) samajh aata hai. Compiler tumhare code ko in bytes me badal deta hai. Ab
problem ye hai ki bytes ko padhna impossible hai. Yahan disassembly kaam aata hai — ye
ulta kaam karta hai, bytes ko wapas mov, add, jump jaise readable words me convert
kar deta hai. Aur jo tool ye karta hai usko bolte hai objdump. Command simple hai:
objdump -d -M intel ./a.out. -d matlab disassemble, aur -M intel matlab Intel syntax
(jisme mov dst, src matlab dst = src, bilkul maths jaisa).
Har line ke 4 parts hote hai — yaad rakho A-B-M-O: Address, Bytes, Mnemonic, Operands.
Jaise 1149: 48 83 ec 08 sub rsp, 0x8. Yahan 1149 address hai, 48 83 ec 08 actual
bytes hai, sub operation hai, aur rsp, 0x8 operands. x86 me instructions ki length fixed
nahi hoti (CISC hai), isliye kabhi 1 byte kabhi 15 byte — ye ARM se alag hai.
Isko padhna kyun important hai? Kyunki jab tumhara program crash hota hai, tumhe ek address
milta hai, line number nahi. Disassembly us gap ko bridge karti hai. Aur sabse mazedaar baat
— jab -O2 optimization on karte ho, compiler tumhare a+b ko poora stack frame banaye
bina sirf ek lea eax, [rdi+rsi] me kar deta hai. Ye dekh ke tumhe pata chalta hai compiler
ne actually kya kiya. Galti se mat sochna ki "zyada instructions = slow" — ek div 30 cycle
le sakta hai, dus mov sirf 3. Count nahi, kya chal raha hai woh dekho, phir profile karo.