# x86 ## History ```mermaid graph LR 1[Intel \n 8088 Series] 2[Intel Itanium \n IA64 Arch.] 3[AMD \n AMD64 Arch.] 1 --"backward \n incompatible"--> 2 1 --"backward \n compatible" --> 3 3 --> 4[x86-64 Arch.] 2 -. "discontinued" .-> 4 ``` ## Registers - `%rsp` - [[stack|stack pointer]], which points to the last value pushed on stack. - `%rbp` - frame pointer/base pointer - Part of the register can be accessed with a different name. This enables backward compatibility for 32-bit program. - Value in `%rax` is the default return value. (the _accumulator_) - Some instructions related to string operation use `%rsi` and `%rdi` - Remember to save the state of registers (by pushing and popping stacks) > [!warning] Watch for the `%`! > > - AT&T syntax has a `%` before registers, in `src, dstn` format. (Used by > `gcc`) > - Intel syntax has not, in `dstn, src` format. ## Addressing - Global value - `main` - Immediate value - `$32` - Register value - `%rsp` refers to value stored in `%rsp` - Indirect value - `(%rsp)` refers to value pointed to by `%rsp` - Base-relative - `-16(%rcx)` - Complex - `-16(%rbx, %rcx, 8)`, in which `%rbx` is the base of array, `%rcx` is index, `8` is size of the items, `-16` is an offset relative to the item selected. ## Instructions ### Data Movement - Move Data - `MOV{B,W,L,Q} %rbx %rax` (MOVE source, destination) - Stands for `BYTE` (8 bits), `WORD` (16 bits), `LONG` (32 bits), `QUADWORD` (64 bits) - Load effective address `LEA` ### Arithmetic - Add - Multiply - `IMUL` takes operand, multiply by the value in `%rax` - Leaves the low 64 bits in `%rax`, and high 64 bits in `%rdx` - Division - `IDIV` takes 128-bit integer in `%rdx %rax`, divide it by operand - Quotient is placed in `%rax`, remainder in `%rdx` - `IDIV` and `IMUL` (signed div/mul) are more hardware-optimized - Use `CQO` to sign-extend `%rax` to `%rdx` (for quad word) ### Conditional - `CMPQ`, comparison instruction puts result into `EFLAGS` register. All comparisons are done at the same time? - `JLE`, `JL`, `JEQ`, `JNE`, `JGE`, `JG` ### Function Call 32-bit system uses stack calling convention: ```asm PUSH %rip J f POP %rip ``` 64-bit system uses register calling convention -- System V ABI Calling Convention ```asm name: .string "Peter" LEAQ str, %rdi # LEAQ instead of MOVQ ``` ### Function Definition ```c int compute(int a, int b) { return a + b * 3; } ``` ```asm .global compute compute: MOVQ %rdi, %rbx # %rbx should be saved MOVQ %rsi, %rax # %rax is scratch MOVQ $3, %rcx # %rcx is scatch IMULQ %rcx # implicitly implies %rax * %rcx ADDQ %rbx, %rax RET ``` ### Nest-able Functions ```asm .compute: PUSH %rbp MOVQ %rsp, %rbp PUSH %rdi PUSH %rsi SUBQ $24, %rsp # 3 local vars of 8 bytes PUSH %rbx ... # Save other registers MOVQ - 8(%rbp), %r10 # arg0 MOVQ -16(%rbp), %r11 # arg1 MOVQ $3, %r12 MOVQ %r11, %rax IMULQ %r12 ADDQ %r10, %rax MOVQ %rax, -24(%rbx) # put results into a local var POP ... $ pop scratch regs # local vars and args automatically bypassed MOVQ %rbp, $rsp # go to the caller POP %rbp RET ``` - First to instructions are _idioms_ which can be found in the start of functions of any languages. - Save the arguments - Save space for local variables -- so that it's easier to reference them - Save the local variables (which are already on the stack) ## Program Elements - Directives, begin with a `.` - `.file` - `.data` - `.text` - Labels - Name them starting with `.` is ideal. These are meant to be put in the `data` section. - `.global main`, to make `main` visible to outer scope for it to be called. ## Debugging - Compile with `-d` flag - `stepi` to go through individual instructions - Use `print` on `$rax`, `$eflags`, `$rip`, or `info registers` to view all registers