2020-11-06 16:18:48 +00:00
|
|
|
* 1. x86 Assembly
|
|
|
|
|
|
|
|
|
|
- David Wen Riccardi-Zhu
|
|
|
|
|
- Senior Software Engineer @ Good Uncle
|
|
|
|
|
- dwrz@dwrz.net
|
|
|
|
|
|
2026-10-27 12:37:57 +00:00
|
|
|
Slides and code: https://code.chimeric.al/dwrz/talks.
|
2020-11-06 16:18:48 +00:00
|
|
|
|
|
|
|
|
* 2. Overview
|
|
|
|
|
|
2020-11-13 17:14:44 +00:00
|
|
|
1. Follow a trail of questions into the depths of the machine.
|
2020-11-06 16:18:48 +00:00
|
|
|
2. Peel away some abstractions on the way.
|
|
|
|
|
3. Gloss over a bunch of stuff (we have an hour, not a semester).
|
|
|
|
|
4. Surface (hopefully) with a better understanding of how computers work.
|
|
|
|
|
|
|
|
|
|
* 3. What does this program do?
|
|
|
|
|
|
|
|
|
|
#+begin_src bash :results raw
|
|
|
|
|
node -e "console.log('Hello, World');"
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
* 4. How does this program /work/?
|
|
|
|
|
|
|
|
|
|
#+begin_src bash :results raw
|
|
|
|
|
node -e "console.log('Hello, World');"
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
How does "Hello World" get onto the terminal?
|
|
|
|
|
|
|
|
|
|
* 5. What does this program do?
|
2020-11-13 17:19:09 +00:00
|
|
|
Let's try something simpler.
|
2020-11-06 16:18:48 +00:00
|
|
|
|
|
|
|
|
#+begin_src bash
|
|
|
|
|
node -e ""
|
|
|
|
|
#+end_src
|
|
|
|
|
|
2020-11-13 17:19:09 +00:00
|
|
|
Does this do /anything/?
|
2020-11-06 16:18:48 +00:00
|
|
|
|
|
|
|
|
* 6. It does /something/.
|
|
|
|
|
|
|
|
|
|
We can tell, because it takes a few milliseconds to execute.
|
|
|
|
|
|
|
|
|
|
#+begin_src bash :results raw
|
2020-11-13 17:14:44 +00:00
|
|
|
time node -e ""
|
2020-11-06 16:18:48 +00:00
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
#+begin_src bash :results raw
|
2020-11-13 17:14:44 +00:00
|
|
|
time node -e "console.log('Hello, World');"
|
2020-11-06 16:18:48 +00:00
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
* 7. It /definitely/ does /something/.
|
|
|
|
|
|
|
|
|
|
We can tell, because it's making system calls.
|
|
|
|
|
|
|
|
|
|
#+begin_src bash :results raw
|
|
|
|
|
strace node -e ""
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
Lot of noise for a program that does "nothing"...
|
|
|
|
|
|
|
|
|
|
#+begin_src bash :results raw
|
|
|
|
|
strace node -e "console.log('Hello, World');"
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
* 8. JavaScript
|
|
|
|
|
We've actually started with something difficult.
|
|
|
|
|
|
|
|
|
|
JavaScript is an interpreted language.
|
|
|
|
|
|
|
|
|
|
#+begin_src js
|
|
|
|
|
const myProgram = '0 + 1'.replace('+', '-');
|
|
|
|
|
|
|
|
|
|
const result = eval(myProgram);
|
|
|
|
|
|
|
|
|
|
console.log(result); // -1
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
#+RESULTS:
|
|
|
|
|
|
|
|
|
|
* 9. C
|
|
|
|
|
Let's use a simpler example.
|
|
|
|
|
|
|
|
|
|
C is compiled.
|
|
|
|
|
|
|
|
|
|
We create our own program, rather than use a program that interprets strings.
|
|
|
|
|
|
|
|
|
|
#+begin_src C :results raw
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
int main(void) {
|
|
|
|
|
printf("Hello, World\n");
|
|
|
|
|
}
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
* 10. Compile and Execute
|
|
|
|
|
|
|
|
|
|
#+begin_src bash
|
|
|
|
|
gcc hello-world.c -o hello-world
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
#+begin_src bash
|
|
|
|
|
./hello-world
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
#+begin_src bash
|
|
|
|
|
strace ./hello-world
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
* 11. write
|
|
|
|
|
This seems familiar:
|
|
|
|
|
#+begin_src C
|
|
|
|
|
write(1, "Hello, World\n", 13Hello, World
|
|
|
|
|
) = 13
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
It's in our node program, too:
|
|
|
|
|
#+begin_src bash
|
|
|
|
|
strace node -e "console.log('Hello, World');" 2>&1 | grep "Hello"
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
/What is this?/
|
|
|
|
|
What is ~write~?
|
|
|
|
|
What is 1?
|
|
|
|
|
What is 13?
|
|
|
|
|
|
|
|
|
|
* 12. System Calls
|
|
|
|
|
~strace~ shows us system calls. ~write~ is a system call.
|
|
|
|
|
|
|
|
|
|
What is a system call?
|
|
|
|
|
|
|
|
|
|
#+begin_src bash
|
|
|
|
|
man syscalls
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
#+begin_quote
|
|
|
|
|
The system call is the fundamental interface between an application and the Linux kernel.
|
|
|
|
|
#+end_quote
|
|
|
|
|
|
|
|
|
|
* 13. write
|
|
|
|
|
|
|
|
|
|
#+begin_src bash
|
|
|
|
|
man 2 write
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
#+begin_src C
|
|
|
|
|
write(int fd, const void *buf, size_t count);
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
#+begin_quote
|
|
|
|
|
write() writes up to count bytes from the buffer starting at buf to the file referred to by the file descriptor fd.
|
|
|
|
|
#+end_quote
|
|
|
|
|
|
|
|
|
|
* 14. write
|
|
|
|
|
|
|
|
|
|
#+begin_src text
|
|
|
|
|
write(1, "Hello, World\n", 13Hello, World
|
|
|
|
|
) = 13
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
File Descriptor 1 = Standard Out (inherited from terminal process)
|
|
|
|
|
Hello World = Buffer
|
|
|
|
|
Count = 13 bytes
|
|
|
|
|
|
|
|
|
|
|---+---+---+---+---+---+---+---+---+---+---+---+----|
|
|
|
|
|
| H | e | l | l | o | , | | W | o | r | l | d | \n |
|
|
|
|
|
|---+---+---+---+---+---+---+---+---+---+---+---+----|
|
|
|
|
|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | 1 | 2 | 3 |
|
|
|
|
|
|---+---+---+---+---+---+---+---+---+---+---+---+----|
|
|
|
|
|
|
|
|
|
|
* 15. Back to Nothing
|
|
|
|
|
#+begin_src C
|
|
|
|
|
int main(void) {}
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
#+begin_src bash
|
|
|
|
|
gcc exit.c -o exit
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
#+begin_src bash
|
|
|
|
|
strace ./exit
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
* 16. Exit Code
|
|
|
|
|
In C, the return type prefixes the function.
|
|
|
|
|
|
|
|
|
|
~main~ returns an ~int~; the default is zero (indicating no error).
|
|
|
|
|
|
|
|
|
|
#+begin_src C
|
|
|
|
|
int main(void) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
#+begin_src C
|
|
|
|
|
exit_group(1)
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
* 17. exit_group
|
|
|
|
|
#+begin_src bash
|
|
|
|
|
man 2 exit_group
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
#+begin_src C
|
|
|
|
|
void exit_group(int status);
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
* 18. Exit
|
|
|
|
|
|
2020-11-13 03:34:31 +00:00
|
|
|
[[file:src/exit/exit.s]]
|
2020-11-06 16:18:48 +00:00
|
|
|
|
|
|
|
|
* 19. Assemble, Link, Execute, Trace
|
|
|
|
|
#+begin_src bash
|
|
|
|
|
as exit.s -o exit.o
|
|
|
|
|
|
|
|
|
|
ld exit.o -o exit
|
|
|
|
|
|
|
|
|
|
./exit
|
|
|
|
|
|
|
|
|
|
strace ./exit
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
* 20. x86 Assembly
|
|
|
|
|
- Human readable form of machine code.
|
|
|
|
|
- 1-to-1 mapping between one assembly instruction and one CPU instruction.
|
|
|
|
|
- Hardware specific: e.g., x86 Assembly differs from ARM Assembly.
|
|
|
|
|
- Often OS specific --> Linux System Calls != BSD, Mac, Windows system calls.
|
|
|
|
|
- Different syntax formats: ATT, Intel.
|
2020-11-13 17:14:44 +00:00
|
|
|
- Examples use ATT syntax.
|
2020-11-06 16:18:48 +00:00
|
|
|
- What instructions? Need to consult hardware manual.
|
|
|
|
|
- [[https://software.intel.com/content/www/us/en/develop/articles/intel-sdm.html][Intel x86 Developer Manual]] is ~5,000 pages long, plus errata.
|
|
|
|
|
|
2020-11-13 17:14:44 +00:00
|
|
|
#+begin_src bash
|
|
|
|
|
lscpu
|
|
|
|
|
#+end_src
|
|
|
|
|
|
2020-11-06 16:18:48 +00:00
|
|
|
* 21. Use Cases
|
|
|
|
|
- Low-level programming (micro-controllers, operating systems)
|
|
|
|
|
- Resource Constrained Hardware
|
2020-11-13 17:14:44 +00:00
|
|
|
- [[https://github.com/chrislgarry/Apollo-11][Apollo 11 Guidance Computer Assembly]] (1969)
|
|
|
|
|
- [[https://github.com/pret/pokered][Pokemon Red/Blue Assembly]] (1996, AA batteries)
|
2020-11-06 16:18:48 +00:00
|
|
|
- Performance
|
2020-11-13 17:14:44 +00:00
|
|
|
- Less runtime overhead (system calls, etc)
|
|
|
|
|
- Better code than compiler (harder to do these days)
|
2020-11-06 16:18:48 +00:00
|
|
|
- Control
|
2020-11-13 17:14:44 +00:00
|
|
|
- Instructions not available in higher level language
|
2020-11-06 16:18:48 +00:00
|
|
|
- Reverse Engineering
|
|
|
|
|
|
2020-11-13 17:14:44 +00:00
|
|
|
#+begin_src bash
|
|
|
|
|
hexdump -C exit
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
#+begin_src bash
|
|
|
|
|
objdump -D exit
|
|
|
|
|
#+end_src
|
|
|
|
|
|
2020-11-06 16:18:48 +00:00
|
|
|
* 22. Instructions
|
2020-11-13 03:34:31 +00:00
|
|
|
- Represented by numbers (opcodes).
|
2020-11-06 16:18:48 +00:00
|
|
|
- Describe an operation the CPU should perform, e.g.:
|
|
|
|
|
- Move data in and out of registers
|
|
|
|
|
- Modify register contents
|
|
|
|
|
- Modify stack
|
|
|
|
|
- Control program flow
|
|
|
|
|
|
|
|
|
|
* 23. Instruction Cycle
|
|
|
|
|
- On every tick of its internal clock, the CPU:
|
|
|
|
|
- *Fetches* the next instruction.
|
|
|
|
|
- *Decodes* it (what operation, on what operands).
|
|
|
|
|
- *Executes* the instruction.
|
|
|
|
|
- Increments the instruction pointer.
|
|
|
|
|
|
|
|
|
|
* 24. Registers
|
|
|
|
|
- Storage on the CPU (fastest storage).
|
|
|
|
|
- Act as a scratchpad -- temporary variables.
|
|
|
|
|
- General Purpose Registers
|
|
|
|
|
- RAX, RBX, RCX
|
|
|
|
|
- RSP, RBP (stack pointer, stack frame pointer)
|
|
|
|
|
- Special Purpose Registers
|
|
|
|
|
- RIP (Instruction Pointer)
|
|
|
|
|
- RFLAGS (negative, zero, etc.)
|
|
|
|
|
- It's possible to use just a portion of the register.
|
|
|
|
|
#+begin_src text
|
|
|
|
|
|__64__|__56__|__48__|__40__|__32__|__24__|__16__|__8___|
|
|
|
|
|
|__________________________RAX__________________________|
|
|
|
|
|
|xxxxxxxxxxxxxxxxxxxxxxxxxxx|____________EAX____________|
|
|
|
|
|
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|_____AX______|
|
|
|
|
|
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|__AH__|__AL__|
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
* 25. Exit++
|
|
|
|
|
|
|
|
|
|
[[file:src/math/math.s]]
|
|
|
|
|
|
|
|
|
|
* 26. Sections
|
|
|
|
|
What happens when we run a program? A few things...
|
|
|
|
|
|
|
|
|
|
One of them: the kernel loads the executable into memory.
|
|
|
|
|
|
|
|
|
|
Assembly sections refer to executable's memory layout:
|
|
|
|
|
|
|
|
|
|
|-----------|
|
|
|
|
|
| TEXT | --> Code (instructions)
|
|
|
|
|
| RODATA | --> const str = "Hello, World";
|
|
|
|
|
| DATA | --> var str = "Hello, World";
|
|
|
|
|
| BSS | --> var str;
|
2020-11-13 03:34:31 +00:00
|
|
|
| ↓ HEAP ↓ | --> (for traditional C)
|
2020-11-06 16:18:48 +00:00
|
|
|
| |
|
|
|
|
|
| ↑ STACK ↑ |
|
|
|
|
|
|-----------|
|
|
|
|
|
|
|
|
|
|
* 27. Hello World
|
|
|
|
|
|
|
|
|
|
[[file:src/hello-world/hello-world.s]]
|
|
|
|
|
|
|
|
|
|
* 28. Control Flow
|
|
|
|
|
Programs are either sequential, looping, or branching.
|
|
|
|
|
|
|
|
|
|
- CPU sets FLAGS register after instruction: e.g., result is zero, negative.
|
|
|
|
|
- Jump to code based on the state of FLAGS.
|
2020-11-13 17:14:44 +00:00
|
|
|
- Jump changes instruction pointer.
|
2020-11-06 16:18:48 +00:00
|
|
|
|
|
|
|
|
[[file:src/control-flow/control-flow.s]]
|
|
|
|
|
|
|
|
|
|
* 29. Stack
|
|
|
|
|
RSP register points to the top of the stack.
|
|
|
|
|
RBP register (typically) points to the (current) base of the stack.
|
|
|
|
|
Together, they form a stack frame.
|
|
|
|
|
|
|
|
|
|
Instructions:
|
|
|
|
|
- ~push~ :: decrements RSP, moves bytes onto stack.
|
|
|
|
|
- ~pop~ :: increments RSP, moves stack bytes into register.
|
|
|
|
|
|
|
|
|
|
[[file:src/stack/stack.s]]
|
|
|
|
|
|
|
|
|
|
* 30. Functions
|
|
|
|
|
Why do we use functions? Same reasons apply in Assembly:
|
|
|
|
|
- Reuse
|
|
|
|
|
- Organization
|
|
|
|
|
- Abstraction
|
|
|
|
|
- Splitting work
|
|
|
|
|
|
|
|
|
|
Problems:
|
|
|
|
|
- How to pass arguments?
|
|
|
|
|
- Registers -- which ones?
|
|
|
|
|
- Stack -- what order?
|
|
|
|
|
- Whose job is it to preserve or clean up registers? Caller? Callee?
|
|
|
|
|
- E.g., caller saves a value in %rbx to use after function returns.
|
|
|
|
|
- Callee uses %rbx and overwrites that value.
|
|
|
|
|
- How to pass return value(s)?
|
|
|
|
|
|
|
|
|
|
* 31. Convention
|
|
|
|
|
Which side of the street should we drive on?
|
|
|
|
|
Either way works, both are used in practice.
|
|
|
|
|
What matters is agreement on an approach.
|
|
|
|
|
|
2020-11-13 17:14:44 +00:00
|
|
|
[[file:static/convention.jpg]]
|
|
|
|
|
|
2020-11-06 16:18:48 +00:00
|
|
|
System V AMD64 ABI is calling convention for Unix x64 systems:
|
|
|
|
|
- Some registers must be saved by the caller, so callee can use them.
|
2020-11-13 17:19:09 +00:00
|
|
|
- Some registers must be saved by callee, if they plan to use them later.
|
2020-11-06 16:18:48 +00:00
|
|
|
- Some registers used to pass arguments.
|
|
|
|
|
- Stack used to pass extra or large arguments.
|
|
|
|
|
- RAX and RDX are used for return values.
|
|
|
|
|
|
|
|
|
|
* 32. Stack Arguments
|
|
|
|
|
|
|
|
|
|
[[file:src/func/func.s]]
|
|
|
|
|
|
|
|
|
|
Each row is 8 bytes (64 bits).
|
|
|
|
|
|----------------+-----------+----------------|
|
|
|
|
|
| Address | Data | Stack Pointers |
|
|
|
|
|
|----------------+-----------+----------------|
|
|
|
|
|
| 0x7fffffffe8f8 | | |
|
|
|
|
|
| 0x7fffffffe900 | 0x0 (rbp) | |
|
|
|
|
|
| 0x7fffffffe908 | 0x401002 | |
|
|
|
|
|
| 0x7fffffffe910 | 3 | ←rsp |
|
|
|
|
|
|----------------+-----------+----------------|
|
|
|
|
|
←rbp
|
|
|
|
|
|
|
|
|
|
* 33. Safety and Security
|
|
|
|
|
|
|
|
|
|
[[file:src/safety/safety.s]]
|
|
|
|
|
|
|
|
|
|
* 34. Review
|
|
|
|
|
Where we started:
|
|
|
|
|
|
|
|
|
|
#+begin_src bash
|
|
|
|
|
node -e ""
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
- CPU processes instructions
|
|
|
|
|
- Uses registers and memory (stack)
|
|
|
|
|
- Control flow with jump instruction and flags register
|
|
|
|
|
- Functions
|
|
|
|
|
- System Calls
|
|
|
|
|
- Comparison with Compiled and Interpreted Languages
|
|
|
|
|
- Tradeoffs
|
|
|
|
|
|
|
|
|
|
* 35. Conclusion
|
|
|
|
|
- Insight into how computers work.
|
2020-11-13 17:14:44 +00:00
|
|
|
- Appreciation for higher level, and work done to get us here.
|
2020-11-06 16:18:48 +00:00
|
|
|
- A platform to better understand things like functions, closures, APIs, pass by reference and pass by value, performance.
|
2020-11-13 17:19:09 +00:00
|
|
|
- A few mysteries to leave you curious...
|
2020-11-06 16:18:48 +00:00
|
|
|
|
|
|
|
|
* 36. References / Further Reading
|
|
|
|
|
|
2020-11-13 17:14:44 +00:00
|
|
|
- [[https://www.youtube.com/watch?v=tpIctyqH29Q&list=PL8dPuuaLjXtNlUrzyH5r6jN9ulIgZBpdo][Crash Course: Computer Science]]
|
2020-11-06 16:18:48 +00:00
|
|
|
- Davy Wybiral, [[https://www.youtube.com/playlist?list=PLmxT2pVYo5LB5EzTPZGfFN0c2GDiSXgQe][Intro to x86 Assembly Language]]
|
2020-11-13 17:19:09 +00:00
|
|
|
- [[https://www.gnu.org/software/gdb/][GDB]]
|
2020-11-06 16:18:48 +00:00
|
|
|
- Jennifer Rexford, [[https://www.cs.princeton.edu/courses/archive/fall05/cos217/][Princeton COS 217: Introduction to Programming Systems]]
|
|
|
|
|
- [[https://en.wikipedia.org/wiki/Structured_program_theorem][Structured Program Theorem]]
|