diff --git a/labs/lab-07/guides/stack-addressing/README.md b/labs/lab-07/guides/stack-addressing/README.md index c347a2de4..8e4c8669e 100644 --- a/labs/lab-07/guides/stack-addressing/README.md +++ b/labs/lab-07/guides/stack-addressing/README.md @@ -10,49 +10,46 @@ The `stack_addressing.asm` file demonstrates how data is stored on the stack, an Here's what an usual output for the compiled program would be: ```c -0xff99fba8: 0xf7f46020 -0xff99fba4: 0xa -0xff99fba0: 0xb -0xff99fb9c: 0xc -0xff99fb98: 0xd +0x7fff124f4830: 0x7fff124f48d0 +0x7fff124f4828: 0xa +0x7fff124f4820: 0xb +0x7fff124f4818: 0xc +0x7fff124f4810: 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. +> **Answer:** It is the old RBP 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" +%include "printf64.asm" section .text extern printf global main main: - push ebp - mov ebp, esp + push rbp + mov rbp, rsp - push dword 10 - push dword 11 - push dword 12 - push dword 13 + push qword 10 + push qword 11 + push qword 12 + push qword 13 - mov eax, ebp + mov rax, rbp print_stack: - PRINTF32 `0x\x0` - PRINTF32 `%x\x0`, eax - PRINTF32 `: 0x\x0` - PRINTF32 `%x\n\x0`, [eax] + PRINTF64 `%p: %p\n\x0`, rax, [rax] - sub eax, 4 - cmp eax, esp + sub rax, 8 + cmp rax, rsp jge print_stack - xor eax, eax + xor rax, rax leave ret ``` diff --git a/labs/lab-07/guides/stack-addressing/support/Makefile b/labs/lab-07/guides/stack-addressing/support/Makefile index 4afa1bf60..bf86e0c0d 100644 --- a/labs/lab-07/guides/stack-addressing/support/Makefile +++ b/labs/lab-07/guides/stack-addressing/support/Makefile @@ -7,9 +7,9 @@ OBJS := $(SRCS:.asm=.o) UTILSDIR := ../utils/ -ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)" +ASFLAGS ?= -f elf64 -F dwarf -I "$(UTILSDIR)" CFLAGS ?= -Wall -LDFLAGS ?= -m32 -no-pie +LDFLAGS ?= -m64 -no-pie TARGET_EXEC = stack-addressing diff --git a/labs/lab-07/guides/stack-addressing/support/stack-addressing.asm b/labs/lab-07/guides/stack-addressing/support/stack-addressing.asm index 1c9d2e442..b0c6568ce 100644 --- a/labs/lab-07/guides/stack-addressing/support/stack-addressing.asm +++ b/labs/lab-07/guides/stack-addressing/support/stack-addressing.asm @@ -1,26 +1,26 @@ -%include "printf32.asm" +%include "printf64.asm" section .text extern printf global main main: - push ebp - mov ebp, esp + push rbp + mov rbp, rsp - push dword 10 - push dword 11 - push dword 12 - push dword 13 + push qword 10 + push qword 11 + push qword 12 + push qword 13 - mov eax, ebp + mov rax, rbp print_stack: - PRINTF32 `%p: %p\n\x0`, eax, [eax] + PRINTF64 `%p: %p\n\x0`, rax, qword [rax] - sub eax, 4 - cmp eax, esp + sub rax, 8 + cmp rax, rsp jge print_stack - xor eax, eax + xor rax, rax leave ret diff --git a/labs/lab-07/guides/stack-addressing/utils/printf32.asm b/labs/lab-07/guides/stack-addressing/utils/printf32.asm deleted file mode 100644 index 0617f3d8d..000000000 --- a/labs/lab-07/guides/stack-addressing/utils/printf32.asm +++ /dev/null @@ -1,24 +0,0 @@ -; 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/labs/lab-07/guides/stack-addressing/utils/printf64.asm b/labs/lab-07/guides/stack-addressing/utils/printf64.asm new file mode 100644 index 000000000..358881592 --- /dev/null +++ b/labs/lab-07/guides/stack-addressing/utils/printf64.asm @@ -0,0 +1,73 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; no floating point support +;; all parameters need to be 64bit wide +;; format string int8_t=%hhx int16_t=%hx int32_t=%x int64_t=%lx +;; +%macro PRINTF64 1-* +jmp %%endstr +%%str db %1, 0 +%%endstr: + ;sub rsp, 8 + pushfq + push rax + push rcx + push rdx + push rsi + push rdi + push r8 + push r9 + push r10 + push r11 + + push %%str +%if %0 >= 2 + push %2 +%endif +%if %0 >= 3 + push %3 +%endif +%if %0 >= 4 + push %4 +%endif +%if %0 >= 5 + push %5 +%endif +%if %0 == 6 + push %6 +%endif +%if %0 > 6 + %error "PRINTF64 accepts at most 6 arguments" +%endif +%if %0 == 6 + pop r9 +%endif +%if %0 >= 5 + pop r8 +%endif +%if %0 >= 4 + pop rcx +%endif +%if %0 >= 3 + pop rdx +%endif +%if %0 >= 2 + pop rsi +%endif + pop rdi + xor eax, eax + + call printf + + + pop r11 + pop r10 + pop r9 + pop r8 + pop rdi + pop rsi + pop rdx + pop rcx + pop rax + popfq + ;add rsp, 8 +%endmacro diff --git a/labs/lab-07/guides/stack-operations/README.md b/labs/lab-07/guides/stack-operations/README.md index ce2bc00a3..89433fc51 100644 --- a/labs/lab-07/guides/stack-operations/README.md +++ b/labs/lab-07/guides/stack-operations/README.md @@ -14,61 +14,57 @@ For convenience, here's the contents of the file. To play around with it, download the lab locally. ```assembly -%include "printf32.asm" +%include "printf64.asm" section .data - var: dd ? + var: dq ? section .text -; esp -> stack pointer -; ebp -> base pointer +; rsp -> stack pointer +; rbp -> base pointer extern printf global main main: - push ebp - mov ebp, esp + push rbp + mov rbp, rsp - 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 + push qword 10 ; same as: sub rsp, 8 followed by: mov [rsp], 10 + 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 ; 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 + pop rax ; same as: mov rax, [rsp] followed by: add rsp, 8 + pop rax ; same as: mov rax, [rsp] followed by: add rsp, 8 + pop rax ; same as: mov rax, [rsp] followed by: add rsp, 8 + pop rax ; same as: mov rax, [rsp] followed by: add rsp, 8 + pop rax ; same as: mov rax, [rsp] followed by: add rsp, 8 ; Version 2 - ; add esp, 20 ; 4 * number_of_push + ; add rsp, 40 ; 8 * number_of_push ; Version 3 - ; mov esp, ebp + ; mov rsp, rbp - ; sub esp <-> add esp -> use to allocate/deallocate memory + ; sub rsp <-> add rsp -> use to allocate/deallocate memory - ; Aloc 8 bytes <-> 2 int - ; sub esp, 8 - ; mov [esp], 10 - ; mov [esp + 4], 12 + ; Aloc 16 bytes <-> 2 long + ; sub rsp, 16 + ; mov [rsp], 10 + ; mov [rsp + 8], 12 ; Push/Pop from global variable - mov dword [var], 1337 + mov qword [var], 1337 - push dword [var] - pop dword [var] + push qword [var] + pop qword [var] - mov eax, [var] - PRINTF32 `VAR: %d\n\x0`, eax + mov rax, [var] + PRINTF64 `VAR: %d\n\x0`, rax leave diff --git a/labs/lab-07/guides/stack-operations/support/Makefile b/labs/lab-07/guides/stack-operations/support/Makefile index 552ecfada..cf1ec93b2 100644 --- a/labs/lab-07/guides/stack-operations/support/Makefile +++ b/labs/lab-07/guides/stack-operations/support/Makefile @@ -7,9 +7,9 @@ OBJS := $(SRCS:.asm=.o) UTILSDIR := ../utils/ -ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)" +ASFLAGS ?= -f elf64 -F dwarf -I "$(UTILSDIR)" CFLAGS ?= -Wall -LDFLAGS ?= -m32 -no-pie +LDFLAGS ?= -m64 -no-pie TARGET_EXEC = stack-operations diff --git a/labs/lab-07/guides/stack-operations/support/stack-operations.asm b/labs/lab-07/guides/stack-operations/support/stack-operations.asm index 5911cce8e..308980b27 100644 --- a/labs/lab-07/guides/stack-operations/support/stack-operations.asm +++ b/labs/lab-07/guides/stack-operations/support/stack-operations.asm @@ -1,58 +1,54 @@ -%include "printf32.asm" +%include "printf64.asm" section .data - var: dd ? + var: dq ? section .text -; esp -> stack pointer -; ebp -> base pointer +; rsp -> stack pointer +; rbp -> base pointer extern printf global main main: - push ebp - mov ebp, esp + push rbp + mov rbp, rsp - 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 + push qword 10 ; same as: sub rsp, 8 followed by: mov [rsp], 10 + 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 ; 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 + pop rax ; same as: mov rax, [rsp] followed by: add rsp, 8 + pop rax ; same as: mov rax, [rsp] followed by: add rsp, 8 + pop rax ; same as: mov rax, [rsp] followed by: add rsp, 8 + pop rax ; same as: mov rax, [rsp] followed by: add rsp, 8 + pop rax ; same as: mov rax, [rsp] followed by: add rsp, 8 ; Version 2 - ; add esp, 20 ; 4 * number_of_push + ; add rsp, 40 ; 8 * number_of_push ; Version 3 - ; mov esp, ebp + ; mov rsp, rbp - ; sub esp <-> add esp -> use to allocate/deallocate memory + ; sub rsp <-> add rsp -> use to allocate/deallocate memory - ; Aloc 8 bytes <-> 2 int - ; sub esp, 8 - ; mov [esp], 10 - ; mov [esp + 4], 12 + ; Aloc 16 bytes <-> 2 long + ; sub rsp, 16 + ; mov [rsp], 10 + ; mov [rsp + 8], 12 ; Push/Pop from global variable - mov dword [var], 1337 + mov qword [var], 1337 - push dword [var] - pop dword [var] + push qword [var] + pop qword [var] - mov eax, [var] - PRINTF32 `VAR: %d\n\x0`, eax + mov rax, [var] + PRINTF64 `VAR: %ld\n\x0`, rax leave diff --git a/labs/lab-07/guides/stack-operations/utils/printf32.asm b/labs/lab-07/guides/stack-operations/utils/printf32.asm deleted file mode 100644 index 0617f3d8d..000000000 --- a/labs/lab-07/guides/stack-operations/utils/printf32.asm +++ /dev/null @@ -1,24 +0,0 @@ -; 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/labs/lab-07/guides/stack-operations/utils/printf64.asm b/labs/lab-07/guides/stack-operations/utils/printf64.asm new file mode 100644 index 000000000..358881592 --- /dev/null +++ b/labs/lab-07/guides/stack-operations/utils/printf64.asm @@ -0,0 +1,73 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; no floating point support +;; all parameters need to be 64bit wide +;; format string int8_t=%hhx int16_t=%hx int32_t=%x int64_t=%lx +;; +%macro PRINTF64 1-* +jmp %%endstr +%%str db %1, 0 +%%endstr: + ;sub rsp, 8 + pushfq + push rax + push rcx + push rdx + push rsi + push rdi + push r8 + push r9 + push r10 + push r11 + + push %%str +%if %0 >= 2 + push %2 +%endif +%if %0 >= 3 + push %3 +%endif +%if %0 >= 4 + push %4 +%endif +%if %0 >= 5 + push %5 +%endif +%if %0 == 6 + push %6 +%endif +%if %0 > 6 + %error "PRINTF64 accepts at most 6 arguments" +%endif +%if %0 == 6 + pop r9 +%endif +%if %0 >= 5 + pop r8 +%endif +%if %0 >= 4 + pop rcx +%endif +%if %0 >= 3 + pop rdx +%endif +%if %0 >= 2 + pop rsi +%endif + pop rdi + xor eax, eax + + call printf + + + pop r11 + pop r10 + pop r9 + pop r8 + pop rdi + pop rsi + pop rdx + pop rcx + pop rax + popfq + ;add rsp, 8 +%endmacro diff --git a/labs/lab-07/reading/stack.md b/labs/lab-07/reading/stack.md index 55fd4dd41..e1866bbba 100644 --- a/labs/lab-07/reading/stack.md +++ b/labs/lab-07/reading/stack.md @@ -33,12 +33,13 @@ As the above image suggests, the order in which items are inserted and removed f ## 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! +The x86_64 architecture provides plenty general-purpose registers for us to use in our programs, but sometimes we need to store and reuse multiple values. +Using up all our registers for this purpose could prove to be a waste of resources. +Likewise, 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 arguments (not on the x86 64-bit architecture), - 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. @@ -66,18 +67,18 @@ 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 + 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 - pop eax ; retrieve the value of the eax register from the stack - PRINTF32 `%d \n\x0`, eax ; 15 + pop rax ; retrieve the value of the rax register from the stack + PRINTF64 `%d \n\x0`, rax ; 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". +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". ```assembly %include "io.asm" @@ -85,20 +86,20 @@ CMAIN: 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 + 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 + mov rax, 10 + PRINTF64 `%d \n\x0`, rax + + mov rax, [rsp] ; retrieve the value from the stack + add rsp, 8 ; restore the value of the rsp register + PRINTF64 `%d \n\x0`, rax ``` -> **IMPORTANT:** Comment out the instructions `sub esp, 4` and `add esp, 4`. +> **IMPORTANT:** Comment out the instructions `sub rsp, 4` and `add rsp, 4`. > What happens? > Why? > @@ -111,18 +112,18 @@ CMAIN: 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: +Therefore, the `push rax` instruction on an x86_64 processor is equivalent to: ```assembly -sub esp, 4 -mov [esp], eax +sub rsp, 8 +mov [rsp], rax ``` -And the `pop eax` is equivalent to: +And the `pop rax` is equivalent to: ```assembly -mov eax, [esp] -add esp, 4 +mov rax, [rsp] +add rsp, 8 ``` > **IMPORTANT:** We need to be careful with the amount of data allocated on the stack because the size of the stack is limited. @@ -156,19 +157,19 @@ Given that the stack is used for function calls, it is very important that when section .text global CMAIN CMAIN: - mov eax, 5 - mov ebx, 6 - mov ecx, 7 + mov rax, 5 + mov rbx, 6 + mov rcx, 7 - push eax - push ebx - push ecx + push rax + push rbx + push rcx - add esp, 12 ; equivalent to using 3 consecutive pop-s + add rsp, 24 ; 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. +1. An alternative method is to save the current stack pointer value in a separate register, such as `rbp`, 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 @@ -176,22 +177,22 @@ section .text global CMAIN CMAIN: - mov ebp, esp ; save current stack pointer value in ebp + mov rbp, rsp ; save current stack pointer value in rbp - mov eax, 5 - mov ebx, 6 - mov ecx, 7 + mov rax, 5 + mov rbx, 6 + mov rcx, 7 - push eax - push ebx - push ecx + push rax + push rbx + push rcx - mov esp, ebp ; restore stack pointer value + mov rsp, rbp ; restore stack pointer value ret ``` -> **IMPORTANT:** What is the primary use of the `ebp` register? +> **IMPORTANT:** What is the primary use of the `rbp` 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`. +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`. diff --git a/labs/lab-07/tasks/gcd/README.md b/labs/lab-07/tasks/gcd/README.md index f2791e308..c77262cd2 100644 --- a/labs/lab-07/tasks/gcd/README.md +++ b/labs/lab-07/tasks/gcd/README.md @@ -6,7 +6,7 @@ parent: Lab 7 - The Stack # Task: 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. +The code calculates the greatest common divisor (GCD) of two numbers given as parameters using the `rax` and `rdx` 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: diff --git a/labs/lab-07/tasks/gcd/solution/gcd.asm b/labs/lab-07/tasks/gcd/solution/gcd.asm index 77d733242..e5aa84f64 100644 --- a/labs/lab-07/tasks/gcd/solution/gcd.asm +++ b/labs/lab-07/tasks/gcd/solution/gcd.asm @@ -1,45 +1,45 @@ ; SPDX-License-Identifier: BSD-3-Clause -%include "../utils/printf32.asm" +%include "../utils/printf64.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 + ; Input values (rax, rdx) : the 2 numbers to compute the gcd for. + mov rax, 49 + mov rdx, 28 - push eax - push edx + push rax + push rdx gcd: - neg eax + neg rax je gcd_end swap_values: - neg eax - push eax - push edx - pop eax - pop edx + neg rax + push rax + push rdx + pop rax + pop rdx subtract_values: - sub eax,edx + sub rax,rdx jg subtract_values jne swap_values gcd_end: - add eax,edx + add rax,rdx jne print - inc eax + inc rax print: - pop edx - pop ebx + pop rdx + pop rbx - PRINTF32 `gcd(%d, %d) = %d\n\x0`, ebx, edx, eax ; eax = greatest common divisor + PRINTF64 `gcd(%ld, %ld) = %ld\n\x0`, rbx, rdx, rax ; rax = greatest common divisor - xor eax, eax + xor rax, rax ret diff --git a/labs/lab-07/tasks/gcd/support/Makefile b/labs/lab-07/tasks/gcd/support/Makefile index 2e9237490..947975190 100644 --- a/labs/lab-07/tasks/gcd/support/Makefile +++ b/labs/lab-07/tasks/gcd/support/Makefile @@ -7,9 +7,9 @@ OBJS := $(SRCS:.asm=.o) UTILSDIR := ../utils/ -ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)" +ASFLAGS ?= -f elf64 -F dwarf -I "$(UTILSDIR)" CFLAGS ?= -Wall -LDFLAGS ?= -m32 -no-pie +LDFLAGS ?= -m64 -no-pie TARGET_EXEC = gcd diff --git a/labs/lab-07/tasks/gcd/support/gcd.asm b/labs/lab-07/tasks/gcd/support/gcd.asm index 6a3331b70..5fe2c073a 100644 --- a/labs/lab-07/tasks/gcd/support/gcd.asm +++ b/labs/lab-07/tasks/gcd/support/gcd.asm @@ -1,44 +1,44 @@ -%include "printf32.asm" +%include "printf64.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 + ; input values (rax, rdx): the 2 numbers to compute the gcd for + mov rax, 49 + mov rdx, 28 - push eax - push edx + push rax + push rdx gcd: - neg eax + neg rax je gcd_end swap_values: - neg eax - push eax - push edx - pop eax - pop edx + neg rax + push rax + push rdx + pop rax + pop rdx subtract_values: - sub eax,edx + sub rax,rdx jg subtract_values jne swap_values gcd_end: - add eax,edx + add rax,rdx jne print - inc eax + inc rax 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 + ; TODO 2: print the result in the form of: "gdc(rax, rdx)=7" with PRINTF64 macro + ; output value in rax - xor eax, eax + xor rax, rax ret diff --git a/labs/lab-07/tasks/gcd/utils/printf32.asm b/labs/lab-07/tasks/gcd/utils/printf32.asm deleted file mode 100644 index 0617f3d8d..000000000 --- a/labs/lab-07/tasks/gcd/utils/printf32.asm +++ /dev/null @@ -1,24 +0,0 @@ -; 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/labs/lab-07/tasks/gcd/utils/printf64.asm b/labs/lab-07/tasks/gcd/utils/printf64.asm new file mode 100644 index 000000000..358881592 --- /dev/null +++ b/labs/lab-07/tasks/gcd/utils/printf64.asm @@ -0,0 +1,73 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; no floating point support +;; all parameters need to be 64bit wide +;; format string int8_t=%hhx int16_t=%hx int32_t=%x int64_t=%lx +;; +%macro PRINTF64 1-* +jmp %%endstr +%%str db %1, 0 +%%endstr: + ;sub rsp, 8 + pushfq + push rax + push rcx + push rdx + push rsi + push rdi + push r8 + push r9 + push r10 + push r11 + + push %%str +%if %0 >= 2 + push %2 +%endif +%if %0 >= 3 + push %3 +%endif +%if %0 >= 4 + push %4 +%endif +%if %0 >= 5 + push %5 +%endif +%if %0 == 6 + push %6 +%endif +%if %0 > 6 + %error "PRINTF64 accepts at most 6 arguments" +%endif +%if %0 == 6 + pop r9 +%endif +%if %0 >= 5 + pop r8 +%endif +%if %0 >= 4 + pop rcx +%endif +%if %0 >= 3 + pop rdx +%endif +%if %0 >= 2 + pop rsi +%endif + pop rdi + xor eax, eax + + call printf + + + pop r11 + pop r10 + pop r9 + pop r8 + pop rdi + pop rsi + pop rdx + pop rcx + pop rax + popfq + ;add rsp, 8 +%endmacro diff --git a/labs/lab-07/tasks/local-var/solution/local-var.asm b/labs/lab-07/tasks/local-var/solution/local-var.asm index 4a7187730..0ce7c6d52 100644 --- a/labs/lab-07/tasks/local-var/solution/local-var.asm +++ b/labs/lab-07/tasks/local-var/solution/local-var.asm @@ -1,4 +1,4 @@ -%include "../utils/printf32.asm" +%include "../utils/printf64.asm" section .data @@ -16,91 +16,91 @@ extern printf global main main: - mov ebp, esp - sub esp, 4 * ARRAY_1_LEN - mov eax, esp - mov edx, 0 + mov rbp, rsp + sub rsp, 4 * ARRAY_1_LEN + mov rax, rsp + mov rdx, 0 array_1_on_stack: - mov ecx, [array_1 + 4 * edx] - mov [eax], ecx - inc edx - add eax, 4 - cmp edx, ARRAY_1_LEN + mov ecx, [array_1 + 4 * rdx] + mov [rax], ecx + inc rdx + add rax, 4 + cmp rdx, ARRAY_1_LEN jl array_1_on_stack - mov eax, esp + mov rax, rsp - sub esp, 4 * ARRAY_2_LEN - mov ebx, esp - mov edx, 0 + sub rsp, 4 * ARRAY_2_LEN + mov rbx, rsp + mov rdx, 0 array_2_on_stack: - mov ecx, [array_2 + 4 * edx] - mov [ebx], ecx - inc edx - add ebx, 4 - cmp edx, ARRAY_2_LEN + mov ecx, [array_2 + 4 * rdx] + mov [rbx], ecx + inc rdx + add rbx, 4 + cmp rdx, ARRAY_2_LEN jl array_2_on_stack - mov ebx, esp - sub esp, 4 * ARRAY_OUTPUT_LEN - mov ecx, esp + mov rbx, rsp + sub rsp, 4 * ARRAY_OUTPUT_LEN + mov rcx, rsp merge_arrays: - mov edx, [eax] - cmp edx, [ebx] + mov edx, [rax] + cmp edx, [rbx] jg array_2_lower array_1_lower: - mov [ecx], edx ; The element from array_1 is lower - add eax, 4 - add ecx, 4 + mov [rcx], edx ; The element from array_1 is lower + add rax, 4 + add rcx, 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 + mov edx, [rbx] + mov [rcx], edx ; The elements of the array_2 is lower + add rbx, 4 + add rcx, 4 verify_array_end: - mov edx, ebp - cmp eax, edx + mov rdx, rbp + cmp rax, rdx jge copy_array_2 - sub edx, 4 * ARRAY_1_LEN - cmp ebx, ebp + sub rdx, 4 * ARRAY_1_LEN + cmp rbx, rbp 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 + xor rdx, rdx + mov eax, [rax] + mov [rcx], edx + add rcx, 4 + add rax, 4 + cmp rax, rbp 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 + xor rdx, rdx + mov edx, [rbx] + mov [rcx], edx + add rcx, 4 + add rbx, 4 + mov rdx, rbp + sub rdx, 4 * ARRAY_1_LEN + cmp rbx, rdx jb copy_array_2 print_array: - PRINTF32 `Array merged:\n\x0` - xor eax, eax - xor ecx, ecx + PRINTF64 `Array merged:\n\x0` + xor rax, rax + xor rcx, rcx print: - mov eax, [esp] - PRINTF32 `%d \x0`, eax - add esp, 4 - inc ecx - cmp ecx, ARRAY_OUTPUT_LEN + mov eax, [rsp] + PRINTF64 `%d \x0`, rax + add rsp, 4 + inc rcx + cmp rcx, ARRAY_OUTPUT_LEN jb print - PRINTF32 `\n\x0` - xor eax, eax - mov esp, ebp + PRINTF64 `\n\x0` + xor rax, rax + mov rsp, rbp ret \ No newline at end of file diff --git a/labs/lab-07/tasks/local-var/support/Makefile b/labs/lab-07/tasks/local-var/support/Makefile index 6c5d5d988..f2eda186d 100644 --- a/labs/lab-07/tasks/local-var/support/Makefile +++ b/labs/lab-07/tasks/local-var/support/Makefile @@ -7,9 +7,9 @@ OBJS := $(SRCS:.asm=.o) UTILSDIR := ../utils/ -ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)" +ASFLAGS ?= -f elf64 -F dwarf -I "$(UTILSDIR)" CFLAGS ?= -Wall -LDFLAGS ?= -m32 -no-pie +LDFLAGS ?= -m64 -no-pie TARGET_EXEC = local-var diff --git a/labs/lab-07/tasks/local-var/support/local-var.asm b/labs/lab-07/tasks/local-var/support/local-var.asm index 397230808..f23808c02 100644 --- a/labs/lab-07/tasks/local-var/support/local-var.asm +++ b/labs/lab-07/tasks/local-var/support/local-var.asm @@ -1,4 +1,4 @@ -%include "printf32.asm" +%include "printf64.asm" %define ARRAY_1_LEN 5 %define ARRAY_2_LEN 7 @@ -16,58 +16,58 @@ 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 + mov rax, 0 ; counter used for array_1 + mov rbx, 0 ; counter used for array_2 + mov rcx, 0 ; counter used for the output array merge_arrays: - mov edx, [array_1 + 4 * eax] - cmp edx, [array_2 + 4 * ebx] + mov edx, [array_1 + 4 * rax] + cmp edx, [array_2 + 4 * rbx] jg array_2_lower array_1_lower: - mov [array_output + 4 * ecx], edx - inc eax - inc ecx + mov [array_output + 4 * rcx], edx + inc rax + inc rcx jmp verify_array_end array_2_lower: - mov edx, [array_2 + 4 * ebx] - mov [array_output + 4 * ecx], edx - inc ecx - inc ebx + mov edx, [array_2 + 4 * rbx] + mov [array_output + 4 * rcx], edx + inc rcx + inc rbx verify_array_end: - cmp eax, ARRAY_1_LEN + cmp rax, ARRAY_1_LEN jge copy_array_2 - cmp ebx, ARRAY_2_LEN + cmp rbx, 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 + mov edx, [array_1 + 4 * rax] + mov [array_output + 4 * rcx], edx + inc rcx + inc rax + cmp rax, 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 + mov edx, [array_2 + 4 * rbx] + mov [array_output + 4 * rcx], edx + inc rcx + inc rbx + cmp rbx, ARRAY_2_LEN jb copy_array_2 print_array: - PRINTF32 `Array merged:\n\x0` - mov ecx, 0 + PRINTF64 `Array merged:\n\x0` + mov rcx, 0 print: - mov eax, [array_output + 4 * ecx] - PRINTF32 `%d \x0`, eax - inc ecx - cmp ecx, ARRAY_OUTPUT_LEN + mov eax, [array_output + 4 * rcx] + PRINTF64 `%d \x0`, rax + inc rcx + cmp rcx, ARRAY_OUTPUT_LEN jb print - PRINTF32 `\n\x0` - xor eax, eax + PRINTF64 `\n\x0` + xor rax, rax ret \ No newline at end of file diff --git a/labs/lab-07/tasks/local-var/tests/test.sh b/labs/lab-07/tasks/local-var/tests/test.sh index b33baeae4..d248c8e90 100755 --- a/labs/lab-07/tasks/local-var/tests/test.sh +++ b/labs/lab-07/tasks/local-var/tests/test.sh @@ -20,8 +20,8 @@ test_local_var() ./"$binary" > "$out" 2>&1 ./"$ref_binary" > "$ref" 2>&1 - if grep -q "sub esp, .*" "${binary}.asm" && - grep -q "mov .*, [esp]" "${binary}.asm"; then + if grep -q "sub rsp, .*" "${binary}.asm" && + grep -q "mov .*, [rsp]" "${binary}.asm"; then if diff -q "$out" "$ref"; then exit 0 else diff --git a/labs/lab-07/tasks/local-var/utils/printf32.asm b/labs/lab-07/tasks/local-var/utils/printf32.asm deleted file mode 100644 index 0617f3d8d..000000000 --- a/labs/lab-07/tasks/local-var/utils/printf32.asm +++ /dev/null @@ -1,24 +0,0 @@ -; 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/labs/lab-07/tasks/local-var/utils/printf64.asm b/labs/lab-07/tasks/local-var/utils/printf64.asm new file mode 100644 index 000000000..358881592 --- /dev/null +++ b/labs/lab-07/tasks/local-var/utils/printf64.asm @@ -0,0 +1,73 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; no floating point support +;; all parameters need to be 64bit wide +;; format string int8_t=%hhx int16_t=%hx int32_t=%x int64_t=%lx +;; +%macro PRINTF64 1-* +jmp %%endstr +%%str db %1, 0 +%%endstr: + ;sub rsp, 8 + pushfq + push rax + push rcx + push rdx + push rsi + push rdi + push r8 + push r9 + push r10 + push r11 + + push %%str +%if %0 >= 2 + push %2 +%endif +%if %0 >= 3 + push %3 +%endif +%if %0 >= 4 + push %4 +%endif +%if %0 >= 5 + push %5 +%endif +%if %0 == 6 + push %6 +%endif +%if %0 > 6 + %error "PRINTF64 accepts at most 6 arguments" +%endif +%if %0 == 6 + pop r9 +%endif +%if %0 >= 5 + pop r8 +%endif +%if %0 >= 4 + pop rcx +%endif +%if %0 >= 3 + pop rdx +%endif +%if %0 >= 2 + pop rsi +%endif + pop rdi + xor eax, eax + + call printf + + + pop r11 + pop r10 + pop r9 + pop r8 + pop rdi + pop rsi + pop rdx + pop rcx + pop rax + popfq + ;add rsp, 8 +%endmacro diff --git a/labs/lab-07/tasks/max/README.md b/labs/lab-07/tasks/max/README.md index 6d6039bf1..5aac52ab2 100644 --- a/labs/lab-07/tasks/max/README.md +++ b/labs/lab-07/tasks/max/README.md @@ -5,7 +5,7 @@ parent: Lab 7 - The Stack # Task: Max -Calculate the maximum between two numbers in two registers (`eax` and `ebx`) using a comparison instruction, a jump instruction, and push/pop instructions. +Calculate the maximum between two numbers in two registers (`rax` and `rbx`) using a comparison instruction, a jump instruction, and push/pop instructions. > **TIP:** Consider how you can swap two registers using the stack. diff --git a/labs/lab-07/tasks/max/solution/max.asm b/labs/lab-07/tasks/max/solution/max.asm index 593b1601d..b6bbf89c1 100644 --- a/labs/lab-07/tasks/max/solution/max.asm +++ b/labs/lab-07/tasks/max/solution/max.asm @@ -1,4 +1,4 @@ -%include "../utils/printf32.asm" +%include "../utils/printf64.asm" section .text @@ -6,17 +6,17 @@ extern printf global main main: ; Numbers are placed in these two registers. - mov eax, 1 - mov ebx, 4 + mov rax, 1 + mov rbx, 4 - cmp eax, ebx + cmp rax, rbx ja print_max - push eax - push ebx - pop eax - pop ebx + push rax + push rbx + pop rax + pop rbx print_max: - PRINTF32 `Max value is: %d\n\x0`, eax + PRINTF64 `Max value is: %d\n\x0`, rax ret \ No newline at end of file diff --git a/labs/lab-07/tasks/max/support/Makefile b/labs/lab-07/tasks/max/support/Makefile index 2227e8f5a..36b067a1d 100644 --- a/labs/lab-07/tasks/max/support/Makefile +++ b/labs/lab-07/tasks/max/support/Makefile @@ -7,9 +7,9 @@ OBJS := $(SRCS:.asm=.o) UTILSDIR := ../utils/ -ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)" +ASFLAGS ?= -f elf64 -F dwarf -I "$(UTILSDIR)" CFLAGS ?= -Wall -LDFLAGS ?= -m32 -no-pie +LDFLAGS ?= -m64 -no-pie TARGET_EXEC = max diff --git a/labs/lab-07/tasks/max/support/max.asm b/labs/lab-07/tasks/max/support/max.asm index 04427d919..17977c186 100644 --- a/labs/lab-07/tasks/max/support/max.asm +++ b/labs/lab-07/tasks/max/support/max.asm @@ -1,4 +1,4 @@ -%include "printf32.asm" +%include "printf64.asm" section .text @@ -6,11 +6,11 @@ extern printf global main main: ; numbers are placed in these two registers - mov eax, 1 - mov ebx, 4 + mov rax, 1 + mov rbx, 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 + PRINTF64 `Max value is: %ld\n\x0`, rax ; print maximum value ret diff --git a/labs/lab-07/tasks/max/tests/test.sh b/labs/lab-07/tasks/max/tests/test.sh index 4c6b2a091..589f725ee 100755 --- a/labs/lab-07/tasks/max/tests/test.sh +++ b/labs/lab-07/tasks/max/tests/test.sh @@ -20,7 +20,7 @@ test_max() ./"$binary" > "$out" 2>&1 ./"$ref_binary" > "$ref" 2>&1 - if grep -q -E 'cmp eax, ebx|cmp ebx, eax' "${binary}.asm" && + if grep -q -E 'cmp rax, rbx|cmp rbx, rax' "${binary}.asm" && grep -q -E 'jl|jg|jb|ja|jle|jge|jbe|jae' "${binary}.asm" && grep -q -E 'push' "${binary}.asm" && grep -q -E 'pop' "${binary}.asm"; then diff --git a/labs/lab-07/tasks/max/utils/printf32.asm b/labs/lab-07/tasks/max/utils/printf32.asm deleted file mode 100644 index 0617f3d8d..000000000 --- a/labs/lab-07/tasks/max/utils/printf32.asm +++ /dev/null @@ -1,24 +0,0 @@ -; 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/labs/lab-07/tasks/max/utils/printf64.asm b/labs/lab-07/tasks/max/utils/printf64.asm new file mode 100644 index 000000000..358881592 --- /dev/null +++ b/labs/lab-07/tasks/max/utils/printf64.asm @@ -0,0 +1,73 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; no floating point support +;; all parameters need to be 64bit wide +;; format string int8_t=%hhx int16_t=%hx int32_t=%x int64_t=%lx +;; +%macro PRINTF64 1-* +jmp %%endstr +%%str db %1, 0 +%%endstr: + ;sub rsp, 8 + pushfq + push rax + push rcx + push rdx + push rsi + push rdi + push r8 + push r9 + push r10 + push r11 + + push %%str +%if %0 >= 2 + push %2 +%endif +%if %0 >= 3 + push %3 +%endif +%if %0 >= 4 + push %4 +%endif +%if %0 >= 5 + push %5 +%endif +%if %0 == 6 + push %6 +%endif +%if %0 > 6 + %error "PRINTF64 accepts at most 6 arguments" +%endif +%if %0 == 6 + pop r9 +%endif +%if %0 >= 5 + pop r8 +%endif +%if %0 >= 4 + pop rcx +%endif +%if %0 >= 3 + pop rdx +%endif +%if %0 >= 2 + pop rsi +%endif + pop rdi + xor eax, eax + + call printf + + + pop r11 + pop r10 + pop r9 + pop r8 + pop rdi + pop rsi + pop rdx + pop rcx + pop rax + popfq + ;add rsp, 8 +%endmacro diff --git a/labs/lab-07/tasks/reverse-array/solution/reverse-array.asm b/labs/lab-07/tasks/reverse-array/solution/reverse-array.asm index c1607b507..e0c4b7416 100644 --- a/labs/lab-07/tasks/reverse-array/solution/reverse-array.asm +++ b/labs/lab-07/tasks/reverse-array/solution/reverse-array.asm @@ -1,11 +1,11 @@ -%include "../utils/printf32.asm" +%include "../utils/printf64.asm" %define ARRAY_LEN 7 section .data -input dd 122, 184, 199, 242, 263, 845, 911 -output times ARRAY_LEN dd 0 +input dq 122, 184, 199, 242, 263, 845, 911 +output times ARRAY_LEN dq 0 section .text @@ -14,25 +14,25 @@ global main main: push ARRAY_LEN - pop ecx + pop rcx push_elem: - push dword [input + 4 * (ecx - 1)] + push qword [input + 8 * (rcx - 1)] loop push_elem push ARRAY_LEN - pop ecx + pop rcx pop_elem: - pop dword [output + 4 * (ecx - 1)] + pop qword [output + 8 * (rcx - 1)] loop pop_elem - PRINTF32 `Reversed array: \n\x0` - xor ecx, ecx + PRINTF64 `Reversed array: \n\x0` + xor rcx, rcx print_array: - mov edx, [output + 4 * ecx] - PRINTF32 `%d\n\x0`, edx - inc ecx - cmp ecx, ARRAY_LEN + mov rdx, [output + 8 * rcx] + PRINTF64 `%ld\n\x0`, rdx + inc rcx + cmp rcx, ARRAY_LEN jb print_array - xor eax, eax + xor rax, rax ret diff --git a/labs/lab-07/tasks/reverse-array/support/Makefile b/labs/lab-07/tasks/reverse-array/support/Makefile index b15f88097..bd860e714 100644 --- a/labs/lab-07/tasks/reverse-array/support/Makefile +++ b/labs/lab-07/tasks/reverse-array/support/Makefile @@ -7,9 +7,9 @@ OBJS := $(SRCS:.asm=.o) UTILSDIR := ../utils/ -ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)" +ASFLAGS ?= -f elf64 -F dwarf -I "$(UTILSDIR)" CFLAGS ?= -Wall -LDFLAGS ?= -m32 -no-pie +LDFLAGS ?= -m64 -no-pie TARGET_EXEC = reverse-array diff --git a/labs/lab-07/tasks/reverse-array/support/reverse-array.asm b/labs/lab-07/tasks/reverse-array/support/reverse-array.asm index 8319189b9..2758227d0 100644 --- a/labs/lab-07/tasks/reverse-array/support/reverse-array.asm +++ b/labs/lab-07/tasks/reverse-array/support/reverse-array.asm @@ -1,11 +1,11 @@ -%include "printf32.asm" +%include "printf64.asm" %define ARRAY_LEN 7 section .data -input dd 122, 184, 199, 242, 263, 845, 911 -output times ARRAY_LEN dd 0 +input dq 122, 184, 199, 242, 263, 845, 911 +output times ARRAY_LEN dq 0 section .text @@ -16,14 +16,14 @@ 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 + PRINTF64 `Reversed array: \n\x0` + xor rcx, rcx print_array: - mov edx, [output + 4 * ecx] - PRINTF32 `%d\n\x0`, edx - inc ecx - cmp ecx, ARRAY_LEN + mov rdx, [output + 8 * rcx] + PRINTF64 `%ld\n\x0`, rdx + inc rcx + cmp rcx, ARRAY_LEN jb print_array - xor eax, eax + xor rax, rax ret diff --git a/labs/lab-07/tasks/reverse-array/utils/printf32.asm b/labs/lab-07/tasks/reverse-array/utils/printf32.asm deleted file mode 100644 index 0617f3d8d..000000000 --- a/labs/lab-07/tasks/reverse-array/utils/printf32.asm +++ /dev/null @@ -1,24 +0,0 @@ -; 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/labs/lab-07/tasks/reverse-array/utils/printf64.asm b/labs/lab-07/tasks/reverse-array/utils/printf64.asm new file mode 100644 index 000000000..358881592 --- /dev/null +++ b/labs/lab-07/tasks/reverse-array/utils/printf64.asm @@ -0,0 +1,73 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; no floating point support +;; all parameters need to be 64bit wide +;; format string int8_t=%hhx int16_t=%hx int32_t=%x int64_t=%lx +;; +%macro PRINTF64 1-* +jmp %%endstr +%%str db %1, 0 +%%endstr: + ;sub rsp, 8 + pushfq + push rax + push rcx + push rdx + push rsi + push rdi + push r8 + push r9 + push r10 + push r11 + + push %%str +%if %0 >= 2 + push %2 +%endif +%if %0 >= 3 + push %3 +%endif +%if %0 >= 4 + push %4 +%endif +%if %0 >= 5 + push %5 +%endif +%if %0 == 6 + push %6 +%endif +%if %0 > 6 + %error "PRINTF64 accepts at most 6 arguments" +%endif +%if %0 == 6 + pop r9 +%endif +%if %0 >= 5 + pop r8 +%endif +%if %0 >= 4 + pop rcx +%endif +%if %0 >= 3 + pop rdx +%endif +%if %0 >= 2 + pop rsi +%endif + pop rdi + xor eax, eax + + call printf + + + pop r11 + pop r10 + pop r9 + pop r8 + pop rdi + pop rsi + pop rdx + pop rcx + pop rax + popfq + ;add rsp, 8 +%endmacro diff --git a/labs/lab-07/tasks/stack-addressing/README.md b/labs/lab-07/tasks/stack-addressing/README.md index 1781a4e6d..0a39a83c6 100644 --- a/labs/lab-07/tasks/stack-addressing/README.md +++ b/labs/lab-07/tasks/stack-addressing/README.md @@ -11,7 +11,7 @@ The `stack-addressing.asm` program in the lab's archive allocates and initialize - a string "Bob has corn". 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 high addresses to low addresses) dword by dword. +1. Print the addresses and values on the stack in the interval `[rsp, rbp]` (from high addresses to low addresses) qword by qword. 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. @@ -20,18 +20,18 @@ Think about where you should start displaying and what size each element has. 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 ->Bob has corn ->0xffe804cc: 0xf7d91519 ->0xffe804c8: 0x5 ->0xffe804c4: 0x4 ->0xffe804c0: 0x3 ->0xffe804bc: 0x2 ->0xffe804b8: 0x1 ->0xffe804b4: 0x0 ->0xffe804b0: 0x6e726f63 ->0xffe804ac: 0x20736168 ->0xffe804a8: 0x20626f42 ->Bob has corn +>Anthony is very handsome +>0x10dcdff8: 0x6182a1ca +>0x10dcdff0: 0x5 +>0x10dcdfe8: 0x4 +>0x10dcdfe0: 0x3 +>0x10dcdfd8: 0x2 +>0x10dcdfd0: 0x1 +>0x10dcdfc8: 0x0 +>0x10dcdfc0: 0x646e6168 +>0x10dcdfb8: 0x76207369 +>0x10dcdfb0: 0x68746e41 +>Anthony is very handsome >1 2 3 4 5 >``` > diff --git a/labs/lab-07/tasks/stack-addressing/solution/stack-addressing.asm b/labs/lab-07/tasks/stack-addressing/solution/stack-addressing.asm index 7c175b746..1a1eb3c61 100644 --- a/labs/lab-07/tasks/stack-addressing/solution/stack-addressing.asm +++ b/labs/lab-07/tasks/stack-addressing/solution/stack-addressing.asm @@ -1,4 +1,4 @@ -%include "../utils/printf32.asm" +%include "../utils/printf64.asm" %define NUM 5 section .text @@ -6,54 +6,57 @@ section .text extern printf global main main: - mov ebp, esp - mov ecx, NUM + mov rbp, rsp + mov rcx, NUM push_nums: - sub esp, 4 - mov dword [esp], ecx + sub rsp, 8 + mov qword [rsp], rcx loop push_nums - sub esp, 4 - mov dword [esp], 0 + sub rsp, 8 + mov qword [rsp], 0 - sub esp, 4 - mov dword [esp], "corn" + sub rsp, 8 + mov rax, "handsome" + mov qword [rsp], rax - sub esp, 4 - mov dword [esp], "has " + sub rsp, 8 + mov rax, "is very " + mov qword [rsp], rax - sub esp, 4 - mov dword [esp], "Bob " - lea esi, [esp] - PRINTF32 `%s\n\x0`, esi + sub rsp, 8 + mov rax, "Anthony " + mov qword [rsp], rax + lea rsi, [rsp] + PRINTF64 `%s\n\x0`, rsi ; Print the stack in "address: value" format. - mov eax, ebp + mov rax, rbp print_stack: - PRINTF32 `0x%x: 0x%x\n\x0`, eax, [eax] + PRINTF64 `0x%x: 0x%x\n\x0`, rax, qword [rax] - sub eax, 4 - cmp eax, esp + sub rax, 8 + cmp rax, rsp jge print_stack ; Print the string. - lea esi, [esp] - PRINTF32 `%s\n\x0`, esi + lea rsi, [rsp] + PRINTF64 `%s\n\x0`, rsi ; Print the array. - add esp, 16 - mov eax, esp + add rsp, 32 + mov rax, rsp print_array: - PRINTF32 `%d \x0`, [eax] + PRINTF64 `%d \x0`, qword [rax] - add eax, 4 - cmp eax, ebp + add rax, 8 + cmp rax, rbp jl print_array - PRINTF32 `\n\x0` + PRINTF64 `\n\x0` - ; Restore the previous value of the EBP (Base Pointer). - mov esp, ebp + ; Restore the previous value of the RBP (Base Pointer). + mov rsp, rbp ; Exit without errors. - xor eax, eax + xor rax, rax ret diff --git a/labs/lab-07/tasks/stack-addressing/support/Makefile b/labs/lab-07/tasks/stack-addressing/support/Makefile index a78256d7b..b25a20e81 100644 --- a/labs/lab-07/tasks/stack-addressing/support/Makefile +++ b/labs/lab-07/tasks/stack-addressing/support/Makefile @@ -7,9 +7,9 @@ OBJS := $(SRCS:.asm=.o) UTILSDIR := ../utils/ -ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)" +ASFLAGS ?= -f elf64 -F dwarf -I "$(UTILSDIR)" CFLAGS ?= -Wall -LDFLAGS ?= -m32 -no-pie +LDFLAGS ?= -m64 -no-pie TARGET_EXEC = stack-addressing diff --git a/labs/lab-07/tasks/stack-addressing/support/stack-addressing.asm b/labs/lab-07/tasks/stack-addressing/support/stack-addressing.asm index 2f146d7cb..6cf0ec784 100644 --- a/labs/lab-07/tasks/stack-addressing/support/stack-addressing.asm +++ b/labs/lab-07/tasks/stack-addressing/support/stack-addressing.asm @@ -1,4 +1,4 @@ -%include "printf32.asm" +%include "printf64.asm" %define NUM 5 @@ -7,32 +7,35 @@ section .text extern printf global main main: - mov ebp, esp + mov rbp, rsp - ; TODO 1: replace every "push" instruction by an equivalent sequence of commands (use direct addressing of memory. Hint: esp) - mov ecx, NUM + ; TODO 1: replace every "push" instruction by an equivalent sequence of commands (use direct addressing of memory. Hint: rsp) + mov rcx, NUM push_nums: - push ecx + push rcx loop push_nums push 0 - push "corn" - push "has " - push "Bob " + mov rax, "handsome" + push rax + mov rax, "is very " + push rax + mov rax, "Anthony " + push rax - lea esi, [esp] - PRINTF32 `%s\n\x0`, esi + lea rsi, [rsp] + PRINTF64 `%s\n\x0`, rsi - ; TODO 2: print the stack in "address: value" format in the range of [ESP:EBP] - ; use PRINTF32 macro - see format above + ; TODO 2: print the stack in "address: value" format in the range of [RSP:RBP] + ; use PRINTF64 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 + ; restore the previous value of the rbp (Base Pointer) + mov rsp, rbp ; exit without errors - xor eax, eax + xor rax, rax ret diff --git a/labs/lab-07/tasks/stack-addressing/tests/test.sh b/labs/lab-07/tasks/stack-addressing/tests/test.sh index 3e14df43f..820844911 100755 --- a/labs/lab-07/tasks/stack-addressing/tests/test.sh +++ b/labs/lab-07/tasks/stack-addressing/tests/test.sh @@ -23,7 +23,7 @@ test_stack_addressing() awk ' BEGIN { expected_addr = "" } - /^Bob has corn$/ { + /^Anthony is very handsome$/ { if (NR != 1 && NR != 12) exit 1 next } @@ -31,7 +31,7 @@ test_stack_addressing() NR == 2 { if (!match($0, /^0x[0-9a-fA-F]+: 0x[0-9a-fA-F]+$/)) exit 1 split($0, parts, ": ") - expected_addr = strtonum(parts[1]) - 4 + expected_addr = strtonum(parts[1]) - 8 next } @@ -42,7 +42,7 @@ test_stack_addressing() if (current_addr != expected_addr) exit 1 - expected_addr -= 4 + expected_addr -= 8 next } diff --git a/labs/lab-07/tasks/stack-addressing/utils/printf32.asm b/labs/lab-07/tasks/stack-addressing/utils/printf32.asm deleted file mode 100644 index 0617f3d8d..000000000 --- a/labs/lab-07/tasks/stack-addressing/utils/printf32.asm +++ /dev/null @@ -1,24 +0,0 @@ -; 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/labs/lab-07/tasks/stack-addressing/utils/printf64.asm b/labs/lab-07/tasks/stack-addressing/utils/printf64.asm new file mode 100644 index 000000000..358881592 --- /dev/null +++ b/labs/lab-07/tasks/stack-addressing/utils/printf64.asm @@ -0,0 +1,73 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; no floating point support +;; all parameters need to be 64bit wide +;; format string int8_t=%hhx int16_t=%hx int32_t=%x int64_t=%lx +;; +%macro PRINTF64 1-* +jmp %%endstr +%%str db %1, 0 +%%endstr: + ;sub rsp, 8 + pushfq + push rax + push rcx + push rdx + push rsi + push rdi + push r8 + push r9 + push r10 + push r11 + + push %%str +%if %0 >= 2 + push %2 +%endif +%if %0 >= 3 + push %3 +%endif +%if %0 >= 4 + push %4 +%endif +%if %0 >= 5 + push %5 +%endif +%if %0 == 6 + push %6 +%endif +%if %0 > 6 + %error "PRINTF64 accepts at most 6 arguments" +%endif +%if %0 == 6 + pop r9 +%endif +%if %0 >= 5 + pop r8 +%endif +%if %0 >= 4 + pop rcx +%endif +%if %0 >= 3 + pop rdx +%endif +%if %0 >= 2 + pop rsi +%endif + pop rdi + xor eax, eax + + call printf + + + pop r11 + pop r10 + pop r9 + pop r8 + pop rdi + pop rsi + pop rdx + pop rcx + pop rax + popfq + ;add rsp, 8 +%endmacro diff --git a/labs/lab-09/reading/inline-assembly.md b/labs/lab-09/reading/inline-assembly.md index 4e9b175ac..31bb94b0d 100644 --- a/labs/lab-09/reading/inline-assembly.md +++ b/labs/lab-09/reading/inline-assembly.md @@ -22,9 +22,11 @@ asm asm-qualifiers ( AssemblerTemplate Where: - **asm:** Is just the keyword `asm` (like `for`, or `if`). -- **asm-qualifiers:** Are modifiers in the same vein as `const` is a modifier to variable declarations. The only one you will ever be interested in is `volatile`. +- **asm-qualifiers:** Are modifiers in the same vein as `const` is a modifier to variable declarations. +The only one you will ever be interested in is `volatile`. This keyword tells **gcc** to avoid modifying your assembly code snippet, even for the purpose of what it calls "optimization". -- **AssemblerTemplate:** Is a string literal containing one or more assembly statements. These statements can be separated through either a `;` character or a `\n`. +- **AssemblerTemplate:** Is a string literal containing one or more assembly statements. +These statements can be separated through either a `;` character or a `\n`. - **OutputOperands:** Binds register values at the end of the assembly code snippet to C variables where the values should be stored. - **InputOperands:** Specifies what values (immediate or located in C variables) should be used to initialize specific registers when starting to execute the assembly code snippet. - **Clobbers:** A list of registers (or memory) changed by the AssemblerTemplate that were not explicitly stated as OutputOperands.