From 51fe910d6925c3806e60a5a23baf0dc74571912c Mon Sep 17 00:00:00 2001 From: Rares-Stefan Goidescu Date: Sun, 29 Mar 2026 12:22:15 +0300 Subject: [PATCH 1/2] labs/lab-07/reading: Fix inconsistencies and update code examples Update the `stack.md` reading material to be consistent with 64-bit architecture: - Fix typos - Fix numbering in Stack Operations section - Update all code examples to be complete, runnable programs using `printf64.asm`, proper function preamble/epilogue, and main entry point - Replace legacy `io.asm` and `CMAIN` references with `printf64.asm` and `main` - Fix format string spacing in `PRINTF64` macro calls - Use standard LIFO terminology instead of 'first in, last out' - Clarify the historical context for 32-bit ebp register reference Signed-off-by: Rares-Stefan Goidescu --- labs/lab-07/reading/stack.md | 85 ++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 27 deletions(-) diff --git a/labs/lab-07/reading/stack.md b/labs/lab-07/reading/stack.md index dafbeebd..84316c9c 100644 --- a/labs/lab-07/reading/stack.md +++ b/labs/lab-07/reading/stack.md @@ -5,7 +5,7 @@ parent: Lab 7 - The Stack # Reading: Introduction to the Stack -In this lab, we will learn about how the stack is represented in assembly language, its utility, and how to it could be useful to us. +In this lab, we will learn about how the stack is represented in assembly language, its utility, and how it could be useful to us. ## Reminder: Stack Data Structure @@ -28,7 +28,7 @@ Finally, the "pop" instruction makes the stack lose element 2. ![Stack Stages](../media/the-stack.svg) -As the above image suggests, the order in which items are inserted and removed from a stack is represented by the phrase "first in, last out". +As the above image suggests, the order in which items are inserted and removed from a stack is represented by the phrase "Last In, First Out" (LIFO). ## So, Why is it Useful? @@ -45,8 +45,8 @@ You might have also felt the absence of functions. The stack will help us out as More on this in the next lab. As you might have guessed, the solution to this is to use a stack on which we can put arbitrary values onto. -We don't need implement it ourselves - it comes built-in 😄! -Whenever a program stars, the kernel makes sure a zone of memory is allocated for the sole purpose of writing arbitrary data onto. +We don't need to implement it ourselves - it comes built-in 😄! +Whenever a program starts, the kernel makes sure a zone of memory is allocated for the sole purpose of writing arbitrary data onto. Moreover, CPUs also have some specialized instructions that work directly with this memory in a way similar to how a normal stack works. > **Note**: The size of the stack memory area is often [set at compile-time](https://stackoverflow.com/questions/54821412/how-to-increase-stack-size-when-compiling-a-c-program-using-mingw-compiler). @@ -60,42 +60,57 @@ The stack can be modified in two ways: 1. By using special instructions designed for stack operations, the most common of which are `push` and `pop`: ```assembly -%include "io.asm" +%include "printf64.asm" section .text -global CMAIN -CMAIN: + +extern printf +global main +main: + push rbp + mov rbp, rsp mov rax, 7 mov rbx, 8 add rax, rbx - push rax ; push the value of the rax register onto the stack - mov rax, 10 ; we can now use the rax register, as its value is saved on the stack - PRINTF64 `%d \n\x0`, rax ; 10 + push rax ; push the value of the rax register onto the stack + mov rax, 10 ; we can now use the rax register, as its value is saved on the stack + PRINTF64 `%d\n\x0`, rax ; prints 10 + + pop rax ; retrieve the value of the rax register from the stack + PRINTF64 `%d\n\x0`, rax ; prints 15 - pop rax ; retrieve the value of the rax register from the stack - PRINTF64 `%d \n\x0`, rax ; 15 + leave + ret ``` -1. By directly accessing the memory with the help of a special register in which the top of the stack is held - `rsp` also known as the "stack pointer register". +2. By directly accessing the memory with the help of a special register in which the top of the stack is held - `rsp` also known as the "stack pointer register". ```assembly -%include "io.asm" +%include "printf64.asm" section .text -global CMAIN -CMAIN: + +extern printf +global main +main: + push rbp + mov rbp, rsp + mov rax, 7 mov rbx, 8 add rax, rbx - sub rsp, 8 ; reserve 8 bytes on the stack - mov [rsp], rax ; move the contents of the rax register to the new address pointed to by rsp + sub rsp, 8 ; reserve 8 bytes on the stack + mov [rsp], rax ; move the contents of the rax register to the new address pointed to by rsp mov rax, 10 - PRINTF64 `%d \n\x0`, rax + PRINTF64 `%d\n\x0`, rax ; prints 10 + + mov rax, [rsp] ; retrieve the value from the stack + add rsp, 8 ; restore the value of the rsp register + PRINTF64 `%d\n\x0`, rax ; prints 15 - mov rax, [rsp] ; retrieve the value from the stack - add rsp, 8 ; restore the value of the rsp register - PRINTF64 `%d \n\x0`, rax + leave + ret ``` > **IMPORTANT:** Comment out the instructions `sub rsp, 8` and `add rsp, 8`. @@ -153,9 +168,16 @@ Given that the stack is used for function calls, it is very important that when 1. In situations where we perform N `push`-es and reach the end of the function without doing a `pop` for any of the values, we can restore the stack pointer using the `add` instruction. ```assembly +%include "printf64.asm" + section .text -global CMAIN -CMAIN: + +extern printf +global main +main: + push rbp + mov rbp, rsp + mov rax, 5 mov rbx, 6 mov rcx, 7 @@ -165,6 +187,8 @@ CMAIN: push rcx add rsp, 24 ; equivalent to using 3 consecutive pop-s + + leave ret ``` @@ -172,10 +196,14 @@ CMAIN: This allows us to easily restore the stack pointer value at the end of the function, without having to keep track of the number of `push` operations performed. ```assembly +%include "printf64.asm" + section .text -global CMAIN -CMAIN: +extern printf +global main +main: + push rbp mov rbp, rsp ; save current stack pointer value in rbp mov rax, 5 @@ -187,6 +215,7 @@ CMAIN: push rcx mov rsp, rbp ; restore stack pointer value + pop rbp ret ``` @@ -194,4 +223,6 @@ CMAIN: As we can observe, the `rbp` register defines the stack frame for each function. Similarly to how we can address local variables using the `rsp` register, we can do the same with `rbp`. -Additionally, we will see that, on 32-bit systems, function parameters are addressed using its 32-bit equivalent, `ebp`. + +> **NOTE:** For historical context, on 32-bit x86 systems, function parameters are passed on the stack and addressed using the 32-bit equivalent of `rbp`, which is `ebp`. +> In contrast, 64-bit x86-64 systems pass the first six arguments in registers (`rdi`, `rsi`, `rdx`, `rcx`, `r8`, `r9` - in order), with any additional arguments passed on the stack. From 54a8b4dfda29e00ec769b37247d4171f5e66686a Mon Sep 17 00:00:00 2001 From: Rares-Stefan Goidescu Date: Sun, 29 Mar 2026 12:38:25 +0300 Subject: [PATCH 2/2] labs/lab-07/guides: Fix README inconsistencies and typos Update guide README files to be accurate and consistent with actual code: - Fix typos - Fix spelling and use 64-bit terminology - Fix format specifier: %d -> %ld for 64-bit values - Add explicit qword specifier to match actual file Signed-off-by: Rares-Stefan Goidescu --- labs/lab-07/guides/stack-addressing/README.md | 6 +++--- labs/lab-07/guides/stack-operations/README.md | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/labs/lab-07/guides/stack-addressing/README.md b/labs/lab-07/guides/stack-addressing/README.md index 8e4c8669..8bfcb7dc 100644 --- a/labs/lab-07/guides/stack-addressing/README.md +++ b/labs/lab-07/guides/stack-addressing/README.md @@ -5,9 +5,9 @@ parent: Lab 7 - The Stack # Guide: Stack Addressing -The `stack_addressing.asm` file demonstrates how data is stored on the stack, and especially in what order. +The `stack-addressing.asm` file demonstrates how data is stored on the stack, and especially in what order. -Here's what an usual output for the compiled program would be: +Here's what a usual output for the compiled program would be: ```c 0x7fff124f4830: 0x7fff124f48d0 @@ -43,7 +43,7 @@ main: mov rax, rbp print_stack: - PRINTF64 `%p: %p\n\x0`, rax, [rax] + PRINTF64 `%p: %p\n\x0`, rax, qword [rax] sub rax, 8 cmp rax, rsp diff --git a/labs/lab-07/guides/stack-operations/README.md b/labs/lab-07/guides/stack-operations/README.md index 98e7e125..55bfc7de 100644 --- a/labs/lab-07/guides/stack-operations/README.md +++ b/labs/lab-07/guides/stack-operations/README.md @@ -5,7 +5,7 @@ parent: Lab 7 - The Stack # Guide: Stack Operations -The `stack_operations.asm` file demonstrates various stack operations. +The `stack-operations.asm` file demonstrates various stack operations. The main focus is to show how to manipulate the stack by pushing and popping values, and how to "allocate" and "deallocate" memory on the stack. > **Note:** Notice how `push` and `pop` are just syntactic sugar for the simpler `sub`, `add`, and `mov` instructions. @@ -34,7 +34,7 @@ main: push qword 11 ; same as: sub rsp, 8 followed by: mov [rsp], 11 push qword 12 ; same as: sub rsp, 8 followed by: mov [rsp], 12 push qword 13 ; same as: sub rsp, 8 followed by: mov [rsp], 13 - push qword 14 ; same as: sub rsp, 8 followed by: mov [rsp], 13 + push qword 14 ; same as: sub rsp, 8 followed by: mov [rsp], 14 ; Version 1 pop rax ; same as: mov rax, [rsp] followed by: add rsp, 8 @@ -51,7 +51,7 @@ main: ; sub rsp <-> add rsp -> use to allocate/deallocate memory - ; Aloc 16 bytes <-> 2 long + ; Alloc 16 bytes <-> 2 qwords ; sub rsp, 16 ; mov [rsp], 10 ; mov [rsp + 8], 12 @@ -64,7 +64,7 @@ main: pop qword [var] mov rax, [var] - PRINTF64 `VAR: %d\n\x0`, rax + PRINTF64 `VAR: %ld\n\x0`, rax leave