x86 Assembly
Table of Contents
x86 is a family of instruction set architectures based on the complex instruction set computer (CISC) architecture (unlike RISC-V). Here, we will focus on the 32-bit ISA, called IA-32 or i386. There are also two different syntaxes for IA-32 assembly, Intel and AT&T; the instructions below will use AT&T syntax.
1. Registers
x86 has only 8 general purpose registers (GPR):
| Register | Description |
|---|---|
ax |
accumulator |
bx |
base |
cx |
counter |
dx |
data |
sp |
stack pointer |
bp |
base pointer |
si |
source index |
di |
destination index |
Originally, these GPRs started as 16-bits. The 32-bit registers used in i386 are therefore denoted with the e prefix (e.g. eax for ax) and with the r prefix for 62-bits (e.g. rax for ax). The lower and upper 8 bits of each 16-bit register can also be explicitly addressed by replacing x with either l or h.
In AT&T syntax, registers are addressed using the percent sign (e.g. %eax for eax). Immediates such as constants are preceded by a dollar sign (e.g. $162 for the constant 162).
1.1. Calling Convention
Before calling a function, the caller needs to:
- Save caller-saved GPRs onto the stack if needed after the function call.
- Push parameters onto the stack in reverse order (e.g. start with the “rightmost” parameter). Add padding before the parameters to ensure a 16-byte alignment.
Then the caller calls the function by pushing the return address onto the stack and jumping to the function. Then, before executing any function logic, the callee needs to:
- Push
ebponto the stack and setebpto be the newesp. This marks the start of a new stack frame. - Allocate stack space for any local variables (i.e. decrement
esp). - Save callee-saved GPRs onto the stack if used during the function call.
Then, the callee will perform the function logic. Before returning, the callee needs to:
- Store the return value in
eax. - Restore callee-saved GPRs from the prologue.
- Deallocate local variables (e.g. set
espto be the currentebp). - Restore the caller’s
ebpfrom the stack. - Return from the function by popping the return address that was pushed to the caller and jumping to it.
Finally, after the function call returns back to the caller, we need to:
- Remove the parameters from the stack.
- Restore caller-saved GPRs from the prologue.
2. Instructions
In AT&T syntax, the source precedes the destination. There are also a few commonly used instructions that will show up in nearly every assembly code due to calling convention:
pushl src # push src onto stack
popl dest # pop from stack into dest
call addr # push return address onto stack and jump to addr
leave # restore ebp and esp to previous stack frame
ret # pop return address from stack and jump to it