diff --git a/course/extra/Adressage_memoire_et_protection.pdf b/course/extra/Adressage_memoire_et_protection.pdf new file mode 100644 index 0000000000000000000000000000000000000000..edae7573da47e7501c014848ecdee9c0f1c4a8eb Binary files /dev/null and b/course/extra/Adressage_memoire_et_protection.pdf differ diff --git a/course/extra/Intel_x86_architecture.md b/course/extra/Intel_x86_architecture.md new file mode 100644 index 0000000000000000000000000000000000000000..9690e0ffa85e83cb1f544df26664e04bdf8a8691 --- /dev/null +++ b/course/extra/Intel_x86_architecture.md @@ -0,0 +1,764 @@ +--- +author: Florent Gluck - Florent.Gluck@hesge.ch + +title: Intel x86 Architecture + +date: \vspace{.5cm} \footnotesize \today + +pandoc-latex-fontsize: + - classes: [tiny] + size: tiny + - classes: [verysmall] + size: scriptsize + - classes: [small] + size: footnotesize + - classes: [huge, important] + size: huge +--- + +[//]: # ---------------------------------------------------------------- +# Introduction + +[//]: # ---------------------------------------------------------------- +## x86 architecture + +\footnotesize + +**Real mode** (“640KB ought to be enough for anybody”)\ + +- 16-bit mode +- No mode switch (always privileged) +- No memory protection + +**Protected mode**\ + +- 32-bit mode (IA-32) +- Protection levels +- Memory virtualization/protection through segmentation and pagination + +**Virtual 8086 mode**\ + +- Compatibility for executing 16-bit code in 32-bit mode + +**Long mode**\ + +- 64-bit mode, but memory pagination only +- Compatibility mode for executing 32-bit code + +[//]: # ---------------------------------------------------------------- +## Protection mechanism + +- IA-32 supports 4 privilege levels, called **rings** +- The most privileged level is **ring 0** +- Usually, the kernel runs in **ring 0** while user code (applications) run in **ring 3** + +\vspace{.2cm} + +\centering +{ width=60% } + +[//]: # ---------------------------------------------------------------- +## IA-32 architecture + +- Little-endian architecture +- Registers : + - General purpose registers + - Segment registers (memory addressing and protection) + - Status register (flags) +- General purpose instructions +- Branching instructions +- Stack and stack frame instructions +- Calling conventions (ABI) + +[//]: # ---------------------------------------------------------------- +# IA-32 registers + +[//]: # ---------------------------------------------------------------- +## IA-32 registers + +\centering +{ width=100% } + +[//]: # ---------------------------------------------------------------- +## General registers purposes + +For most operations, the registers below can be used for any purpose. +However, they are also used in specific situations described below: + +\footnotesize + +**Register** **Specific purpose** +------------ ------------------------------------------------------------- +EAX Accumulator for operands and results. +EBX Data pointer (within segment pointed by DS). +ECX Counter for loops and string operations. +EDX Port access (PMIO). +ESP Stack pointer (within segment pointed by SS). +EBP Base pointer for stack frame (within segment pointed by SS). +ESI Data pointer (within segment pointed by DS). + Source pointer for string operations. +EDI Data pointer (within segment pointed by ES). + Destination pointer for string operations. +------------ ------------------------------------------------------------- + +[//]: # ---------------------------------------------------------------- +## EFLAGS status register (1/2) + +\centering +{ width=80% } + +[//]: # ---------------------------------------------------------------- +## EFLAGS status register (2/2) + +\tiny + +**Bit** **Name** **Description** +------- -------- ------------------------------------------------------------------------------------------------- +0 CF **Carry Flag**. Set if the last arithmetic operation carried (addition) or borrowed (subtraction) + a bit beyond the size of the register. This is then checked when the operation is followed with + an add-with-carry or subtract-with-borrow to deal with values too large for just one register to + contain. +2 PF **Parity flag**. Set if the number of set bits in the least significant byte is a multiple of 2. +4 AF **Auxiliary Carry Flag**. Carry of Binary Code Decimal (BCD) numbers arithmetic operations. +6 ZF **Zero Flag**. Set if the result of an operation is Zero (0). +7 SF **Sign Flag**. Set if the result of an operation is negative. +8 TF **Trap Flag**. Set if step by step debugging. +9 IF **Interruption Flag**. Set if interrupts are enabled. +10 DF **Direction Flag**. Stream direction. If set, string operations will decrement their pointer + rather than incrementing it, reading memory backwards. +11 OF **Overflow Flag**. Set if signed arithmetic operations result in a value too large for the + register to contain. +12-13 IOPL **I/O Privilege Level field**. I/O Privilege Level of the current process. +14 NT **Nested Task flag**. Controls chaining of interrupts. Set if the current process is linked to the + next process. +16 RF **Resume Flag**. Response to debug exceptions. +17 VM **Virtual-8086 Mode**. Set if in 8086 compatibility mode. +------- -------- ------------------------------------------------------------------------------------------------- + +[//]: # ---------------------------------------------------------------- +# IA-32 instructions + + +[//]: # ---------------------------------------------------------------- +## Main instructions + +\small + +**Instruction** **Description** +------------------------- -------------------------------------- +`mov` move (copy) source into destination +`add`, `sub` addition/subtraction (integer) +`inc`, `dec` increment/decrement (integer) +`mul`, `div` unsigned multiply/divide +`and`, `or`, `xor`, `not` bitwise operations +`shl`, `shr` left, right shifts (logical) +`cmp` comparison +`jmp` unconditional jump +`jcond` conditional jump +`call`, `ret` function call/return +`enter`, `leave` create/destroy a stack frame +`push`, `pop` push/pop a value on the stack + +[//]: # ---------------------------------------------------------------- +## MOV instruction + +- `mov`: move (copy) source into destination + +\vspace{.5cm} + +```{.small .assembler} +mov eax, 123456 ; eax = 42 (32 bits) +mov esi, eax ; esi = eax (32 bits) +mov ebp, esp ; ebp = esp (32 bits) + +mov bx, 10 ; bx = 10 (16 bits) +mov ax, bx ; ax = bx (16 bits) + +mov cl, 10 ; cl = 10 (8 bits) +mov dh, cl ; dh = cl (8 bits) +``` + +[//]: # ---------------------------------------------------------------- +## ADD, SUB, INC, DEC instructions + +- `add`/`sub`: add/subtract source into destination +- `inc`/`dec`: increment/decrement operand + +\vspace{.5cm} + +```{.small .assembler} +add eax, 10 ; eax = eax + 10 +add ebx, eax ; ebx = ebx + eax + +sub esi, 10 ; esi = esi - 10 + +inc dh ; dh = dh + 1 +dec esp ; esp = esp - 1 +``` + +[//]: # ---------------------------------------------------------------- +## MUL, DIV instructions + +\small + +- `mul`: unsigned multiply EAX by operand; result in EAX, overflow in EDX +- `div`: unsigned divide EDX:EAX by operand; quotient in EAX, remainder in EDX +- For other data sizes, see: + - \scriptsize [\textcolor{myblue}{https://www.felixcloutier.com/x86/mul}](https://www.felixcloutier.com/x86/mul) + - \scriptsize [\textcolor{myblue}{https://www.felixcloutier.com/x86/div}](https://www.felixcloutier.com/x86/div) +- Use `imul` and `idiv` for signed operations + +\vspace{.2cm} + +```{.verysmall .assembler} +mul ecx ; eax = eax * ecx (result in edx:eax) +mul dword [10] ; eax = eax * "32 bits value at address 10" + +mov edx, 0 ; higher 32 bits of dividend +mov eax, 1000 ; lower 32 bits of dividend +mov ecx, 17 ; divisor +div ecx ; divide 1000 by 17 => eax = 58, edx = 14 +``` + +[//]: # ---------------------------------------------------------------- +## AND, OR, XOR, NOT instructions + +- `and`/`or`/`xor`/`not`: bitwise logical instructions + +\vspace{.5cm} + +```{.small .assembler} +and eax, 128 ; eax = eax & 128 + +or esp, 0x80 ; esp = esp | 0x80 + +xor ecx, 1 ; ecx = ecx ^ 1 + +not ebx ; ebx = ~ebx +``` + +[//]: # ---------------------------------------------------------------- +## SHL, SHR instructions + +- `shl`: shift left (logical) +- `shr`: shift right (logical) + +\vspace{.5cm} + +```{.small .assembler} +shl eax, 2 ; eax = eax << 2 +shr ebx, 3 ; ebx = ebx >> 3 + +mov cl, 4 +shl eax, cl ; MUST be cl, cx or an immediate value! +``` + +[//]: # ---------------------------------------------------------------- +## Compare and jump instructions + +\small + +- `cmp`: compare operands +- `jmp`: unconditional jump +- `jcond`: conditional jump; see \scriptsize [\textcolor{myblue}{https://www.felixcloutier.com/x86/jcc}](https://www.felixcloutier.com/x86/jcc) + +\vspace{.2cm} + +```{.verysmall .assembler} +jmp some_label ; goto some_label +``` + +```{.verysmall .assembler} +cmp eax,ebx ; compare eax with eabx +je equal ; if (eax == ebx) then jump to label "equal" +... +equal: +... +``` + +```{.verysmall .assembler} +cmp ebx,17 ; compare ebx with 17 +jge larger ; if (ebx >= 17) then jump to label "larger" +... +larger: +... +``` + +[//]: # ---------------------------------------------------------------- +## Conditional jumps table + +\centering +{ width=100% } + + +[//]: # ---------------------------------------------------------------- +## CALL, RET instructions + +- `call`: call a function (routine), **implicitly** stores the return address on the stack +- `ret`: return to caller, **implicitely** retrieves the return address from the stack + +\vspace{.5cm} + +```{.small .assembler} +call func +and eax, 0x20 +inc eax + +func: +mov eax, 17 +mov ebx, 5 +add eax, ebx +ret +``` + +[//]: # ---------------------------------------------------------------- +## PUSH, POP instructions + +- `push`: store a value (32 bits) onto the stack +- `pop`: retrieve the value (32 bits) at the top of the stack + +\vspace{.5cm} + +```{.small .assembler} +push 10 ; push the value 10 onto the stack +push eax ; push the value of EAX onto the stack + +pop ebx ; pop the value at the top of the stack + ; into EBX +``` + +[//]: # ---------------------------------------------------------------- +## Privileged instructions + +The following instructions can **only be executed** in ring 0: + +\small + +------------------------------- ----------------------------------------- +`hlt` Halt the CPU; if a hardware interrupt is + raised, the CPU resumes its execution. +`cli`, `sti` Mask/unmask hardware interrupts. +`lidt`, `lgdt`, `ltr` Load the IDT, the GDT and the task + register. +`mov` `ds`/`ss`/`es`/`fs`/`gs` Load any of the segment registers. +`in`, `out`[^1] Port read or write (PMIO). +------------------------------- ----------------------------------------- + +[^1]: not always true: it depends on the task configuration/permissions + +[//]: # ---------------------------------------------------------------- +## Memory addressing + +\scriptsize + +--------------------- ----------------------------------------------------------------- +`mov eax,[ebx]` Copy into `eax` the 32-bit value located at the address in `ebx`. + Equivalent to `eax = *ebx` in C. +`mov eax,[n]` Copy into `eax` the 32-bit value located at address `n`. + Equivalent to `eax = *n` in C. +`mov al,[ebx]` Copy into al the 8-bit value at the address in `ebx`. +`mov [eax],42` Error: the CPU doesn't know how many bytes to write! +`mov byte[eax],42` Copy the value 42 (8-bit) at the address in `eax`. +`mov dword[eax],42` Copy the value 42 (32-bit) at the address in `eax`. +`mov eax,42` Copy the immediate value 42 into `eax`. +`mov eax,n` Copy the address of `n` into `eax`. +`mov [esi+eax],cl` Copy the value of `cl` (8-bit) at the address `esi+eax`. +`mov [esi+4*ebx],cx` Copy the value of `cx` (16-bit) at the address `esi+4*ebx`. +--------------------- ----------------------------------------------------------------- + +\vspace{-.5cm} + +\small +- At most, two registers plus a constant can be added to compute a memory address (source or destination) +- Additionally, one of these two registers can be multiplied by 2, 4 or 8 + +[//]: # ---------------------------------------------------------------- +# The stack + +[//]: # ---------------------------------------------------------------- +## The stack + +:::::: {.columns} +::: {.column width="60%"} + +- The stack "grows" **down!** + +- To **push** onto the stack: + ```{.verysmall .assembler} + push 37 <=> sub esp,4 + mov dword[esp],37 + ``` + +- To **pop** from the stack: + ```{.verysmall .assembler} + pop eax <=> mov eax,[esp] + add esp,4 + ``` + +::: +::: {.column width="40%"} + +\centering +{ width=100% } + +::: +:::::: + +[//]: # ---------------------------------------------------------------- +## Stack frame (1/2) + +\small + +\metroset{block=fill} +\begin{block}{Stack frame} +Collection of all information on the stack related to a function call +\end{block} + +- Also called "activation frame" or "activation record" +- **Only exist** at **runtime** +- Help supporting **recursive** functions +- Machine dependent and ABI-dependent +- Stack frame contents: + - Function arguments + - Local variables + - Saved copies of registers modified by functions that could need restoration + - Return address + +[//]: # ---------------------------------------------------------------- +## Stack frame (2/2) + +\small + +:::::: {.columns} +::: {.column width="55%"} + +- A stack frame is **allocated** when the function is called +- A stack frame is **deallocated** when the function exits + +- Stack frame **allocation** + ```{.verysmall .assembler} + push ebp <=> enter 0,0 + mov ebp,esp + ``` + +- Stack frame **deallocation** + ```{.verysmall .assembler} + mov esp,ebp <=> leave + pop ebp + ``` + +::: +::: {.column width="45%"} + +\centering +{ width=100% } + +::: +:::::: + +[//]: # ---------------------------------------------------------------- +## Function call example1 + +\centering +{ width=100% } + +[//]: # ---------------------------------------------------------------- +## Function call example2 + +:::::: {.columns} +::: {.column width="55%"} + +```{.verysmall .c} +int f(int a, int b, int c) { + int tmp = a + b + c; + return tmp; +} + +int main() { + f(3, 8, 17); + return 0; +} +``` + +\vspace{.3cm} + +Reminder: +```{.verysmall .assembler} +leave <=> mov esp,ebp + pop ebp +``` + +\vspace{.3cm} + +\scriptsize +`*` to generate IA-32 assembly code from C:\ +\scriptsize `gcc -S -m32 -masm=intel prog.c` + +::: +::: {.column width="45%"} + +```{.tiny .assembler} +f: + push ebp + mov ebp,esp + sub esp,16 + mov edx,[ebp+8] ; a + mov eax,[ebp+12] ; b + add edx,eax + mov eax,[ebp+16] ; c + add eax,edx + mov [ebp-4],eax ; tmp + mov eax,[ebp-4] + leave + ret + +main: + push ebp + mov ebp,esp + push 17 + push 8 + push 3 + call f + add esp,12 + mov eax,0 + leave + ret +``` + +::: +:::::: + +[//]: # ---------------------------------------------------------------- +## Calling conventions + +\metroset{block=fill} +\begin{block}{Calling convention} +Protocol defining how to call and return from functions +\end{block} + +\vspace{.2cm} + +- Typically: + - How are arguments passed to a function? + - Which registers to save? + - How to retrieve a function's result? +- Allow different langages to call functions of other languages (C $\leftrightarrow$ asm, Rust $\leftrightarrow$ C, etc.) +- Allow programs to share code (e.g. libraries) +- **Specific** to CPU architecture and compiler[^2]! + +[^2]: List of X86 calling conventions at [\tiny \textcolor{myblue}{https://en.wikipedia.org/wiki/X86\_calling\_conventions}](https://en.wikipedia.org/wiki/X86_calling_conventions) + +[//]: # ---------------------------------------------------------------- +## cdecl calling convention for IA-32 + +- cdecl = **C decl**aration + - Among the most popular calling conventions +- Function arguments passed on the stack +- Local variables allocated on the stack +- Return value stored in specific register(s) +- Two sets of rules: + - Caller rules (code calling the function) + - Callee rules (code of the function) + +[//]: # ---------------------------------------------------------------- +## cdecl: caller rules + +Before the function call\ + +- Must save `eax`, `ecx`, `edx` since functions are allowed to modify these registers +- Function arguments passed in **reverse** order +- Function called with the `call` instruction (which **implictly** saves the return address on the stack!) + +After the function call\ + +- Cleanup caller stack (i.e. discard arguments pushed on stack before call) +- Restore `eax`, `ecx`, `edx` from the stack + +[//]: # ---------------------------------------------------------------- +## cdecl: callee rules (1/2) + +\small + +**1. Create a stack frame** (optional)\ + +\vspace{.3cm} +```{.verysmall .assembler} +push ebp +mov ebp,esp +``` +`ebp` is then used as a base pointer to function arguments and local variables (see slide 24) + +\vspace{.3cm} + +**2. Allocate local variables** (if any)\ + +Allocate stack space by decrementing `esp` of the desired number of bytes: +```{.verysmall .assembler} +sub esp,16 ; allocate 16 bytes +``` + +\vspace{.2cm} + +**3. Save modified registers** on the stack\ + +The function is responsible to preserve `ebx`, `edi`, `esi` + +[//]: # ---------------------------------------------------------------- +## cdecl: callee rules (2/2) + +Rules before exiting the function: + +1. Store the function return value (if any) in `eax` (if $\leq$ 32 bits) or `edx:eax` (if 64 bits) +1. If `ebx`, `edi` or `esi` were modified, restore their values from the stack +1. Deallocate the stack frame with the `leave` instruction or with: + ```{.verysmall .assembler} + mov esp,ebp + pop ebp + ``` +1. Return to the caller with the `ret` instruction\ + $\rightarrow$ `ret` **implictly** retrieves the return address from the stack! + +[//]: # ---------------------------------------------------------------- +## Stack conventions + +- The `esp` register is the stack pointer + - Points to the stack's last value ("top" of the stack) + - The next free stack element is at `[esp-4]` + - These instructions **implicitly modify** the stack pointer: `push`, `pop`, `call`, `ret` + +- The `ebp` register is the "base pointer" + - Base pointer to locate **function arguments** and **local variables** + - Explicitly handled by the programmer + +[//]: # ---------------------------------------------------------------- +## Variable-argument functions in C (1/4) + +C syntax for variable-argument functions: + +\vspace{.3cm} + +```{.verysmall .c} +int sum(int n, ...) { + // body of the function +} +``` + +- `...` represents the variable arguments (minimum 1 argument) +- `...` **must** be preceded by another argument + +[//]: # ---------------------------------------------------------------- +## Variable-argument functions in C (2/4) + +Retrieve variable arguments by pointing to the stack "by hand": + +```{.verysmall .c} +int sum(int n, ...) { + int sum = 0; + int32_t *p = ((int32_t*)&n)+1; + for (int i = 0; i < n; i++) { + sum += *p; + p++; + } + return sum; +} +``` + +- **Dangerous** and **to avoid** as the compiler might makes optimizations that render the pointer invalid! +- Above example works fine when compiled with `-O0` and `-O1`, but not with `-O2` or `-O3`! + +[//]: # ---------------------------------------------------------------- +## Variable-argument functions in C (3/4) + +\small + +Retrieve variable arguments by pointing to the stack using gcc compiler builtin `__builtin_next_arg(x)`: + +```{.verysmall .c} +int sum(int n, ...) { + int sum = 0; + int32_t *p = __builtin_next_arg(n); + for (int i = 0; i < n; i++) { + sum += *p; + p++; + } + return sum; +} +``` + +- When arguments are passed on the stack, `__builtin_next_arg(x)` returns the address of the argument following `x` +- **Specific** to gcc; other C compilers feature similar builtins +- Typically used by variadic macros + +[//]: # ---------------------------------------------------------------- +## Variable-argument functions in C (4/4) + +\small + +Retrieve variable arguments by using variadic macros[^3]: + +```{.verysmall .c} +int sum(int n, ...) { + int sum = 0; + va_list ap; // set up ap to point to each arg in turn + va_start(ap, n); // ap points to arg following n + for (int i = 0; i < n; i++) { + sum += va_arg(ap, int); // extract arg as an int + } + va_end(ap); // clean up + return sum; +} +``` + +- Requires `#include <stdarg.h>` +- **Portable**: part of the C language since C99 + +[^3]: More details at [\tiny \textcolor{myblue}{https://www.gnu.org/software/libc/manual/html\_node/Variadic-Functions.html}](https://www.gnu.org/software/libc/manual/html_node/Variadic-Functions.html) + +[//]: # ---------------------------------------------------------------- +## Nested variable argument functions + +How to call a variable argument function from another variable argument function? + +\vfill + +```{.tiny .c} +int sum_va(int arg_count, va_list args) { + int sum = 0; + for (int i = 0; i < arg_count; i++) + sum += va_arg(args, int); + return sum; +} + +int sum(int arg_count, ...) { + va_list ap; + va_start(ap, arg_count); + int sum = sum_va(arg_count, ap); + va_end(ap); + return sum; +} + +int main() { + return sum(3, 11, 9, 22); +} +``` + +[//]: # ---------------------------------------------------------------- +## Resources + +\small + +- “PC Assembly Language”, Paul A. Carter\ +\scriptsize Available at [\textcolor{myblue}{http://pacman128.github.io/pcasm/}](http://pacman128.github.io/pcasm/) +\small + +- x86 Assembly Guide, University of Virginia Computer Science\ +\scriptsize [\textcolor{myblue}{https://www.cs.virginia.edu/~evans/cs216/guides/x86.html}](https://www.cs.virginia.edu/~evans/cs216/guides/x86.html) +\small + +- x86 and amd64 instruction reference\ +\scriptsize [\textcolor{myblue}{https://www.felixcloutier.com/x86/}](https://www.felixcloutier.com/x86/) +\small + +- x86_64 NASM Assembly Quick Reference ("Cheat Sheet")\ +\scriptsize [\textcolor{myblue}{https://www.cs.uaf.edu/2006/fall/cs301/support/x86\_64/}](https://www.cs.uaf.edu/2006/fall/cs301/support/x86_64/) +\small \ No newline at end of file diff --git a/course/extra/Intel_x86_architecture.pdf b/course/extra/Intel_x86_architecture.pdf new file mode 100644 index 0000000000000000000000000000000000000000..79d407488b68a9eb397f9c88179ee67573ca381d Binary files /dev/null and b/course/extra/Intel_x86_architecture.pdf differ