talks

git clone git://code.dwrz.net/talks
Log | Files | Refs

slides.org (10006B)


      1 * 1. x86 Assembly
      2 
      3 - David Wen Riccardi-Zhu
      4 - Senior Software Engineer @ Good Uncle
      5 - dwrz@dwrz.net
      6 
      7 Slides and code: https://github.com/dwrz/talks/x86-assembly.
      8 
      9 * 2. Overview
     10 
     11 1. Follow a trail of questions into the depths of the machine.
     12 2. Peel away some abstractions on the way.
     13 3. Gloss over a bunch of stuff (we have an hour, not a semester).
     14 4. Surface (hopefully) with a better understanding of how computers work.
     15 
     16 * 3. What does this program do?
     17 
     18 #+begin_src bash :results raw
     19 node -e "console.log('Hello, World');"
     20 #+end_src
     21 
     22 * 4. How does this program /work/?
     23 
     24 #+begin_src bash :results raw
     25 node -e "console.log('Hello, World');"
     26 #+end_src
     27 
     28 How does "Hello World" get onto the terminal?
     29 
     30 * 5. What does this program do?
     31 Let's try something simpler.
     32 
     33 #+begin_src bash
     34 node -e ""
     35 #+end_src
     36 
     37 Does this do /anything/?
     38 
     39 * 6. It does /something/.
     40 
     41 We can tell, because it takes a few milliseconds to execute.
     42 
     43 #+begin_src bash :results raw
     44 time node -e ""
     45 #+end_src
     46 
     47 #+begin_src bash :results raw
     48 time node -e "console.log('Hello, World');"
     49 #+end_src
     50 
     51 * 7. It /definitely/ does /something/.
     52 
     53 We can tell, because it's making system calls.
     54 
     55 #+begin_src bash :results raw
     56 strace node -e ""
     57 #+end_src
     58 
     59 Lot of noise for a program that does "nothing"...
     60 
     61 #+begin_src bash :results raw
     62 strace node -e "console.log('Hello, World');"
     63 #+end_src
     64 
     65 * 8. JavaScript
     66 We've actually started with something difficult.
     67 
     68 JavaScript is an interpreted language.
     69 
     70 #+begin_src js
     71 const myProgram = '0 + 1'.replace('+', '-');
     72 
     73 const result = eval(myProgram);
     74 
     75 console.log(result); // -1
     76 #+end_src
     77 
     78 #+RESULTS:
     79 
     80 * 9. C
     81 Let's use a simpler example.
     82 
     83 C is compiled.
     84 
     85 We create our own program, rather than use a program that interprets strings.
     86 
     87 #+begin_src C :results raw
     88 #include <stdio.h>
     89 
     90 int main(void) {
     91 	printf("Hello, World\n");
     92 }
     93 #+end_src
     94 
     95 * 10. Compile and Execute
     96 
     97 #+begin_src bash
     98 gcc hello-world.c -o hello-world
     99 #+end_src
    100 
    101 #+begin_src bash
    102 ./hello-world
    103 #+end_src
    104 
    105 #+begin_src bash
    106 strace ./hello-world
    107 #+end_src
    108 
    109 * 11. write
    110 This seems familiar:
    111 #+begin_src C
    112 write(1, "Hello, World\n", 13Hello, World
    113 )          = 13
    114 #+end_src
    115 
    116 It's in our node program, too:
    117 #+begin_src bash
    118 strace node -e "console.log('Hello, World');" 2>&1 | grep "Hello"
    119 #+end_src
    120 
    121 /What is this?/
    122 What is ~write~?
    123 What is 1?
    124 What is 13?
    125 
    126 * 12. System Calls
    127 ~strace~ shows us system calls. ~write~ is a system call.
    128 
    129 What is a system call?
    130 
    131 #+begin_src bash
    132 man syscalls
    133 #+end_src
    134 
    135 #+begin_quote
    136 The system call is the fundamental interface between an application and the Linux kernel.
    137 #+end_quote
    138 
    139 * 13. write
    140 
    141 #+begin_src bash
    142 man 2 write
    143 #+end_src
    144 
    145 #+begin_src C
    146 write(int fd, const void *buf, size_t count);
    147 #+end_src
    148 
    149 #+begin_quote
    150 write()  writes  up  to count bytes from the buffer starting at buf to the file referred to by the file descriptor fd.
    151 #+end_quote
    152 
    153 * 14. write
    154 
    155 #+begin_src text
    156 write(1, "Hello, World\n", 13Hello, World
    157 )          = 13
    158 #+end_src
    159 
    160 File Descriptor 1 = Standard Out (inherited from terminal process)
    161 Hello World = Buffer
    162 Count = 13 bytes
    163 
    164 |---+---+---+---+---+---+---+---+---+---+---+---+----|
    165 | H | e | l | l | o | , |   | W | o | r | l | d | \n |
    166 |---+---+---+---+---+---+---+---+---+---+---+---+----|
    167 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | 1 | 2 |  3 |
    168 |---+---+---+---+---+---+---+---+---+---+---+---+----|
    169 
    170 * 15. Back to Nothing
    171 #+begin_src C
    172 int main(void) {}
    173 #+end_src
    174 
    175 #+begin_src bash
    176 gcc exit.c -o exit
    177 #+end_src
    178 
    179 #+begin_src bash
    180 strace ./exit
    181 #+end_src
    182 
    183 * 16. Exit Code
    184 In C, the return type prefixes the function.
    185 
    186 ~main~ returns an ~int~; the default is zero (indicating no error).
    187 
    188 #+begin_src C
    189 int main(void) {
    190 	return 1;
    191 }
    192 #+end_src
    193 
    194 #+begin_src C
    195 exit_group(1)
    196 #+end_src
    197 
    198 * 17. exit_group
    199 #+begin_src bash
    200 man 2 exit_group
    201 #+end_src
    202 
    203 #+begin_src C
    204 void exit_group(int status);
    205 #+end_src
    206 
    207 * 18. Exit
    208 
    209 [[file:src/exit/exit.s]]
    210 
    211 * 19. Assemble, Link, Execute, Trace
    212 #+begin_src bash
    213 as exit.s -o exit.o
    214 
    215 ld exit.o -o exit
    216 
    217 ./exit
    218 
    219 strace ./exit
    220 #+end_src
    221 
    222 * 20. x86 Assembly
    223 - Human readable form of machine code.
    224 - 1-to-1 mapping between one assembly instruction and one CPU instruction.
    225 - Hardware specific: e.g., x86 Assembly differs from ARM Assembly.
    226 - Often OS specific --> Linux System Calls != BSD, Mac, Windows system calls.
    227 - Different syntax formats: ATT, Intel.
    228   - Examples use ATT syntax.
    229 - What instructions? Need to consult hardware manual.
    230   - [[https://software.intel.com/content/www/us/en/develop/articles/intel-sdm.html][Intel x86 Developer Manual]] is ~5,000 pages long, plus errata.
    231 
    232 #+begin_src bash
    233 lscpu
    234 #+end_src
    235 
    236 * 21. Use Cases
    237 - Low-level programming (micro-controllers, operating systems)
    238 - Resource Constrained Hardware
    239   - [[https://github.com/chrislgarry/Apollo-11][Apollo 11 Guidance Computer Assembly]] (1969)
    240   - [[https://github.com/pret/pokered][Pokemon Red/Blue Assembly]] (1996, AA batteries)
    241 - Performance
    242   - Less runtime overhead (system calls, etc)
    243   - Better code than compiler (harder to do these days)
    244 - Control
    245   - Instructions not available in higher level language
    246 - Reverse Engineering
    247 
    248 #+begin_src bash
    249 hexdump -C exit
    250 #+end_src
    251 
    252 #+begin_src bash
    253 objdump -D exit
    254 #+end_src
    255 
    256 * 22. Instructions
    257 - Represented by numbers (opcodes).
    258 - Describe an operation the CPU should perform, e.g.:
    259   - Move data in and out of registers
    260   - Modify register contents
    261   - Modify stack
    262   - Control program flow
    263 
    264 * 23. Instruction Cycle
    265 - On every tick of its internal clock, the CPU:
    266   - *Fetches* the next instruction.
    267   - *Decodes* it (what operation, on what operands).
    268   - *Executes* the instruction.
    269   - Increments the instruction pointer.
    270 
    271 * 24. Registers
    272 - Storage on the CPU (fastest storage).
    273 - Act as a scratchpad -- temporary variables.
    274 - General Purpose Registers
    275   - RAX, RBX, RCX
    276   - RSP, RBP (stack pointer, stack frame pointer)
    277 - Special Purpose Registers
    278   - RIP (Instruction Pointer)
    279   - RFLAGS (negative, zero, etc.)
    280 - It's possible to use just a portion of the register.
    281 #+begin_src text
    282 |__64__|__56__|__48__|__40__|__32__|__24__|__16__|__8___|
    283 |__________________________RAX__________________________|
    284 |xxxxxxxxxxxxxxxxxxxxxxxxxxx|____________EAX____________|
    285 |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|_____AX______|
    286 |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|__AH__|__AL__|
    287 #+end_src
    288 
    289 * 25. Exit++
    290 
    291 [[file:src/math/math.s]]
    292 
    293 * 26. Sections
    294 What happens when we run a program? A few things...
    295 
    296 One of them: the kernel loads the executable into memory.
    297 
    298 Assembly sections refer to executable's memory layout:
    299 
    300 |-----------|
    301 | TEXT      | --> Code (instructions)
    302 | RODATA    | --> const str = "Hello, World";
    303 | DATA      | --> var str = "Hello, World";
    304 | BSS       | --> var str;
    305 | ↓ HEAP ↓  | --> (for traditional C)
    306 |           |
    307 | ↑ STACK ↑ |
    308 |-----------|
    309 
    310 * 27. Hello World
    311 
    312 [[file:src/hello-world/hello-world.s]]
    313 
    314 * 28. Control Flow
    315 Programs are either sequential, looping, or branching.
    316 
    317 - CPU sets FLAGS register after instruction: e.g., result is zero, negative.
    318 - Jump to code based on the state of FLAGS.
    319 - Jump changes instruction pointer.
    320 
    321 [[file:src/control-flow/control-flow.s]]
    322 
    323 * 29. Stack
    324 RSP register points to the top of the stack.
    325 RBP register (typically) points to the (current) base of the stack.
    326 Together, they form a stack frame.
    327 
    328 Instructions:
    329 - ~push~ :: decrements RSP, moves bytes onto stack.
    330 - ~pop~ :: increments RSP, moves stack bytes into register.
    331 
    332 [[file:src/stack/stack.s]]
    333 
    334 * 30. Functions
    335 Why do we use functions? Same reasons apply in Assembly:
    336 - Reuse
    337 - Organization
    338 - Abstraction
    339 - Splitting work
    340 
    341 Problems:
    342 - How to pass arguments?
    343   - Registers -- which ones?
    344   - Stack -- what order?
    345 - Whose job is it to preserve or clean up registers? Caller? Callee?
    346   - E.g., caller saves a value in %rbx to use after function returns.
    347   - Callee uses %rbx and overwrites that value.
    348 - How to pass return value(s)?
    349 
    350 * 31. Convention
    351 Which side of the street should we drive on?
    352 Either way works, both are used in practice.
    353 What matters is agreement on an approach.
    354 
    355 [[file:static/convention.jpg]]
    356 
    357 System V AMD64 ABI is calling convention for Unix x64 systems:
    358 - Some registers must be saved by the caller, so callee can use them.
    359 - Some registers must be saved by callee, if the plan to use them later.
    360 - Some registers used to pass arguments.
    361 - Stack used to pass extra or large arguments.
    362 - RAX and RDX are used for return values.
    363 
    364 * 32. Stack Arguments
    365 
    366 [[file:src/func/func.s]]
    367 
    368 Each row is 8 bytes (64 bits).
    369 |----------------+-----------+----------------|
    370 |        Address |      Data | Stack Pointers |
    371 |----------------+-----------+----------------|
    372 | 0x7fffffffe8f8 |           |                |
    373 | 0x7fffffffe900 | 0x0 (rbp) |                |
    374 | 0x7fffffffe908 |  0x401002 |                |
    375 | 0x7fffffffe910 |         3 | ←rsp           |
    376 |----------------+-----------+----------------|
    377 ←rbp
    378 
    379 * 33. Safety and Security
    380 
    381 [[file:src/safety/safety.s]]
    382 
    383 * 34. Review
    384 Where we started:
    385 
    386 #+begin_src bash
    387 node -e ""
    388 #+end_src
    389 
    390 - CPU processes instructions
    391 - Uses registers and memory (stack)
    392 - Control flow with jump instruction and flags register
    393 - Functions
    394 - System Calls
    395 - Comparison with Compiled and Interpreted Languages
    396 - Tradeoffs
    397 
    398 * 35. Conclusion
    399 - Insight into how computers work.
    400 - Appreciation for higher level, and work done to get us here.
    401 - A platform to better understand things like functions, closures, APIs, pass by reference and pass by value, performance.
    402 - A few mysteries to leave you curious...
    403 
    404 * 36. References / Further Reading
    405 
    406 - [[https://www.youtube.com/watch?v=tpIctyqH29Q&list=PL8dPuuaLjXtNlUrzyH5r6jN9ulIgZBpdo][Crash Course: Computer Science]]
    407 - Davy Wybiral, [[https://www.youtube.com/playlist?list=PLmxT2pVYo5LB5EzTPZGfFN0c2GDiSXgQe][Intro to x86 Assembly Language]]
    408 - [[https://www.gnu.org/software/gdb/][GDB]]
    409 - Jennifer Rexford, [[https://www.cs.princeton.edu/courses/archive/fall05/cos217/][Princeton COS 217: Introduction to Programming Systems]]
    410 - [[https://en.wikipedia.org/wiki/Structured_program_theorem][Structured Program Theorem]]