From 236c61ec2d30270278f193fc923965d7c717a0d1 Mon Sep 17 00:00:00 2001 From: George Cosma Date: Wed, 24 Apr 2024 21:11:21 +0300 Subject: [PATCH] stack/stack: Add lab exercises, guides and reading Cool description here Signed-off-by: George Cosma --- .../stack/intro/drills/tasks/gcd/README.md | 13 ++ .../drills/tasks/gcd/solution/.gitignore | 1 + .../intro/drills/tasks/gcd/solution/Makefile | 1 + .../intro/drills/tasks/gcd/solution/gcd.asm | 45 +++++ .../intro/drills/tasks/gcd/support/.gitignore | 1 + .../intro/drills/tasks/gcd/support/Makefile | 25 +++ .../intro/drills/tasks/gcd/support/gcd.asm | 44 +++++ .../intro/drills/tasks/gcd/utils/printf32.asm | 24 +++ .../intro/drills/tasks/local-var/README.md | 9 + .../tasks/local-var/solution/.gitignore | 1 + .../drills/tasks/local-var/solution/Makefile | 1 + .../tasks/local-var/solution/local-var.asm | 106 ++++++++++ .../drills/tasks/local-var/support/.gitignore | 1 + .../drills/tasks/local-var/support/Makefile | 25 +++ .../tasks/local-var/support/local-var.asm | 73 +++++++ .../drills/tasks/local-var/utils/printf32.asm | 24 +++ .../stack/intro/drills/tasks/max/README.md | 7 + .../drills/tasks/max/solution/.gitignore | 1 + .../intro/drills/tasks/max/solution/Makefile | 1 + .../intro/drills/tasks/max/solution/max.asm | 22 +++ .../intro/drills/tasks/max/support/.gitignore | 1 + .../intro/drills/tasks/max/support/Makefile | 25 +++ .../intro/drills/tasks/max/support/max.asm | 16 ++ .../intro/drills/tasks/max/utils/printf32.asm | 24 +++ .../drills/tasks/reverse-array/README.md | 18 ++ .../tasks/reverse-array/solution/.gitignore | 1 + .../tasks/reverse-array/solution/Makefile | 1 + .../reverse-array/solution/reverse-array.asm | 38 ++++ .../tasks/reverse-array/support/.gitignore | 1 + .../tasks/reverse-array/support/Makefile | 25 +++ .../reverse-array/support/reverse-array.asm | 29 +++ .../tasks/reverse-array/utils/printf32.asm | 24 +++ .../drills/tasks/stack-addressing/README.md | 43 ++++ .../stack-addressing/solution/.gitignore | 1 + .../tasks/stack-addressing/solution/Makefile | 1 + .../solution/stack-addressing.asm | 48 +++++ .../tasks/stack-addressing/support/.gitignore | 1 + .../tasks/stack-addressing/support/Makefile | 25 +++ .../support/stack-addressing.asm | 38 ++++ .../tasks/stack-addressing/utils/printf32.asm | 24 +++ .../intro/guides/stack-addressing/README.md | 53 +++++ .../stack-addressing/support/.gitignore | 1 + .../guides/stack-addressing/support/Makefile | 25 +++ .../support/stack-addressing.asm | 26 +++ .../stack-addressing/utils/printf32.asm | 24 +++ .../intro/guides/stack-operations/README.md | 71 +++++++ .../stack-operations/support/.gitignore | 1 + .../guides/stack-operations/support/Makefile | 25 +++ .../support/stack-operations.asm | 59 ++++++ .../stack-operations/utils/printf32.asm | 24 +++ .../intro/media/process_address_space.jpg | Bin 0 -> 11930 bytes .../stack/intro/media/the-stack-growth.svg | 4 + chapters/stack/intro/media/the-stack.svg | 4 + chapters/stack/intro/reading/README.md | 187 ++++++++++++++++++ config.yaml | 23 +++ 55 files changed, 1336 insertions(+) create mode 100644 chapters/stack/intro/drills/tasks/gcd/README.md create mode 100644 chapters/stack/intro/drills/tasks/gcd/solution/.gitignore create mode 120000 chapters/stack/intro/drills/tasks/gcd/solution/Makefile create mode 100644 chapters/stack/intro/drills/tasks/gcd/solution/gcd.asm create mode 100644 chapters/stack/intro/drills/tasks/gcd/support/.gitignore create mode 100644 chapters/stack/intro/drills/tasks/gcd/support/Makefile create mode 100644 chapters/stack/intro/drills/tasks/gcd/support/gcd.asm create mode 100644 chapters/stack/intro/drills/tasks/gcd/utils/printf32.asm create mode 100644 chapters/stack/intro/drills/tasks/local-var/README.md create mode 100644 chapters/stack/intro/drills/tasks/local-var/solution/.gitignore create mode 120000 chapters/stack/intro/drills/tasks/local-var/solution/Makefile create mode 100644 chapters/stack/intro/drills/tasks/local-var/solution/local-var.asm create mode 100644 chapters/stack/intro/drills/tasks/local-var/support/.gitignore create mode 100644 chapters/stack/intro/drills/tasks/local-var/support/Makefile create mode 100644 chapters/stack/intro/drills/tasks/local-var/support/local-var.asm create mode 100644 chapters/stack/intro/drills/tasks/local-var/utils/printf32.asm create mode 100644 chapters/stack/intro/drills/tasks/max/README.md create mode 100644 chapters/stack/intro/drills/tasks/max/solution/.gitignore create mode 120000 chapters/stack/intro/drills/tasks/max/solution/Makefile create mode 100644 chapters/stack/intro/drills/tasks/max/solution/max.asm create mode 100644 chapters/stack/intro/drills/tasks/max/support/.gitignore create mode 100644 chapters/stack/intro/drills/tasks/max/support/Makefile create mode 100644 chapters/stack/intro/drills/tasks/max/support/max.asm create mode 100644 chapters/stack/intro/drills/tasks/max/utils/printf32.asm create mode 100644 chapters/stack/intro/drills/tasks/reverse-array/README.md create mode 100644 chapters/stack/intro/drills/tasks/reverse-array/solution/.gitignore create mode 120000 chapters/stack/intro/drills/tasks/reverse-array/solution/Makefile create mode 100644 chapters/stack/intro/drills/tasks/reverse-array/solution/reverse-array.asm create mode 100644 chapters/stack/intro/drills/tasks/reverse-array/support/.gitignore create mode 100644 chapters/stack/intro/drills/tasks/reverse-array/support/Makefile create mode 100644 chapters/stack/intro/drills/tasks/reverse-array/support/reverse-array.asm create mode 100644 chapters/stack/intro/drills/tasks/reverse-array/utils/printf32.asm create mode 100644 chapters/stack/intro/drills/tasks/stack-addressing/README.md create mode 100644 chapters/stack/intro/drills/tasks/stack-addressing/solution/.gitignore create mode 120000 chapters/stack/intro/drills/tasks/stack-addressing/solution/Makefile create mode 100644 chapters/stack/intro/drills/tasks/stack-addressing/solution/stack-addressing.asm create mode 100644 chapters/stack/intro/drills/tasks/stack-addressing/support/.gitignore create mode 100644 chapters/stack/intro/drills/tasks/stack-addressing/support/Makefile create mode 100644 chapters/stack/intro/drills/tasks/stack-addressing/support/stack-addressing.asm create mode 100644 chapters/stack/intro/drills/tasks/stack-addressing/utils/printf32.asm create mode 100644 chapters/stack/intro/guides/stack-addressing/README.md create mode 100644 chapters/stack/intro/guides/stack-addressing/support/.gitignore create mode 100644 chapters/stack/intro/guides/stack-addressing/support/Makefile create mode 100644 chapters/stack/intro/guides/stack-addressing/support/stack-addressing.asm create mode 100644 chapters/stack/intro/guides/stack-addressing/utils/printf32.asm create mode 100644 chapters/stack/intro/guides/stack-operations/README.md create mode 100644 chapters/stack/intro/guides/stack-operations/support/.gitignore create mode 100644 chapters/stack/intro/guides/stack-operations/support/Makefile create mode 100644 chapters/stack/intro/guides/stack-operations/support/stack-operations.asm create mode 100644 chapters/stack/intro/guides/stack-operations/utils/printf32.asm create mode 100644 chapters/stack/intro/media/process_address_space.jpg create mode 100644 chapters/stack/intro/media/the-stack-growth.svg create mode 100644 chapters/stack/intro/media/the-stack.svg create mode 100644 chapters/stack/intro/reading/README.md diff --git a/chapters/stack/intro/drills/tasks/gcd/README.md b/chapters/stack/intro/drills/tasks/gcd/README.md new file mode 100644 index 00000000..1744ffe6 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/gcd/README.md @@ -0,0 +1,13 @@ +# 5. GCD - Greatest Common Divisor + +Open `gcd.asm` and run the program. +The code calculates the greatest common divisor (GCD) of two numbers given as parameters using the `eax` and `edx` registers, and then stores the calculated value back in the `eax` register. + +1. Make the necessary modifications so that the error message - `Segmentation fault (core dumped)` - no longer appears. +1. Within the `print` label, display the result in the following format: + +```c +gcd(49,28)=7 +``` + +If you're having difficulties solving this exercise, go through [this](../../../reading/README.md) reading material diff --git a/chapters/stack/intro/drills/tasks/gcd/solution/.gitignore b/chapters/stack/intro/drills/tasks/gcd/solution/.gitignore new file mode 100644 index 00000000..8aab0aa9 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/gcd/solution/.gitignore @@ -0,0 +1 @@ +gcd diff --git a/chapters/stack/intro/drills/tasks/gcd/solution/Makefile b/chapters/stack/intro/drills/tasks/gcd/solution/Makefile new file mode 120000 index 00000000..a39be4f2 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/gcd/solution/Makefile @@ -0,0 +1 @@ +../support/Makefile \ No newline at end of file diff --git a/chapters/stack/intro/drills/tasks/gcd/solution/gcd.asm b/chapters/stack/intro/drills/tasks/gcd/solution/gcd.asm new file mode 100644 index 00000000..77d73324 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/gcd/solution/gcd.asm @@ -0,0 +1,45 @@ +; SPDX-License-Identifier: BSD-3-Clause + +%include "../utils/printf32.asm" + +section .text + +extern printf +global main +main: + ; Input values (eax, edx) : the 2 numbers to compute the gcd for. + mov eax, 49 + mov edx, 28 + + push eax + push edx + +gcd: + neg eax + je gcd_end + +swap_values: + neg eax + push eax + push edx + pop eax + pop edx + +subtract_values: + sub eax,edx + jg subtract_values + jne swap_values + +gcd_end: + add eax,edx + jne print + inc eax + +print: + pop edx + pop ebx + + PRINTF32 `gcd(%d, %d) = %d\n\x0`, ebx, edx, eax ; eax = greatest common divisor + + xor eax, eax + ret diff --git a/chapters/stack/intro/drills/tasks/gcd/support/.gitignore b/chapters/stack/intro/drills/tasks/gcd/support/.gitignore new file mode 100644 index 00000000..0c33b182 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/gcd/support/.gitignore @@ -0,0 +1 @@ +gcd \ No newline at end of file diff --git a/chapters/stack/intro/drills/tasks/gcd/support/Makefile b/chapters/stack/intro/drills/tasks/gcd/support/Makefile new file mode 100644 index 00000000..aa8fece8 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/gcd/support/Makefile @@ -0,0 +1,25 @@ +AS = nasm +CC = gcc +RM = rm + +SRCS := $(shell find . -name "*.asm") +OBJS := $(SRCS:.asm=.o) + +UTILSDIR := ../utils/ + +ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)" +CFLAGS ?= -Wall +LDFLAGS ?= -m32 -no-pie + +TARGET_EXEC = gcd + +$(TARGET_EXEC): $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ + +$(OBJS): $(SRCS) + $(AS) $(ASFLAGS) $< -o $@ + +.PHONY: clean + +clean: + $(RM) -r *.o $(TARGET_EXEC) diff --git a/chapters/stack/intro/drills/tasks/gcd/support/gcd.asm b/chapters/stack/intro/drills/tasks/gcd/support/gcd.asm new file mode 100644 index 00000000..4a7ebe0b --- /dev/null +++ b/chapters/stack/intro/drills/tasks/gcd/support/gcd.asm @@ -0,0 +1,44 @@ +%include "printf32.asm" + +section .text + +extern printf +global main +main: + ; input values (eax, edx): the 2 numbers to compute the gcd for + mov eax, 49 + mov edx, 28 + + push eax + push edx + +gcd: + neg eax + je gcd_end + +swap_values: + neg eax + push eax + push edx + pop eax + pop edx + +subtract_values: + sub eax,edx + jg subtract_values + jne swap_values + +gcd_end: + add eax,edx + jne print + inc eax + +print: + + ; TODO 1: solve the 'Segmentation fault!' error + + ; TODO 2: print the result in the form of: "gdc(eax, edx)=7" with PRINTF32 macro + ; output value in eax + + xor eax, eax + ret \ No newline at end of file diff --git a/chapters/stack/intro/drills/tasks/gcd/utils/printf32.asm b/chapters/stack/intro/drills/tasks/gcd/utils/printf32.asm new file mode 100644 index 00000000..0617f3d8 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/gcd/utils/printf32.asm @@ -0,0 +1,24 @@ +; SPDX-License-Identifier: BSD-3-Clause + +;;; macro to use printf with 32bit parameters: +;;; - 1st parameter MUST be an immediate in backquotes `EAX=%d ECX=%x \n\x0` +;;; escape \n and \x0 only work with backquotes +;;; - rest of parameters MUST be 32bit +;;; - gen purpose and flags are preserved +;;; - stack is cleaned +%macro PRINTF32 1-* + pushf + pushad + jmp %%endstr +%%str: db %1 +%%endstr: +%rep %0 - 1 +%rotate -1 + push dword %1 +%endrep + push %%str + call printf + add esp, 4*%0 + popad + popf +%endmacro diff --git a/chapters/stack/intro/drills/tasks/local-var/README.md b/chapters/stack/intro/drills/tasks/local-var/README.md new file mode 100644 index 00000000..7f05a419 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/local-var/README.md @@ -0,0 +1,9 @@ +# 4. Local Var + +The program `local-var.asm` in the laboratory archive combines two sorted arrays (`array_1` and `array_2`) by placing the resulting array in `array_output` defined in the `.data` section. + +Modify the program so that `array_1`, `array_2`, and `array_output` are allocated on the stack. +The array allocation is done using the `sub` instruction. +For the copies of arrays `array_1` and `array_2`, you will need to copy their elements from the `.data` section to the stack before using them. + +If you're having difficulties solving this exercise, go through [this](../../../reading/README.md) reading material diff --git a/chapters/stack/intro/drills/tasks/local-var/solution/.gitignore b/chapters/stack/intro/drills/tasks/local-var/solution/.gitignore new file mode 100644 index 00000000..f6a37181 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/local-var/solution/.gitignore @@ -0,0 +1 @@ +local-var \ No newline at end of file diff --git a/chapters/stack/intro/drills/tasks/local-var/solution/Makefile b/chapters/stack/intro/drills/tasks/local-var/solution/Makefile new file mode 120000 index 00000000..a39be4f2 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/local-var/solution/Makefile @@ -0,0 +1 @@ +../support/Makefile \ No newline at end of file diff --git a/chapters/stack/intro/drills/tasks/local-var/solution/local-var.asm b/chapters/stack/intro/drills/tasks/local-var/solution/local-var.asm new file mode 100644 index 00000000..4a718773 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/local-var/solution/local-var.asm @@ -0,0 +1,106 @@ +%include "../utils/printf32.asm" + +section .data + +%define ARRAY_1_LEN 5 +%define ARRAY_2_LEN 7 +%define ARRAY_OUTPUT_LEN 12 + +section .data +array_1 dd 27, 46, 55, 83, 84 +array_2 dd 1, 4, 21, 26, 59, 92, 105 + +section .text + +extern printf +global main + +main: + mov ebp, esp + sub esp, 4 * ARRAY_1_LEN + mov eax, esp + mov edx, 0 +array_1_on_stack: + mov ecx, [array_1 + 4 * edx] + mov [eax], ecx + inc edx + add eax, 4 + cmp edx, ARRAY_1_LEN + jl array_1_on_stack + mov eax, esp + + sub esp, 4 * ARRAY_2_LEN + mov ebx, esp + mov edx, 0 +array_2_on_stack: + mov ecx, [array_2 + 4 * edx] + mov [ebx], ecx + inc edx + add ebx, 4 + cmp edx, ARRAY_2_LEN + jl array_2_on_stack + mov ebx, esp + sub esp, 4 * ARRAY_OUTPUT_LEN + mov ecx, esp + +merge_arrays: + mov edx, [eax] + cmp edx, [ebx] + jg array_2_lower +array_1_lower: + mov [ecx], edx ; The element from array_1 is lower + add eax, 4 + add ecx, 4 + jmp verify_array_end +array_2_lower: + mov edx, [ebx] + mov [ecx], edx ; The elements of the array_2 is lower + add ebx, 4 + add ecx, 4 + +verify_array_end: + mov edx, ebp + cmp eax, edx + jge copy_array_2 + sub edx, 4 * ARRAY_1_LEN + cmp ebx, ebp + jge copy_array_1 + jmp merge_arrays + +copy_array_1: + xor edx, edx + mov eax, [eax] + mov [ecx], edx + add ecx, 4 + add eax, 4 + cmp eax, ebp + jb copy_array_1 + jmp print_array +copy_array_2: + xor edx, edx + mov edx, [ebx] + mov [ecx], edx + add ecx, 4 + add ebx, 4 + mov edx, ebp + sub edx, 4 * ARRAY_1_LEN + cmp ebx, edx + jb copy_array_2 + +print_array: + PRINTF32 `Array merged:\n\x0` + xor eax, eax + xor ecx, ecx + +print: + mov eax, [esp] + PRINTF32 `%d \x0`, eax + add esp, 4 + inc ecx + cmp ecx, ARRAY_OUTPUT_LEN + jb print + + PRINTF32 `\n\x0` + xor eax, eax + mov esp, ebp + ret \ No newline at end of file diff --git a/chapters/stack/intro/drills/tasks/local-var/support/.gitignore b/chapters/stack/intro/drills/tasks/local-var/support/.gitignore new file mode 100644 index 00000000..f6a37181 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/local-var/support/.gitignore @@ -0,0 +1 @@ +local-var \ No newline at end of file diff --git a/chapters/stack/intro/drills/tasks/local-var/support/Makefile b/chapters/stack/intro/drills/tasks/local-var/support/Makefile new file mode 100644 index 00000000..9f26814b --- /dev/null +++ b/chapters/stack/intro/drills/tasks/local-var/support/Makefile @@ -0,0 +1,25 @@ +AS = nasm +CC = gcc +RM = rm + +SRCS := $(shell find . -name "*.asm") +OBJS := $(SRCS:.asm=.o) + +UTILSDIR := ../utils/ + +ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)" +CFLAGS ?= -Wall +LDFLAGS ?= -m32 -no-pie + +TARGET_EXEC = local-var + +$(TARGET_EXEC): $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ + +$(OBJS): $(SRCS) + $(AS) $(ASFLAGS) $< -o $@ + +.PHONY: clean + +clean: + $(RM) -r *.o $(TARGET_EXEC) diff --git a/chapters/stack/intro/drills/tasks/local-var/support/local-var.asm b/chapters/stack/intro/drills/tasks/local-var/support/local-var.asm new file mode 100644 index 00000000..39723080 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/local-var/support/local-var.asm @@ -0,0 +1,73 @@ +%include "printf32.asm" + +%define ARRAY_1_LEN 5 +%define ARRAY_2_LEN 7 +%define ARRAY_OUTPUT_LEN 12 + +section .data + +array_1 dd 27, 46, 55, 83, 84 +array_2 dd 1, 4, 21, 26, 59, 92, 105 +array_output times 12 dd 0 + + +section .text + +extern printf +global main +main: + mov eax, 0 ; counter used for array_1 + mov ebx, 0 ; counter used for array_2 + mov ecx, 0 ; counter used for the output array + +merge_arrays: + mov edx, [array_1 + 4 * eax] + cmp edx, [array_2 + 4 * ebx] + jg array_2_lower +array_1_lower: + mov [array_output + 4 * ecx], edx + inc eax + inc ecx + jmp verify_array_end +array_2_lower: + mov edx, [array_2 + 4 * ebx] + mov [array_output + 4 * ecx], edx + inc ecx + inc ebx + +verify_array_end: + cmp eax, ARRAY_1_LEN + jge copy_array_2 + cmp ebx, ARRAY_2_LEN + jge copy_array_1 + jmp merge_arrays + +copy_array_1: + mov edx, [array_1 + 4 * eax] + mov [array_output + 4 * ecx], edx + inc ecx + inc eax + cmp eax, ARRAY_1_LEN + jb copy_array_1 + jmp print_array +copy_array_2: + mov edx, [array_2 + 4 * ebx] + mov [array_output + 4 * ecx], edx + inc ecx + inc ebx + cmp ebx, ARRAY_2_LEN + jb copy_array_2 + +print_array: + PRINTF32 `Array merged:\n\x0` + mov ecx, 0 +print: + mov eax, [array_output + 4 * ecx] + PRINTF32 `%d \x0`, eax + inc ecx + cmp ecx, ARRAY_OUTPUT_LEN + jb print + + PRINTF32 `\n\x0` + xor eax, eax + ret \ No newline at end of file diff --git a/chapters/stack/intro/drills/tasks/local-var/utils/printf32.asm b/chapters/stack/intro/drills/tasks/local-var/utils/printf32.asm new file mode 100644 index 00000000..0617f3d8 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/local-var/utils/printf32.asm @@ -0,0 +1,24 @@ +; SPDX-License-Identifier: BSD-3-Clause + +;;; macro to use printf with 32bit parameters: +;;; - 1st parameter MUST be an immediate in backquotes `EAX=%d ECX=%x \n\x0` +;;; escape \n and \x0 only work with backquotes +;;; - rest of parameters MUST be 32bit +;;; - gen purpose and flags are preserved +;;; - stack is cleaned +%macro PRINTF32 1-* + pushf + pushad + jmp %%endstr +%%str: db %1 +%%endstr: +%rep %0 - 1 +%rotate -1 + push dword %1 +%endrep + push %%str + call printf + add esp, 4*%0 + popad + popf +%endmacro diff --git a/chapters/stack/intro/drills/tasks/max/README.md b/chapters/stack/intro/drills/tasks/max/README.md new file mode 100644 index 00000000..5cb36de2 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/max/README.md @@ -0,0 +1,7 @@ +# 1. Max + +Calculate the maximum between two numbers in two registers (eax and ebx) using a comparison instruction, a jump instruction, and push/pop instructions. + +> **TIP:** Consider how you can swap two registers using the stack. + +If you're having difficulties solving this exercise, go through [this](../../../reading/README.md) reading material diff --git a/chapters/stack/intro/drills/tasks/max/solution/.gitignore b/chapters/stack/intro/drills/tasks/max/solution/.gitignore new file mode 100644 index 00000000..7c35932f --- /dev/null +++ b/chapters/stack/intro/drills/tasks/max/solution/.gitignore @@ -0,0 +1 @@ +max \ No newline at end of file diff --git a/chapters/stack/intro/drills/tasks/max/solution/Makefile b/chapters/stack/intro/drills/tasks/max/solution/Makefile new file mode 120000 index 00000000..a39be4f2 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/max/solution/Makefile @@ -0,0 +1 @@ +../support/Makefile \ No newline at end of file diff --git a/chapters/stack/intro/drills/tasks/max/solution/max.asm b/chapters/stack/intro/drills/tasks/max/solution/max.asm new file mode 100644 index 00000000..593b1601 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/max/solution/max.asm @@ -0,0 +1,22 @@ +%include "../utils/printf32.asm" + +section .text + +extern printf +global main +main: + ; Numbers are placed in these two registers. + mov eax, 1 + mov ebx, 4 + + cmp eax, ebx + ja print_max + push eax + push ebx + pop eax + pop ebx + +print_max: + PRINTF32 `Max value is: %d\n\x0`, eax + + ret \ No newline at end of file diff --git a/chapters/stack/intro/drills/tasks/max/support/.gitignore b/chapters/stack/intro/drills/tasks/max/support/.gitignore new file mode 100644 index 00000000..7c35932f --- /dev/null +++ b/chapters/stack/intro/drills/tasks/max/support/.gitignore @@ -0,0 +1 @@ +max \ No newline at end of file diff --git a/chapters/stack/intro/drills/tasks/max/support/Makefile b/chapters/stack/intro/drills/tasks/max/support/Makefile new file mode 100644 index 00000000..4321fd57 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/max/support/Makefile @@ -0,0 +1,25 @@ +AS = nasm +CC = gcc +RM = rm + +SRCS := $(shell find . -name "*.asm") +OBJS := $(SRCS:.asm=.o) + +UTILSDIR := ../utils/ + +ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)" +CFLAGS ?= -Wall +LDFLAGS ?= -m32 -no-pie + +TARGET_EXEC = max + +$(TARGET_EXEC): $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ + +$(OBJS): $(SRCS) + $(AS) $(ASFLAGS) $< -o $@ + +.PHONY: clean + +clean: + $(RM) -r *.o $(TARGET_EXEC) diff --git a/chapters/stack/intro/drills/tasks/max/support/max.asm b/chapters/stack/intro/drills/tasks/max/support/max.asm new file mode 100644 index 00000000..04427d91 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/max/support/max.asm @@ -0,0 +1,16 @@ +%include "printf32.asm" + +section .text + +extern printf +global main +main: + ; numbers are placed in these two registers + mov eax, 1 + mov ebx, 4 + + ; TODO: get maximum value. You are only allowed to use one conditional jump and push/pop instructions. + + PRINTF32 `Max value is: %d\n\x0`, eax ; print maximum value + + ret diff --git a/chapters/stack/intro/drills/tasks/max/utils/printf32.asm b/chapters/stack/intro/drills/tasks/max/utils/printf32.asm new file mode 100644 index 00000000..0617f3d8 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/max/utils/printf32.asm @@ -0,0 +1,24 @@ +; SPDX-License-Identifier: BSD-3-Clause + +;;; macro to use printf with 32bit parameters: +;;; - 1st parameter MUST be an immediate in backquotes `EAX=%d ECX=%x \n\x0` +;;; escape \n and \x0 only work with backquotes +;;; - rest of parameters MUST be 32bit +;;; - gen purpose and flags are preserved +;;; - stack is cleaned +%macro PRINTF32 1-* + pushf + pushad + jmp %%endstr +%%str: db %1 +%%endstr: +%rep %0 - 1 +%rotate -1 + push dword %1 +%endrep + push %%str + call printf + add esp, 4*%0 + popad + popf +%endmacro diff --git a/chapters/stack/intro/drills/tasks/reverse-array/README.md b/chapters/stack/intro/drills/tasks/reverse-array/README.md new file mode 100644 index 00000000..b91b9e18 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/reverse-array/README.md @@ -0,0 +1,18 @@ +# 2. Reverse Array + +Building on the `reverse-array.asm` exercise, implement the `TODO`s without using the `mov` instruction when working with arrays, so that at the end of the program, the `output` array contains the `input` array in reverse order. + +> **NOTE:** After a correct solution, the program should print: +> +>```c +> Reversed array: +> 911 +> 845 +> 263 +> 242 +> 199 +> 184 +> 122 +>``` + +If you're having difficulties solving this exercise, go through [this](../../../reading/README.md) reading material diff --git a/chapters/stack/intro/drills/tasks/reverse-array/solution/.gitignore b/chapters/stack/intro/drills/tasks/reverse-array/solution/.gitignore new file mode 100644 index 00000000..d251583c --- /dev/null +++ b/chapters/stack/intro/drills/tasks/reverse-array/solution/.gitignore @@ -0,0 +1 @@ +reverse-array \ No newline at end of file diff --git a/chapters/stack/intro/drills/tasks/reverse-array/solution/Makefile b/chapters/stack/intro/drills/tasks/reverse-array/solution/Makefile new file mode 120000 index 00000000..a39be4f2 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/reverse-array/solution/Makefile @@ -0,0 +1 @@ +../support/Makefile \ No newline at end of file diff --git a/chapters/stack/intro/drills/tasks/reverse-array/solution/reverse-array.asm b/chapters/stack/intro/drills/tasks/reverse-array/solution/reverse-array.asm new file mode 100644 index 00000000..c1607b50 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/reverse-array/solution/reverse-array.asm @@ -0,0 +1,38 @@ +%include "../utils/printf32.asm" + +%define ARRAY_LEN 7 + +section .data + +input dd 122, 184, 199, 242, 263, 845, 911 +output times ARRAY_LEN dd 0 + +section .text + +extern printf +global main +main: + + push ARRAY_LEN + pop ecx +push_elem: + push dword [input + 4 * (ecx - 1)] + loop push_elem + + push ARRAY_LEN + pop ecx +pop_elem: + pop dword [output + 4 * (ecx - 1)] + loop pop_elem + + PRINTF32 `Reversed array: \n\x0` + xor ecx, ecx +print_array: + mov edx, [output + 4 * ecx] + PRINTF32 `%d\n\x0`, edx + inc ecx + cmp ecx, ARRAY_LEN + jb print_array + + xor eax, eax + ret diff --git a/chapters/stack/intro/drills/tasks/reverse-array/support/.gitignore b/chapters/stack/intro/drills/tasks/reverse-array/support/.gitignore new file mode 100644 index 00000000..d251583c --- /dev/null +++ b/chapters/stack/intro/drills/tasks/reverse-array/support/.gitignore @@ -0,0 +1 @@ +reverse-array \ No newline at end of file diff --git a/chapters/stack/intro/drills/tasks/reverse-array/support/Makefile b/chapters/stack/intro/drills/tasks/reverse-array/support/Makefile new file mode 100644 index 00000000..3d0e9a52 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/reverse-array/support/Makefile @@ -0,0 +1,25 @@ +AS = nasm +CC = gcc +RM = rm + +SRCS := $(shell find . -name "*.asm") +OBJS := $(SRCS:.asm=.o) + +UTILSDIR := ../utils/ + +ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)" +CFLAGS ?= -Wall +LDFLAGS ?= -m32 -no-pie + +TARGET_EXEC = reverse-array + +$(TARGET_EXEC): $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ + +$(OBJS): $(SRCS) + $(AS) $(ASFLAGS) $< -o $@ + +.PHONY: clean + +clean: + $(RM) -r *.o $(TARGET_EXEC) diff --git a/chapters/stack/intro/drills/tasks/reverse-array/support/reverse-array.asm b/chapters/stack/intro/drills/tasks/reverse-array/support/reverse-array.asm new file mode 100644 index 00000000..8319189b --- /dev/null +++ b/chapters/stack/intro/drills/tasks/reverse-array/support/reverse-array.asm @@ -0,0 +1,29 @@ +%include "printf32.asm" + +%define ARRAY_LEN 7 + +section .data + +input dd 122, 184, 199, 242, 263, 845, 911 +output times ARRAY_LEN dd 0 + +section .text + +extern printf +global main +main: + + ; TODO push the elements of the array on the stack + ; TODO retrieve the elements (pop) from the stack into the output array + + PRINTF32 `Reversed array: \n\x0` + xor ecx, ecx +print_array: + mov edx, [output + 4 * ecx] + PRINTF32 `%d\n\x0`, edx + inc ecx + cmp ecx, ARRAY_LEN + jb print_array + + xor eax, eax + ret diff --git a/chapters/stack/intro/drills/tasks/reverse-array/utils/printf32.asm b/chapters/stack/intro/drills/tasks/reverse-array/utils/printf32.asm new file mode 100644 index 00000000..0617f3d8 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/reverse-array/utils/printf32.asm @@ -0,0 +1,24 @@ +; SPDX-License-Identifier: BSD-3-Clause + +;;; macro to use printf with 32bit parameters: +;;; - 1st parameter MUST be an immediate in backquotes `EAX=%d ECX=%x \n\x0` +;;; escape \n and \x0 only work with backquotes +;;; - rest of parameters MUST be 32bit +;;; - gen purpose and flags are preserved +;;; - stack is cleaned +%macro PRINTF32 1-* + pushf + pushad + jmp %%endstr +%%str: db %1 +%%endstr: +%rep %0 - 1 +%rotate -1 + push dword %1 +%endrep + push %%str + call printf + add esp, 4*%0 + popad + popf +%endmacro diff --git a/chapters/stack/intro/drills/tasks/stack-addressing/README.md b/chapters/stack/intro/drills/tasks/stack-addressing/README.md new file mode 100644 index 00000000..6abf29b3 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/stack-addressing/README.md @@ -0,0 +1,43 @@ +# 3. Stack Addressing + +The `stack-addressing.asm` program in the lab's archive allocates and initializes two local variables on the stack: + +- an array of natural numbers from 1 to `NUM` +- a string "Ana are mere". + +1. Replace each `push` instruction with an equivalent sequence of instructions. +1. Print the addresses and values on the stack in the interval `[esp, ebp]` (from low addresses to high addresses) byte by byte. +1. Print the string allocated on the stack byte by byte and explain how it looks in memory. +Think about where you should start displaying and when you should stop. +1. Print the vector allocated on the stack element by element. +Think about where you should start displaying and what size each element has. + +> **NOTE:** After a successful implementation, the program should display something similar to the following output (it won't be exactly the same, stack memory addresses may differ): +> +>```c +>0xffcf071b: 65 +>0xffcf071c: 110 +>0xffcf071d: 97 +>0xffcf071e: 32 +>0xffcf071f: 97 +>... +>0xffcf0734: 4 +>0xffcf0735: 0 +>0xffcf0736: 0 +>0xffcf0737: 0 +>0xffcf0738: 5 +>0xffcf0739: 0 +>0xffcf073a: 0 +>0xffcf073b: 0 +>Ana are mere +>1 2 3 4 5 +>``` +> +> Explain the significance of each byte. +> Why are they arranged in that particular order? +> Why are some bytes 0? +> +> **TIP:** Remember that ASCII character codes are represented as decimal values. +Remember the order in which the bytes of a larger number are stored: review the section **Order of representation of numbers larger than one byte** from Lab 01. + +If you're having difficulties solving this exercise, go through [this](../../../reading/README.md) reading material diff --git a/chapters/stack/intro/drills/tasks/stack-addressing/solution/.gitignore b/chapters/stack/intro/drills/tasks/stack-addressing/solution/.gitignore new file mode 100644 index 00000000..7737b299 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/stack-addressing/solution/.gitignore @@ -0,0 +1 @@ +stack-addressing \ No newline at end of file diff --git a/chapters/stack/intro/drills/tasks/stack-addressing/solution/Makefile b/chapters/stack/intro/drills/tasks/stack-addressing/solution/Makefile new file mode 120000 index 00000000..a39be4f2 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/stack-addressing/solution/Makefile @@ -0,0 +1 @@ +../support/Makefile \ No newline at end of file diff --git a/chapters/stack/intro/drills/tasks/stack-addressing/solution/stack-addressing.asm b/chapters/stack/intro/drills/tasks/stack-addressing/solution/stack-addressing.asm new file mode 100644 index 00000000..f7bd97d3 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/stack-addressing/solution/stack-addressing.asm @@ -0,0 +1,48 @@ +%include "../utils/printf32.asm" + +%define NUM 5 +section .text + +extern printf +global main +main: + mov ebp, esp + mov ecx, NUM +push_nums: + sub esp, 4 + mov dword [esp], ecx + loop push_nums + + sub esp, 4 + mov dword [esp], 0 + + sub esp, 4 + mov dword [esp], "mere" + + sub esp, 4 + mov dword [esp], "are " + + sub esp, 4 + mov dword [esp], "Ana " + lea esi, [esp] + PRINTF32 `%s\n\x0`, esi + + ; Print the stack in "address: value" format. + mov eax, ebp +print_stack: + PRINTF32 `0x%x: 0x%x\n\x0`, eax, [eax] + + sub eax, 4 + cmp eax, esp + jge print_stack + + ; Print the string. + lea esi, [esp] + PRINTF32 `%s\n\x0`, esi + + ; Restore the previous value of the EBP (Base Pointer). + mov esp, ebp + + ; Exit without errors. + xor eax, eax + ret diff --git a/chapters/stack/intro/drills/tasks/stack-addressing/support/.gitignore b/chapters/stack/intro/drills/tasks/stack-addressing/support/.gitignore new file mode 100644 index 00000000..7737b299 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/stack-addressing/support/.gitignore @@ -0,0 +1 @@ +stack-addressing \ No newline at end of file diff --git a/chapters/stack/intro/drills/tasks/stack-addressing/support/Makefile b/chapters/stack/intro/drills/tasks/stack-addressing/support/Makefile new file mode 100644 index 00000000..4afa1bf6 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/stack-addressing/support/Makefile @@ -0,0 +1,25 @@ +AS = nasm +CC = gcc +RM = rm + +SRCS := $(shell find . -name "*.asm") +OBJS := $(SRCS:.asm=.o) + +UTILSDIR := ../utils/ + +ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)" +CFLAGS ?= -Wall +LDFLAGS ?= -m32 -no-pie + +TARGET_EXEC = stack-addressing + +$(TARGET_EXEC): $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ + +$(OBJS): $(SRCS) + $(AS) $(ASFLAGS) $< -o $@ + +.PHONY: clean + +clean: + $(RM) -r *.o $(TARGET_EXEC) diff --git a/chapters/stack/intro/drills/tasks/stack-addressing/support/stack-addressing.asm b/chapters/stack/intro/drills/tasks/stack-addressing/support/stack-addressing.asm new file mode 100644 index 00000000..9ebf991b --- /dev/null +++ b/chapters/stack/intro/drills/tasks/stack-addressing/support/stack-addressing.asm @@ -0,0 +1,38 @@ +%include "printf32.asm" + +%define NUM 5 + +section .text + +extern printf +global main +main: + mov ebp, esp + + ; TODO 1: replace every push by an equivalent sequence of commands (use direct addressing of memory. Hint: esp) + mov ecx, NUM +push_nums: + push ecx + loop push_nums + + push 0 + push "mere" + push "are " + push "Ana " + + lea esi, [esp] + PRINTF32 `%s\n\x0`, esi + + ; TODO 2: print the stack in "address: value" format in the range of [ESP:EBP] + ; use PRINTF32 macro - see format above + + ; TODO 3: print the string + + ; TODO 4: print the array on the stack, element by element. + + ; restore the previous value of the EBP (Base Pointer) + mov esp, ebp + + ; exit without errors + xor eax, eax + ret \ No newline at end of file diff --git a/chapters/stack/intro/drills/tasks/stack-addressing/utils/printf32.asm b/chapters/stack/intro/drills/tasks/stack-addressing/utils/printf32.asm new file mode 100644 index 00000000..0617f3d8 --- /dev/null +++ b/chapters/stack/intro/drills/tasks/stack-addressing/utils/printf32.asm @@ -0,0 +1,24 @@ +; SPDX-License-Identifier: BSD-3-Clause + +;;; macro to use printf with 32bit parameters: +;;; - 1st parameter MUST be an immediate in backquotes `EAX=%d ECX=%x \n\x0` +;;; escape \n and \x0 only work with backquotes +;;; - rest of parameters MUST be 32bit +;;; - gen purpose and flags are preserved +;;; - stack is cleaned +%macro PRINTF32 1-* + pushf + pushad + jmp %%endstr +%%str: db %1 +%%endstr: +%rep %0 - 1 +%rotate -1 + push dword %1 +%endrep + push %%str + call printf + add esp, 4*%0 + popad + popf +%endmacro diff --git a/chapters/stack/intro/guides/stack-addressing/README.md b/chapters/stack/intro/guides/stack-addressing/README.md new file mode 100644 index 00000000..35d46482 --- /dev/null +++ b/chapters/stack/intro/guides/stack-addressing/README.md @@ -0,0 +1,53 @@ +# Stack addressing + +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: + +```c +0xff99fba8: 0xf7f46020 +0xff99fba4: 0xa +0xff99fba0: 0xb +0xff99fb9c: 0xc +0xff99fb98: 0xd +``` + +> **Note:** The last 4 values are the ones we pushed on stack. +> What is the first one? +> +> **Answer:** It is the old EBP we push at the start of the function. + +For convenience, here's the contents of the file. +To play around with it, download the lab locally. + +```assembly +%include "printf32.asm" + +section .text + +extern printf +global main +main: + push ebp + mov ebp, esp + + push dword 10 + push dword 11 + push dword 12 + push dword 13 + + mov eax, ebp +print_stack: + PRINTF32 `0x\x0` + PRINTF32 `%x\x0`, eax + PRINTF32 `: 0x\x0` + PRINTF32 `%x\n\x0`, [eax] + + sub eax, 4 + cmp eax, esp + jge print_stack + + xor eax, eax + leave + ret +``` diff --git a/chapters/stack/intro/guides/stack-addressing/support/.gitignore b/chapters/stack/intro/guides/stack-addressing/support/.gitignore new file mode 100644 index 00000000..7737b299 --- /dev/null +++ b/chapters/stack/intro/guides/stack-addressing/support/.gitignore @@ -0,0 +1 @@ +stack-addressing \ No newline at end of file diff --git a/chapters/stack/intro/guides/stack-addressing/support/Makefile b/chapters/stack/intro/guides/stack-addressing/support/Makefile new file mode 100644 index 00000000..4afa1bf6 --- /dev/null +++ b/chapters/stack/intro/guides/stack-addressing/support/Makefile @@ -0,0 +1,25 @@ +AS = nasm +CC = gcc +RM = rm + +SRCS := $(shell find . -name "*.asm") +OBJS := $(SRCS:.asm=.o) + +UTILSDIR := ../utils/ + +ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)" +CFLAGS ?= -Wall +LDFLAGS ?= -m32 -no-pie + +TARGET_EXEC = stack-addressing + +$(TARGET_EXEC): $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ + +$(OBJS): $(SRCS) + $(AS) $(ASFLAGS) $< -o $@ + +.PHONY: clean + +clean: + $(RM) -r *.o $(TARGET_EXEC) diff --git a/chapters/stack/intro/guides/stack-addressing/support/stack-addressing.asm b/chapters/stack/intro/guides/stack-addressing/support/stack-addressing.asm new file mode 100644 index 00000000..0a5ef79c --- /dev/null +++ b/chapters/stack/intro/guides/stack-addressing/support/stack-addressing.asm @@ -0,0 +1,26 @@ +%include "printf32.asm" + +section .text + +extern printf +global main +main: + push ebp + mov ebp, esp + + push dword 10 + push dword 11 + push dword 12 + push dword 13 + + mov eax, ebp +print_stack: + PRINTF32 `%p: %p\n\x0`, eax, [eax] + + sub eax, 4 + cmp eax, esp + jge print_stack + + xor eax, eax + leave + ret \ No newline at end of file diff --git a/chapters/stack/intro/guides/stack-addressing/utils/printf32.asm b/chapters/stack/intro/guides/stack-addressing/utils/printf32.asm new file mode 100644 index 00000000..0617f3d8 --- /dev/null +++ b/chapters/stack/intro/guides/stack-addressing/utils/printf32.asm @@ -0,0 +1,24 @@ +; SPDX-License-Identifier: BSD-3-Clause + +;;; macro to use printf with 32bit parameters: +;;; - 1st parameter MUST be an immediate in backquotes `EAX=%d ECX=%x \n\x0` +;;; escape \n and \x0 only work with backquotes +;;; - rest of parameters MUST be 32bit +;;; - gen purpose and flags are preserved +;;; - stack is cleaned +%macro PRINTF32 1-* + pushf + pushad + jmp %%endstr +%%str: db %1 +%%endstr: +%rep %0 - 1 +%rotate -1 + push dword %1 +%endrep + push %%str + call printf + add esp, 4*%0 + popad + popf +%endmacro diff --git a/chapters/stack/intro/guides/stack-operations/README.md b/chapters/stack/intro/guides/stack-operations/README.md new file mode 100644 index 00000000..06bf493f --- /dev/null +++ b/chapters/stack/intro/guides/stack-operations/README.md @@ -0,0 +1,71 @@ +# 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. + +For convenience, here's the contents of the file. +To play around with it, download the lab locally. + +```assembly +%include "printf32.asm" + +section .data + var: dd ? + +section .text + +; esp -> stack pointer +; ebp -> base pointer + +extern printf +global main +main: + push ebp + mov ebp, esp + + push dword 10 ; sub esp, 4; mov [esp], 10; + push dword 11 ; sub esp, 4; mov [esp], 11; + push dword 12 ; sub esp, 4; mov [esp], 12; + push dword 13 ; sub esp, 4; mov [esp], 13; + push dword 14 ; sub esp, 4; mov [esp], 13; + + + pusha ; push all registers on the stack + popa ; pop all registers from the stack + + ; Version 1 + pop eax; ; mov eax, [esp]; add esp, 4 + pop eax; ; mov eax, [esp]; add esp, 4 + pop eax; ; mov eax, [esp]; add esp, 4 + pop eax; ; mov eax, [esp]; add esp, 4 + pop eax; ; mov eax, [esp]; add esp, 4 + + ; Version 2 + ; add esp, 20 ; 4 * number_of_push + + ; Version 3 + ; mov esp, ebp + + ; sub esp <-> add esp -> use to allocate/deallocate memory + + ; Aloc 8 bytes <-> 2 int + ; sub esp, 8 + ; mov [esp], 10 + ; mov [esp + 4], 12 + + ; Push/Pop from global variable + + mov dword [var], 1337 + + push dword [var] + pop dword [var] + + mov eax, [var] + PRINTF32 `VAR: %d\n\x0`, eax + + + leave + ret +``` diff --git a/chapters/stack/intro/guides/stack-operations/support/.gitignore b/chapters/stack/intro/guides/stack-operations/support/.gitignore new file mode 100644 index 00000000..8ab582c4 --- /dev/null +++ b/chapters/stack/intro/guides/stack-operations/support/.gitignore @@ -0,0 +1 @@ +stack-operations \ No newline at end of file diff --git a/chapters/stack/intro/guides/stack-operations/support/Makefile b/chapters/stack/intro/guides/stack-operations/support/Makefile new file mode 100644 index 00000000..552ecfad --- /dev/null +++ b/chapters/stack/intro/guides/stack-operations/support/Makefile @@ -0,0 +1,25 @@ +AS = nasm +CC = gcc +RM = rm + +SRCS := $(shell find . -name "*.asm") +OBJS := $(SRCS:.asm=.o) + +UTILSDIR := ../utils/ + +ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)" +CFLAGS ?= -Wall +LDFLAGS ?= -m32 -no-pie + +TARGET_EXEC = stack-operations + +$(TARGET_EXEC): $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ + +$(OBJS): $(SRCS) + $(AS) $(ASFLAGS) $< -o $@ + +.PHONY: clean + +clean: + $(RM) -r *.o $(TARGET_EXEC) diff --git a/chapters/stack/intro/guides/stack-operations/support/stack-operations.asm b/chapters/stack/intro/guides/stack-operations/support/stack-operations.asm new file mode 100644 index 00000000..5911cce8 --- /dev/null +++ b/chapters/stack/intro/guides/stack-operations/support/stack-operations.asm @@ -0,0 +1,59 @@ +%include "printf32.asm" + +section .data + var: dd ? + +section .text + +; esp -> stack pointer +; ebp -> base pointer + +extern printf +global main +main: + push ebp + mov ebp, esp + + push dword 10 ; sub esp, 4; mov [esp], 10; + push dword 11 ; sub esp, 4; mov [esp], 11; + push dword 12 ; sub esp, 4; mov [esp], 12; + push dword 13 ; sub esp, 4; mov [esp], 13; + push dword 14 ; sub esp, 4; mov [esp], 13; + + + pusha ; push all registers on the stack + popa ; pop all registers from the stack + + ; Version 1 + pop eax; ; mov eax, [esp]; add esp, 4 + pop eax; ; mov eax, [esp]; add esp, 4 + pop eax; ; mov eax, [esp]; add esp, 4 + pop eax; ; mov eax, [esp]; add esp, 4 + pop eax; ; mov eax, [esp]; add esp, 4 + + ; Version 2 + ; add esp, 20 ; 4 * number_of_push + + ; Version 3 + ; mov esp, ebp + + ; sub esp <-> add esp -> use to allocate/deallocate memory + + ; Aloc 8 bytes <-> 2 int + ; sub esp, 8 + ; mov [esp], 10 + ; mov [esp + 4], 12 + + ; Push/Pop from global variable + + mov dword [var], 1337 + + push dword [var] + pop dword [var] + + mov eax, [var] + PRINTF32 `VAR: %d\n\x0`, eax + + + leave + ret diff --git a/chapters/stack/intro/guides/stack-operations/utils/printf32.asm b/chapters/stack/intro/guides/stack-operations/utils/printf32.asm new file mode 100644 index 00000000..0617f3d8 --- /dev/null +++ b/chapters/stack/intro/guides/stack-operations/utils/printf32.asm @@ -0,0 +1,24 @@ +; SPDX-License-Identifier: BSD-3-Clause + +;;; macro to use printf with 32bit parameters: +;;; - 1st parameter MUST be an immediate in backquotes `EAX=%d ECX=%x \n\x0` +;;; escape \n and \x0 only work with backquotes +;;; - rest of parameters MUST be 32bit +;;; - gen purpose and flags are preserved +;;; - stack is cleaned +%macro PRINTF32 1-* + pushf + pushad + jmp %%endstr +%%str: db %1 +%%endstr: +%rep %0 - 1 +%rotate -1 + push dword %1 +%endrep + push %%str + call printf + add esp, 4*%0 + popad + popf +%endmacro diff --git a/chapters/stack/intro/media/process_address_space.jpg b/chapters/stack/intro/media/process_address_space.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8f3d59ce12b0b304587275ccc343d52fe6e0f8de GIT binary patch literal 11930 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

J`(6ImY8hq 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 + + +
Base
Base
Top
Top
0xffffffff
0xffffffff
0x00000000
0x00000000
push
push
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/chapters/stack/intro/media/the-stack.svg b/chapters/stack/intro/media/the-stack.svg new file mode 100644 index 00000000..a286c449 --- /dev/null +++ b/chapters/stack/intro/media/the-stack.svg @@ -0,0 +1,4 @@ + + + +
1
1
push
push
1
1
1
1
pop
pop
2
2
2
2
Base
Base
Top
Top
1
1
push
push
2
2
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/chapters/stack/intro/reading/README.md b/chapters/stack/intro/reading/README.md new file mode 100644 index 00000000..9f06c8e9 --- /dev/null +++ b/chapters/stack/intro/reading/README.md @@ -0,0 +1,187 @@ +# 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. + +## Stack data structure - reminder + +> **NOTE:** This is a quick reminder on how the abstract data structure works. +> If you feel like you already understand this, you can skip this part. + +In the world of algorithms and data structure, a "stack" is a data structure used to hold data, mirroring a real-life stack of objects (for example, a stack of books, or a stack of boxes). +This data structure's usefulness comes from optimizing the ease and speed at which elements can be added or removed from the top of the stack. +It forces us to think about how our data is organized relative to the stack's base and top. +The usual operations with the stack are: + +- `push` - add an element to the top of the stack +- `pop` - get the element from the top of the stack **and remove it** +- `peek` or `top` - get the element from the top of the stack **without removing it** + +![An image showing a stack data structure at different stages. The empty stack gains the element labeled "1" after the instruction "push 1" is applied to it. After the instruction "push 2", the stack has two items, element 1 being below element 2. Finally, the "pop" instruction makes the stack lose element 2](../media/the-stack.drawio.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". + +## So, why is it useful? + +In the previous chapters we learned how to work with the basics of assembly. +A pretty big limitation we have imposed on ourselves by using such a low-level language is the small number of values we can work with at a time. +For anything but small programs, having just the 6 registers (`eax`, `ebx`, `ecx`, `edx`, `esi`, `edi`) is usually not enough, and creating global variables for temporary values is not memory efficient and, at some point, we'll struggle to even name them something reasonable! + +You might have also felt the absence of functions. The stack will help us out as it provides a nice place to store: + +- the arguments, +- the values of registers before entering a function so they can be restored on exit, +- and some metadata useful for when we want to exit out of a function. + +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. +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). +> When going over the maximum allocated space, you can receive a Segmentation Fault, and the phenomenon is called a `Stack Overflow`. +> You will have probably received this error when you declare a local array with a very high capacity, or when calling a recursive function which never returns. + +## Stack Operations + +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" + +section .text +global CMAIN +CMAIN: + + mov eax, 7 + mov ebx, 8 + add eax, ebx + push eax ; push the value of the eax register onto the stack + mov eax, 10 ; we can now use the eax register, as its value is saved on the stack + PRINTF32 `%d \n\x0`, eax ; 10 + + pop eax ; retrieve the value of the eax register from the stack + PRINTF32 `%d \n\x0`, eax ; 15 +``` + +1. By directly accessing the memory with the help of a special register in which the top of the stack is held - `esp` also known as the "stack pointer register". + +```assembly +%include "io.asm" + +section .text +global CMAIN +CMAIN: + mov eax, 7 + mov ebx, 8 + add eax, ebx + sub esp, 4 ; reserve 4 bytes on the stack + mov [esp], eax ; move the contents of the eax register to the new address pointed to by esp + mov eax, 10 + PRINTF32 `%d \n\x0`, eax + + mov eax, [esp] ; retrieve the value from the stack + add esp, 4 ; restore the value of the esp register + PRINTF32 `%d \n\x0`, eax +``` + +> **IMPORTANT:** Comment out the instructions `sub esp, 4` and `add esp, 4`. +> What happens? +> Why? +> +> **NOTE:** The stack is used to remember the return address when a function is called. +> **Note that the stack grows from higher addresses to lower addresses.** +> This is why memory allocation on the stack is done using the `sub` instruction, and deallocation is done using the `add` instruction. + +![stack_image](../media/the-stack-growth.drawio.svg) + +Some processors do not have support for stack operations: for example, MIPS processors do not have `push` and `pop` instructions and do not have a special register for the stack pointer. +Thus, if we want to implement stack operations on a MIPS processor, we would do it exactly as in the example above, but we can choose any register to keep track of the stack pointer. + +Therefore, the `push eax` instruction on an x86 processor is equivalent to: + +```assembly +sub esp, 4 +mov [esp], eax +``` + +And the `pop eax` is equivalent to: + +```assembly +mov eax, [esp] +add esp, 4 +``` + +> **IMPORTANT:** We need to be careful with the amount of data allocated on the stack because the size of the stack is limited. +> Overfilling the stack will lead to the well-known error of **stack overflow** (more in the security lab). +> +> **NOTE:** The default stack size on Linux for a 64-bit architecture is 8MiB. + +## Stack in the context of a process's address space + +A process's address space, or more precisely, a process's virtual address space, represents the virtual memory area usable by a process. +Each process has its own address space. +Even in situations where two processes share a memory region, the virtual space is distinct, but it maps to the same physical memory region. + +![stack_image](../media/process_address_space.jpg) + +In the figure above, a typical process's address space is presented. + +The four important zones in a process's address space are the data zone, the code zone, the stack, and the heap. +As can be observed from the figure, the stack and the heap are the zones that can grow. +In fact, these two zones are dynamic and only make sense in the context of a process. +On the other hand, the information in the data and code zones is described in the executable. + +## Tricks and tips + +1. The golden rule of stack usage is: the number of `push`-es should equal the number of `pop`-s in a function. +Given that the stack is used for function calls, it is very important that when a function finishes its execution, the stack pointer should be updated so that it points to the same memory location (of the stack) as it did at the time of entering the function. + +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 +section .text +global CMAIN +CMAIN: + mov eax, 5 + mov ebx, 6 + mov ecx, 7 + + push eax + push ebx + push ecx + + add esp, 12 ; equivalent to using 3 consecutive pop-s + ret +``` + +1. An alternative method is to save the current stack pointer value in a separate register, such as `ebp`, before performing any `push` operations. +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 +section .text +global CMAIN +CMAIN: + + mov ebp, esp ; save current stack pointer value in ebp + + mov eax, 5 + mov ebx, 6 + mov ecx, 7 + + push eax + push ebx + push ecx + + mov esp, ebp ; restore stack pointer value + ret +``` + +> **IMPORTANT:** What is the primary use of the `ebp` register? + +As we can observe, the `ebp` register defines the stack frame for each function. +Similarly to how we can address local variables using the `esp` register, we can do the same with `ebp`. +Additionally, we will see that function parameters are addressed using `ebp`. diff --git a/config.yaml b/config.yaml index 9300ecec..19e00833 100644 --- a/config.yaml +++ b/config.yaml @@ -233,6 +233,29 @@ docusaurus: - Find Substring/: find-substring/ - Mul Arrays/: mul-arrays/ - Courses/: courses/ + - Lab 8 - The Stack: + - Introduction: + path: chapters/stack/intro/ + extra: + - media/ + subsections: + - Reading/: reading/ + - Guides: + path: guides/ + subsections: + - Stack Operations/: stack-operations/ + - Stack Addressing/: stack-addressing/ + - Drills: + path: drills/ + subsections: + - Tasks: + path: tasks/ + subsections: + - Max/: max/ + - Reverse Array/: reverse-array/ + - Stack Addressing/: stack-addressing/ + - Local Var/: local-var/ + - Bonus - GCD/: gcd/ - Lab 11 - Buffer Management. Buffer Overflow: - Introduction to Buffers: path: chapters/memory-security/buffers-intro/