diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml
index 0c85ceab5..b999f8f65 100644
--- a/.github/workflows/actions.yml
+++ b/.github/workflows/actions.yml
@@ -4,6 +4,7 @@ on:
pull_request:
branches:
- main
+ - x86_64
jobs:
checkpatch:
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 000000000..3623fd8ad
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,6 @@
+{
+ "files.associations": {
+ "*.c": "c",
+ "param.h": "c"
+ }
+}
\ No newline at end of file
diff --git a/labs/lab-02/media/arit.svg b/labs/lab-02/media/arit.svg
index bee8b721c..a20916734 100644
--- a/labs/lab-02/media/arit.svg
+++ b/labs/lab-02/media/arit.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/labs/lab-02/reading/memory-operations.md b/labs/lab-02/reading/memory-operations.md
index 92dfb1a5a..92f9b47f5 100644
--- a/labs/lab-02/reading/memory-operations.md
+++ b/labs/lab-02/reading/memory-operations.md
@@ -44,10 +44,12 @@ For example:
char *char_ptr = 1000;
short *short_ptr = 2000;
int *int_ptr = 3000;
+long long *long_long_ptr = 4000;
++char_ptr; /* char_ptr will point to address 1001 */
++short_ptr; /* short_ptr points to address 2002 */
++int_ptr; /* int_ptr points to address 3004 */
+++long_long_ptr; /* long_long_ptr points to address 4008 */
```

diff --git a/labs/lab-02/tasks/iterate/README.md b/labs/lab-02/tasks/iterate/README.md
index ee80a47b0..13011fa55 100644
--- a/labs/lab-02/tasks/iterate/README.md
+++ b/labs/lab-02/tasks/iterate/README.md
@@ -13,14 +13,14 @@ Here is the given piece of C code:
#include
int main() {
- int v[] = {0xCAFEBABE, 0xDEADBEEF, 0x0B00B135, 0xBAADF00D, 0xDEADC0DE};
+ int v[] = {0xCAFEBABE, 0xDEADBEEF, 0x0B00B135, 0xBAADF00D, 0xDEADC0DE, 0x1EE71EE7};
return 0;
}
```
Display the addresses of the elements in the `v` array along with their values.
-Iterate through the addresses in `v` byte by byte, two bytes at a time, and four bytes at a time.
+Iterate through the addresses in `v` byte by byte, two bytes at a time, four bytes at a time, and eight bytes at a time.
> **TIP:** You can iterate through memory byte by byte starting from a specific address using a pointer of type `unsigned char*` (since the `char` type is represented by one byte).
>
@@ -43,9 +43,10 @@ make check
In case of a correct solution, you will get an output such as:
```text
-test_chars ........................ passed ... 33
-test_shorts ........................ passed ... 33
-test_ints ........................ passed ... 34
+test_chars ........................ passed ... 25
+test_shorts ........................ passed ... 25
+test_ints ........................ passed ... 25
+test_long_longs ........................ passed ... 25
Total: 100/100
```
diff --git a/labs/lab-02/tasks/iterate/solution/array.c b/labs/lab-02/tasks/iterate/solution/array.c
index 807a6c684..3d2ec435e 100644
--- a/labs/lab-02/tasks/iterate/solution/array.c
+++ b/labs/lab-02/tasks/iterate/solution/array.c
@@ -2,4 +2,4 @@
#include "array.h"
-int v[5] = {0xCAFEBABE, 0xDEADBEEF, 0x0B00B135, 0xBAADF00D, 0xDEADC0DE};
+int v[6] = {0xCAFEBABE, 0xDEADBEEF, 0x0B00B135, 0xBAADF00D, 0xDEADC0DE, 0x1EE71EE7};
diff --git a/labs/lab-02/tasks/iterate/solution/array.h b/labs/lab-02/tasks/iterate/solution/array.h
index d23697eb6..e6a72e8b2 100644
--- a/labs/lab-02/tasks/iterate/solution/array.h
+++ b/labs/lab-02/tasks/iterate/solution/array.h
@@ -3,6 +3,6 @@
#ifndef ARRAY_H
#define ARRAY_H 1
-extern int v[5];
+extern int v[6];
#endif // ARRAY_H
diff --git a/labs/lab-02/tasks/iterate/solution/iterate.c b/labs/lab-02/tasks/iterate/solution/iterate.c
index 29064040a..0d24fa0c4 100644
--- a/labs/lab-02/tasks/iterate/solution/iterate.c
+++ b/labs/lab-02/tasks/iterate/solution/iterate.c
@@ -53,3 +53,18 @@ void print_ints_ref(void)
}
printf("-------------------------------\n");
}
+
+void print_long_longs_ref(void)
+{
+ unsigned long long *long_long_ptr = (unsigned long long *) &v;
+ unsigned long long i;
+ /**
+ * Iterate through 8 bytes at a time, we have only a quarter of the steps because we are
+ * displaying 8 bytes at each step.
+ */
+ for (i = 0 ; i < sizeof(v) / sizeof((*long_long_ptr)); ++i) {
+ printf("%p -> %p\n", long_long_ptr, *long_long_ptr);
+ ++long_long_ptr;
+ }
+ printf("-------------------------------\n");
+}
diff --git a/labs/lab-02/tasks/iterate/solution/iterate.h b/labs/lab-02/tasks/iterate/solution/iterate.h
index 2be037300..330ad34db 100644
--- a/labs/lab-02/tasks/iterate/solution/iterate.h
+++ b/labs/lab-02/tasks/iterate/solution/iterate.h
@@ -6,5 +6,6 @@
void print_chars_ref(void);
void print_shorts_ref(void);
void print_ints_ref(void);
+void print_long_longs_ref(void);
#endif // ITERATE_REF_H
diff --git a/labs/lab-02/tasks/iterate/solution/main.c b/labs/lab-02/tasks/iterate/solution/main.c
index 3e2d705a7..2ce8c8e42 100644
--- a/labs/lab-02/tasks/iterate/solution/main.c
+++ b/labs/lab-02/tasks/iterate/solution/main.c
@@ -13,6 +13,7 @@ int main(void)
print_chars_ref();
print_shorts_ref();
print_ints_ref();
+ print_long_longs_ref();
return 0;
}
diff --git a/labs/lab-02/tasks/iterate/support/array.c b/labs/lab-02/tasks/iterate/support/array.c
index 807a6c684..3d2ec435e 100644
--- a/labs/lab-02/tasks/iterate/support/array.c
+++ b/labs/lab-02/tasks/iterate/support/array.c
@@ -2,4 +2,4 @@
#include "array.h"
-int v[5] = {0xCAFEBABE, 0xDEADBEEF, 0x0B00B135, 0xBAADF00D, 0xDEADC0DE};
+int v[6] = {0xCAFEBABE, 0xDEADBEEF, 0x0B00B135, 0xBAADF00D, 0xDEADC0DE, 0x1EE71EE7};
diff --git a/labs/lab-02/tasks/iterate/support/array.h b/labs/lab-02/tasks/iterate/support/array.h
index d23697eb6..e6a72e8b2 100644
--- a/labs/lab-02/tasks/iterate/support/array.h
+++ b/labs/lab-02/tasks/iterate/support/array.h
@@ -3,6 +3,6 @@
#ifndef ARRAY_H
#define ARRAY_H 1
-extern int v[5];
+extern int v[6];
#endif // ARRAY_H
diff --git a/labs/lab-02/tasks/iterate/support/iterate.c b/labs/lab-02/tasks/iterate/support/iterate.c
index 68b030454..369f9f083 100644
--- a/labs/lab-02/tasks/iterate/support/iterate.c
+++ b/labs/lab-02/tasks/iterate/support/iterate.c
@@ -34,3 +34,13 @@ void print_ints(void)
printf("-------------------------------\n");
}
+
+void print_long_longs(void)
+{
+ /**
+ * TODO: Implement function
+ */
+ (void) v;
+
+ printf("-------------------------------\n");
+}
diff --git a/labs/lab-02/tasks/iterate/support/iterate.h b/labs/lab-02/tasks/iterate/support/iterate.h
index d3171c6d1..56a68264e 100644
--- a/labs/lab-02/tasks/iterate/support/iterate.h
+++ b/labs/lab-02/tasks/iterate/support/iterate.h
@@ -6,5 +6,6 @@
void print_chars(void);
void print_shorts(void);
void print_ints(void);
+void print_long_longs(void);
#endif // ITERATE_H
diff --git a/labs/lab-02/tasks/iterate/support/main.c b/labs/lab-02/tasks/iterate/support/main.c
index a79ea9bc3..a374126eb 100644
--- a/labs/lab-02/tasks/iterate/support/main.c
+++ b/labs/lab-02/tasks/iterate/support/main.c
@@ -14,6 +14,7 @@ int main(void)
print_chars();
print_shorts();
print_ints();
+ print_long_longs();
return 0;
}
diff --git a/labs/lab-02/tasks/iterate/tests/test_iterate.c b/labs/lab-02/tasks/iterate/tests/test_iterate.c
index 5d6a85b15..9f7386399 100644
--- a/labs/lab-02/tasks/iterate/tests/test_iterate.c
+++ b/labs/lab-02/tasks/iterate/tests/test_iterate.c
@@ -14,9 +14,11 @@
#define CHAR_OUTPUT "char.out"
#define SHORT_OUTPUT "short.out"
#define INT_OUTPUT "int.out"
+#define LONG_LONG_OUTPUT "long_long.out"
#define CHAR_REF "char.ref"
#define SHORT_REF "short.ref"
#define INT_REF "int.ref"
+#define LONG_LONG_REF "long_long.ref"
static int fd, stdout_fd;
@@ -120,10 +122,29 @@ static int test_ints(void)
return status == 0 ? 1 : 0;
}
+static int test_ints(void)
+{
+ int status;
+
+ prep_io(LONG_LONG_OUTPUT);
+ print_long_longs();
+ fflush(stdout);
+ restore_io();
+
+ prep_io(LONG_LONG_REF);
+ print_long_longs_ref();
+ fflush(stdout);
+ restore_io();
+
+ status = system("diff -q " LONG_LONG_OUTPUT " " LONG_LONG_REF);
+ return status == 0 ? 1 : 0;
+}
+
static struct graded_test all_tests[] = {
- { test_chars, "test_chars", 33 },
- { test_shorts, "test_shorts", 33},
- { test_ints, "test_ints", 34},
+ { test_chars, "test_chars", 25 },
+ { test_shorts, "test_shorts", 25},
+ { test_ints, "test_ints", 25},
+ { test_long_longs, "test_long_long", 25},
};
int main(void)
diff --git a/labs/lab-04/guides/discovering-assembly/README.md b/labs/lab-04/guides/discovering-assembly/README.md
index 322920571..b79486e1a 100644
--- a/labs/lab-04/guides/discovering-assembly/README.md
+++ b/labs/lab-04/guides/discovering-assembly/README.md
@@ -8,28 +8,28 @@ nav_order: 10
To follow this guide, you will need to navigate to the `guides/discovering-assembly/support` directory.
1. Open the `ex1.asm` file and read the comments.
-Assemble it by using the `make` utility and run it.
-Using gdb, go through the program line by line (the `start` command followed by `next`) and observe the changes in register values after executing the `mov` and `add` instructions.
-Ignore the sequence of `PRINTF32` instructions.
+ Assemble it by using the `make` utility and run it.
+ Using gdb, go through the program line by line (the `start` command followed by `next`) and observe the changes in register values after executing the `mov` and `add` instructions.
+ Ignore the sequence of `PRINTF64` instructions.
1. Open the `ex2.asm` file and read the comments.
-Assemble it by using the `make` utility and run it.
-Using gdb, observe the change in the `eip` register when executing the `jmp` instruction.
-To skip the `PRINTF32` instructions, add a breakpoint at the `jump_incoming` label (the `break` command followed by `run`).
+ Assemble it by using the `make` utility and run it.
+ Using gdb, observe the change in the `rip` register when executing the `jmp` instruction.
+ To skip the `PRINTF64` instructions, add a breakpoint at the `jump_incoming` label (the `break` command followed by `run`).
1. Open the `ex3.asm` file and read the comments.
-Assemble it by using the `make` utility and run it.
-Using gdb, navigate through the program using breakpoints.
-Follow the program flow.
-Why is `15` displayed first and then `3`?
-Because of the jump at line 9.
-Where does the jump at line 25 point to?
-To the `zone1` label.
+ Assemble it by using the `make` utility and run it.
+ Using gdb, navigate through the program using breakpoints.
+ Follow the program flow.
+ Why is `15` displayed first and then `3`?
+ Because of the jump at line 9.
+ Where does the jump at line 25 point to?
+ To the `zone1` label.
1. Open the `ex4.asm` file and read the comments.
-Assemble it by using the `make` utility and run it.
-Using gdb, go through the program.
-Why isn't the jump at line 12 taken?
-Because the `je` instruction jumps if the `ZF` bit in the `FLAGS` register is set.
-This bit is set by the `cmp` instruction, which calculates the difference between the values of the `eax` and `ebx` registers without storing the result.
-However, the `add` instruction at line 11 clears this flag because the result of the operation is different from 0.
+ Assemble it by using the `make` utility and run it.
+ Using gdb, go through the program.
+ Why isn't the jump at line 12 taken?
+ Because the `je` instruction jumps if the `ZF` bit in the `FLAGS` register is set.
+ This bit is set by the `cmp` instruction, which calculates the difference between the values of the `eax` and `ebx` registers without storing the result.
+ However, the `add` instruction at line 11 clears this flag because the result of the operation is different from 0.
diff --git a/labs/lab-04/guides/discovering-assembly/support/Makefile b/labs/lab-04/guides/discovering-assembly/support/Makefile
index dbcca12d6..eaaa1452d 100644
--- a/labs/lab-04/guides/discovering-assembly/support/Makefile
+++ b/labs/lab-04/guides/discovering-assembly/support/Makefile
@@ -5,11 +5,11 @@ RM = rm
SRCS := $(shell find . -name "*.asm")
OBJS := $(SRCS:.asm=.o)
-UTILSDIR := ..utils/
+UTILSDIR := ../utils/
-ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)"
+ASFLAGS ?= -f elf64 -F dwarf -I "$(UTILSDIR)"
CFLAGS ?= -Wall
-LDFLAGS ?= -m32 -no-pie
+LDFLAGS ?= -no-pie
all: ex1 ex2 ex3 ex4
diff --git a/labs/lab-04/guides/discovering-assembly/support/ex1.asm b/labs/lab-04/guides/discovering-assembly/support/ex1.asm
index 8c8bfeffb..a1de6fc40 100644
--- a/labs/lab-04/guides/discovering-assembly/support/ex1.asm
+++ b/labs/lab-04/guides/discovering-assembly/support/ex1.asm
@@ -1,14 +1,20 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .text
global main
extern printf
main:
- mov eax, 7 ; load the eax register with the value 7
- mov ebx, 8 ; load the ebx register with the value 8
- add eax, ebx ; add the value from ebx to the value from eax
+ push rbp
+ mov rbp, rsp
+
+ mov rax, 7 ; load the eax register with the value 7
+ mov r8, 8 ; load the ebx register with the value 8
+ add rax, r8 ; add the value from ebx to the value from eax
; and store the result in eax
- PRINTF32 `%d\n\x0`, eax ; print the value from the eax register
+ PRINTF64 `%d\n\x0`, rax ; print the value from the eax register
+
+ leave
+ ret
diff --git a/labs/lab-04/guides/discovering-assembly/support/ex2.asm b/labs/lab-04/guides/discovering-assembly/support/ex2.asm
index 3847d1496..3af1bf3a8 100644
--- a/labs/lab-04/guides/discovering-assembly/support/ex2.asm
+++ b/labs/lab-04/guides/discovering-assembly/support/ex2.asm
@@ -1,22 +1,26 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .text
global main
extern printf
main:
- mov eax, 4
- PRINTF32 `%d\n\x0`, eax
+ push rbp
+ mov rbp, rsp
+
+ mov r9, 4
+ PRINTF64 `%d\n\x0`, r9
jump_incoming:
jmp exit ; unconditional jump to the "exit" label
- mov eax, 7 ; this code is unreachable, therefore not executed
- mov ebx, 8
- add eax, ebx
- PRINTF32 `%d\n\x0`, eax
+ mov r9, 7 ; this code is unreachable, therefore not executed
+ mov rbx, 8
+ add r9, rbx
+ PRINTF64 `%d\n\x0`, r9
exit:
+ leave
ret
diff --git a/labs/lab-04/guides/discovering-assembly/support/ex3.asm b/labs/lab-04/guides/discovering-assembly/support/ex3.asm
index 3e7d75520..3c131bf09 100644
--- a/labs/lab-04/guides/discovering-assembly/support/ex3.asm
+++ b/labs/lab-04/guides/discovering-assembly/support/ex3.asm
@@ -1,31 +1,35 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .text
global main
extern printf
main:
- mov eax, zone2
- jmp eax ; unconditional jump to the address stored
+ push rbp
+ mov rbp, rsp
+
+ mov rax, zone2
+ jmp rax ; unconditional jump to the address stored
; in the eax register
zone1:
- mov eax, 1
- mov ebx, 2
- add eax, ebx
- PRINTF32 `%d\n\x0`, eax
+ mov rax, 1
+ mov r10, 2
+ add rax, r10
+ PRINTF64 `%d\n\x0`, rax
jump1:
jmp exit
zone2:
- mov eax, 7
- mov ebx, 8
- add eax, ebx
- PRINTF32 `%d\n\x0`, eax
+ mov rax, 7
+ mov r10, 8
+ add rax, r10
+ PRINTF64 `%d\n\x0`, rax
jump2:
- jmp $-0x4A ; relative jump with a negative offset
+ jmp $-0x82 ; relative jump with a negative offset
; to the address of the previous instruction
exit:
+ leave
ret
diff --git a/labs/lab-04/guides/discovering-assembly/support/ex4.asm b/labs/lab-04/guides/discovering-assembly/support/ex4.asm
index a4aef2a97..894514f98 100644
--- a/labs/lab-04/guides/discovering-assembly/support/ex4.asm
+++ b/labs/lab-04/guides/discovering-assembly/support/ex4.asm
@@ -1,19 +1,26 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .text
global main
extern printf
main:
- mov eax, 1
- mov ebx, 1
- cmp eax, ebx
- add ecx, 1 ; Comment out this line
+ push rbp
+ mov rbp, rsp
+
+ mov rax, 1
+ mov rbx, 1
+ cmp rax, rbx
+ add r15, 1 ; Comment out this line
je print
+
+ leave
ret
print:
- PRINTF32 `%d\n\x0`, eax
+ PRINTF64 `%d\n\x0`, rax
+
+ leave
ret
diff --git a/labs/lab-04/guides/discovering-assembly/utils/printf32.asm b/labs/lab-04/guides/discovering-assembly/utils/printf32.asm
deleted file mode 100644
index 61a930ed7..000000000
--- a/labs/lab-04/guides/discovering-assembly/utils/printf32.asm
+++ /dev/null
@@ -1,22 +0,0 @@
-;;; 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-04/guides/discovering-assembly/utils/printf64.asm b/labs/lab-04/guides/discovering-assembly/utils/printf64.asm
new file mode 100644
index 000000000..2bcf2712b
--- /dev/null
+++ b/labs/lab-04/guides/discovering-assembly/utils/printf64.asm
@@ -0,0 +1,71 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-04/guides/instructions/README.md b/labs/lab-04/guides/instructions/README.md
index 501c36d70..6cfb4631c 100644
--- a/labs/lab-04/guides/instructions/README.md
+++ b/labs/lab-04/guides/instructions/README.md
@@ -28,13 +28,13 @@ Having in mind what the `popf` instruction does, try to guess what would adding
jnc mystery_label
```
-Moving on, we can see that the `0` value is set to the `eax` register using the `mov` instruction.
-Can you give example of another two ways of setting the value in `eax` to `0` without using `mov` ?
+Moving on, we can see that the `0` value is set to the `r9` register using the `mov` instruction.
+Can you give example of another two ways of setting the value in `r9` to `0` without using `mov` ?
> **HINT**: Think about the [logical operators](../../reading/x86-architecture-family.md).
-Next, by using the `test` instruction we can set the `flags` based on the output of the `logical and` between `eax` and itself.
+Next, by using the `test` instruction we can set the `flags` based on the output of the `logical and` between `r9` and itself.
-After resetting the flags, we store `0xffffffff` in the `ebx` register(which is actually the largest number it can store before setting the carry flag) and then use the `test` instruction yet again.
+After resetting the flags, we store `0xffffffffffffffff` in the `rbx` register(which is actually the largest number it can store before setting the carry flag) and then use the `test` instruction yet again.
Similarly, what do you think adding the following line of code after the `test` instruction would produce ?
```assembly
@@ -42,12 +42,12 @@ jnz mystery_label
```
We reset the flags once again and now we take a look at working with the smaller portions of the `eax` register.
-Can you guess the output of the following command, put right under the `add al, bl` instruction ?
+Can you guess the output of the following command, put right under the `add r9b, bl` instruction ?
What about the flags ?
Which flag has been set ?
```assembly
-PRINTF32 `%d\n\x0`, eax
+PRINTF64 `%d\n\x0`, r9
```
Similarly, try to answer the same questions from above, but considering the next portions of the code.
diff --git a/labs/lab-04/guides/instructions/support/Makefile b/labs/lab-04/guides/instructions/support/Makefile
index ade99a100..818b7d923 100644
--- a/labs/lab-04/guides/instructions/support/Makefile
+++ b/labs/lab-04/guides/instructions/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 ?= -no-pie
TARGET_EXEC = instructions
diff --git a/labs/lab-04/guides/instructions/support/instructions.asm b/labs/lab-04/guides/instructions/support/instructions.asm
index 5381fc28f..731146397 100644
--- a/labs/lab-04/guides/instructions/support/instructions.asm
+++ b/labs/lab-04/guides/instructions/support/instructions.asm
@@ -1,53 +1,58 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .text
global main
extern printf
main:
+ push rbp
+ mov rbp, rsp
+
push 0
popf
- mov eax, 0
- test eax, eax
+ mov r9, 0
+ test r9, r9
push 0
popf
- mov ebx, 0xffffffff
- test ebx, ebx
+ mov rbx, 0xffffffffffffffff
+ test rbx, rbx
push 0
popf
- mov al, 250
+ mov r9b, 250
mov bl, 10
- add al, bl
+ add r9b, bl
push 0
popf
- mov al, 0
+ mov r9b, 0
mov bl, 1
- sub al, bl
+ sub r9b, bl
push 0
popf
- mov al, 120
+ mov r9b, 120
mov bl, 120
- add al, bl
+ add r9b, bl
push 0
popf
- mov al, 129
+ mov r9b, 129
mov bl, 129
- add al, bl
+ add r9b, bl
+
+ PRINTF64 `%d\n\x0`, r9
- PRINTF32 `%d\n\x0`, eax
+ leave
ret
diff --git a/labs/lab-04/guides/instructions/utils/printf32.asm b/labs/lab-04/guides/instructions/utils/printf32.asm
deleted file mode 100644
index 61a930ed7..000000000
--- a/labs/lab-04/guides/instructions/utils/printf32.asm
+++ /dev/null
@@ -1,22 +0,0 @@
-;;; 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-04/guides/instructions/utils/printf64.asm b/labs/lab-04/guides/instructions/utils/printf64.asm
new file mode 100644
index 000000000..2bcf2712b
--- /dev/null
+++ b/labs/lab-04/guides/instructions/utils/printf64.asm
@@ -0,0 +1,71 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-04/reading/introduction.md b/labs/lab-04/reading/introduction.md
index d0c9a55a0..8bcbef6fe 100644
--- a/labs/lab-04/reading/introduction.md
+++ b/labs/lab-04/reading/introduction.md
@@ -33,8 +33,8 @@ Most assembly languages provide a direct correspondence between instructions. Fo
```assembly
mov al, 12 <-> '\xB0\x0C'
-xor dx, dx <-> '\x67\x31\xD2'
-jmp esp <-> '\xFF\xE4'
+xor dx, dx <-> '\x66\x31\xD2'
+jmp rsp <-> '\xFF\xE4'
```
> **NOTE**: Because assembly language depends on architecture, it is generally not portable.
diff --git a/labs/lab-04/reading/x86-architecture-family.md b/labs/lab-04/reading/x86-architecture-family.md
index af609eb34..02bfaab1d 100644
--- a/labs/lab-04/reading/x86-architecture-family.md
+++ b/labs/lab-04/reading/x86-architecture-family.md
@@ -17,26 +17,27 @@ These processors are highly backward compatible, with most instructions unchange
The basic working units for x86 processors are registers.
These are a suite of locations within the processor through which it interacts with memory, I/O, etc.
-x86 processors have 8 such 32-bit registers.
+x86 processors have 16 such 64-bit registers.
Although any of these can be used in operations, for historical reasons, each register has a specific role.
Name | Role
----- | ---
-`eax` | accumulator; system calls, I/O, arithmetic
-`ebx` | base register; used for memory-based addressing
-`ecx` | counter in loop instructions
-`edx` | data register, used for I/O, arithmetic, interrupt values; can extend eax to 64 bits
-`esi` | source in string operations
-`edi` | destination in string operations
-`ebp` | base or frame pointer; points to the current stack frame
-`esp` | stack pointer; points to the top of the stack
-
-In addition to these, there are some special registers that cannot be directly accessed by the programmer, such as `eflags` and `eip` (Instruction Pointer).
-
-`eip` is a register that holds the address of the current instruction to be executed.
+`rax` | accumulator; system calls, I/O, arithmetic
+`rbx` | base register; used for memory-based addressing
+`rcx` | counter in loop instructions
+`rdx` | data register, used for I/O, arithmetic, interrupt values; can extend rax to 128 bits
+`rsi` | source in string operations
+`rdi` | destination in string operations
+`rbp` | base or frame pointer; points to the current stack frame
+`rsp` | stack pointer; points to the top of the stack
+`r8-15` | general purpose registers
+
+In addition to these, there are some special registers that cannot be directly accessed by the programmer, such as `rflags` and `rip` (Instruction Pointer).
+
+`rip` is a register that holds the address of the current instruction to be executed.
It cannot be directly modified, programmatically, but indirectly through jump, call, and ret instructions.
-The `eflags` register contains `32` bits used as status indicators or condition variables.
+The `rflags` register contains `64` bits used as status indicators or condition variables.
We say that a flag is set if its value is `1`. The ones commonly used by programmers are:
Name | Expanded Name | Description
@@ -49,13 +50,10 @@ Name | Expanded Name | Description
`OF` | Overflow Flag | Set if the result exceeds the maximum (or minimum) signed integer value
>**NOTE**: If you follow the evolution of registers from 8086, you'll see that initially they were named `ax`, `bx`, `cx` etc., and were 16 bits in size.
->From 80386, Intel extended these registers to 32 bits (i.e., "extended" `ax` → `eax`).
+>From 80386, Intel extended these registers to 32 bits (i.e., "extended" `ax` → `eax`), and again with the release of "Prescott" and "Nocona" processors.
## Instruction Classes
-Although the current set of instructions for Intel processors has [hundreds of instructions](https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf), we will only look at a [small portion of them](http://css.csail.mit.edu/6.858/2015/readings/i386.pdf).
-More precisely, some of the 80386 instructions.
-
All x86 processors instructions can fit into 3 categories :
- data movement instructions
@@ -107,16 +105,16 @@ We are talking about an unsigned subtraction, without storing the result.
Therefore, when talking about the code:
> ```assembly
-> cmp eax, 0
+> cmp rax, 0
> jl negative
> ```
The jump to the `negative` label will be made only if the value in eax is less than `0`.
-The `eax - 0` subtraction is evaluated and if the result is negative(and so, eax is negative), the jump will be made.\
+The `rax - 0` subtraction is evaluated and if the result is negative (and so, rax is negative), the jump will be made.\
When have comparisons with `0`, the same thing can be done more efficiently using the `test` instruction:
> ```assembly
-> test eax, eax
+> test rax, rax
> jl negative
>```
diff --git a/labs/lab-04/tasks/cf-of/solution/cf.asm b/labs/lab-04/tasks/cf-of/solution/cf.asm
index 9258188ad..2ff06fd28 100644
--- a/labs/lab-04/tasks/cf-of/solution/cf.asm
+++ b/labs/lab-04/tasks/cf-of/solution/cf.asm
@@ -1,21 +1,27 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .text
global main
extern printf
main:
+ push rbp
+ mov rbp, rsp
+
mov al, 0xFF
- PRINTF32 `the Carry Flag is not active\n\x0`
+ PRINTF64 `the Carry Flag is not active\n\x0`
test al, al
add al, 1
jc carry_flag
jmp end
carry_flag:
- PRINTF32 `the Carry Flag is active\n\x0`
+ PRINTF64 `the Carry Flag is active\n\x0`
end:
+ xor rax, rax
+
+ leave
ret
diff --git a/labs/lab-04/tasks/cf-of/solution/cf_of.asm b/labs/lab-04/tasks/cf-of/solution/cf_of.asm
index ef80271b6..e7e6f67fd 100644
--- a/labs/lab-04/tasks/cf-of/solution/cf_of.asm
+++ b/labs/lab-04/tasks/cf-of/solution/cf_of.asm
@@ -1,15 +1,17 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .text
global main
extern printf
main:
+ push rbp
+ mov rbp, rsp
mov al, 128
- PRINTF32 `the Carry Flag and the Overflow Flag are not active\n\x0`
+ PRINTF64 `the Carry Flag and the Overflow Flag are not active\n\x0`
test al, al
; Any value between 128 and 255 will set the carry flag
@@ -23,8 +25,10 @@ cf_on:
jmp end
cf_of_on:
- PRINTF32 `the Carry Flag and the Overflow Flag are active\n\x0`
+ PRINTF64 `the Carry Flag and the Overflow Flag are active\n\x0`
end:
- ret
+ xor rax, rax
+ leave
+ ret
diff --git a/labs/lab-04/tasks/cf-of/solution/of.asm b/labs/lab-04/tasks/cf-of/solution/of.asm
index 967e0bdbd..10e582c41 100644
--- a/labs/lab-04/tasks/cf-of/solution/of.asm
+++ b/labs/lab-04/tasks/cf-of/solution/of.asm
@@ -1,22 +1,27 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .text
global main
extern printf
main:
+ push rbp
+ mov rbp, rsp
mov al, 0x7F
- PRINTF32 `the Overflow Flag is not active\n\x0`
+ PRINTF64 `the Overflow Flag is not active\n\x0`
test al, al
add al, 1
jo overflow_flag
jmp end
overflow_flag:
- PRINTF32 `the Overflow Flag is active\n\x0`
+ PRINTF64 `the Overflow Flag is active\n\x0`
end:
+ xor rax, rax
+
+ leave
ret
diff --git a/labs/lab-04/tasks/cf-of/support/Makefile b/labs/lab-04/tasks/cf-of/support/Makefile
index 549af5412..af71359ee 100644
--- a/labs/lab-04/tasks/cf-of/support/Makefile
+++ b/labs/lab-04/tasks/cf-of/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 ?= -no-pie
all: of cf cf_of
diff --git a/labs/lab-04/tasks/cf-of/support/cf.asm b/labs/lab-04/tasks/cf-of/support/cf.asm
index ee8180415..344fb9631 100644
--- a/labs/lab-04/tasks/cf-of/support/cf.asm
+++ b/labs/lab-04/tasks/cf-of/support/cf.asm
@@ -1,14 +1,17 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .text
global main
extern printf
main:
+ push rbp
+ mov rbp, rsp
+
mov al, 0xFF
- PRINTF32 `the Carry Flag is not active\n\x0`
+ PRINTF64 `the Carry Flag is not active\n\x0`
test al, al
;TODO: activate the Carry Flag
@@ -16,7 +19,10 @@ main:
jmp end
carry_flag:
- PRINTF32 `the Carry Flag is active\n\x0`
+ PRINTF64 `the Carry Flag is active\n\x0`
end:
+ xor rax, rax
+
+ leave
ret
diff --git a/labs/lab-04/tasks/cf-of/support/cf_of.asm b/labs/lab-04/tasks/cf-of/support/cf_of.asm
index b0d1b9ca4..78a832cbb 100644
--- a/labs/lab-04/tasks/cf-of/support/cf_of.asm
+++ b/labs/lab-04/tasks/cf-of/support/cf_of.asm
@@ -1,14 +1,17 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .text
global main
extern printf
main:
+ push rbp
+ mov rbp, rsp
+
mov al, 128
- PRINTF32 `the Carry Flag and the Overflow Flag are not active\n\x0`
+ PRINTF64 `the Carry Flag and the Overflow Flag are not active\n\x0`
test al, al
;TODO: activate the Carry Flag and the Overflow Flag
@@ -20,8 +23,10 @@ cf_on:
jmp end
cf_of_on:
- PRINTF32 `the Carry Flag and the Overflow Flag are active\n\x0`
+ PRINTF64 `the Carry Flag and the Overflow Flag are active\n\x0`
end:
- ret
+ xor rax, rax
+ leave
+ ret
diff --git a/labs/lab-04/tasks/cf-of/support/of.asm b/labs/lab-04/tasks/cf-of/support/of.asm
index 0b79eb95f..92d529261 100644
--- a/labs/lab-04/tasks/cf-of/support/of.asm
+++ b/labs/lab-04/tasks/cf-of/support/of.asm
@@ -1,22 +1,28 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .text
global main
extern printf
main:
+ push rbp
+ mov rbp, rsp
mov al, 0x7F
- PRINTF32 `the Overflow Flag is not active\n\x0`
+ PRINTF64 `the Overflow Flag is not active\n\x0`
test al, al
;TODO: activate the Overflow Flag
+
jo overflow_flag
jmp end
overflow_flag:
- PRINTF32 `the Overflow Flag is active\n\x0`
+ PRINTF64 `the Overflow Flag is active\n\x0`
end:
+ xor rax, rax
+
+ leave
ret
diff --git a/labs/lab-04/tasks/cf-of/utils/printf32.asm b/labs/lab-04/tasks/cf-of/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-04/tasks/cf-of/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-04/tasks/cf-of/utils/printf64.asm b/labs/lab-04/tasks/cf-of/utils/printf64.asm
new file mode 100644
index 000000000..2bcf2712b
--- /dev/null
+++ b/labs/lab-04/tasks/cf-of/utils/printf64.asm
@@ -0,0 +1,71 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-04/tasks/conditional-jumps/README.md b/labs/lab-04/tasks/conditional-jumps/README.md
index 05d584ca3..f508100d2 100644
--- a/labs/lab-04/tasks/conditional-jumps/README.md
+++ b/labs/lab-04/tasks/conditional-jumps/README.md
@@ -7,12 +7,12 @@ nav_order: 1
You will solve the exercises starting from the `hello_world.asm` file located in the `tasks/conditional-jumps` directory.
-1. Modify the program so that the message is displayed only if the content of the `eax` register is greater than that of `ebx`.
+1. Modify the program so that the message is displayed only if the content of the `rax` register is greater than that of `r8`.
Also, modify the values of the registers to continue displaying the message `"Hello, World!"`.
1. Modify the program to also display `"Goodbye, World!"` at the end.
-1. Using jump instructions, modify the program to display `"Hello, World!"` N times, where N is given through the `ecx` register.
+1. Using jump instructions, modify the program to display `"Hello, World!"` N times, where N is given through the `rcx` register.
Avoid infinite looping.
> **TIP**: After a successful completion (with `N = 6`), the program should display:
diff --git a/labs/lab-04/tasks/conditional-jumps/solution/hello_world.asm b/labs/lab-04/tasks/conditional-jumps/solution/hello_world.asm
index 3267e2e46..464730656 100644
--- a/labs/lab-04/tasks/conditional-jumps/solution/hello_world.asm
+++ b/labs/lab-04/tasks/conditional-jumps/solution/hello_world.asm
@@ -1,10 +1,10 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .data
myString: db "Hello, World!", 0
- N: dd 6 ; N = 6
+ N: dq 6 ; N = 6
myGoodbyeString: db "Goodbye, World!", 0
section .text
@@ -12,22 +12,30 @@ section .text
extern printf
main:
- mov ecx, DWORD [N] ; N = the value stored in ecx
- PRINTF32 `%d\n\x0`, ecx ; DO NOT REMOVE/MODIFY THIS LINE
+ push rbp
+ mov rbp, rsp
- mov eax, 2
- mov ebx, 1
- cmp eax, ebx
- jg print ; TODO1: eax > ebx?
+ mov rcx, QWORD [N] ; N = the value stored in rcx
+ PRINTF64 `%d\n\x0`, rcx ; DO NOT REMOVE/MODIFY THIS LINE
+
+ mov rax, 2
+ mov r8, 1
+ cmp rax, r8
+ jg print ; TODO1: rax > r8?
+ xor rax, rax
+
+ leave
ret
print:
- PRINTF32 `%s\n\x0`, myString
+ PRINTF64 `%s\n\x0`, myString
; TODO2.2: print "Hello, World!" N times
- dec ecx
- cmp ecx, 0
+ dec rcx
+ cmp rcx, 0
jg print
; TODO2.1: print "Goodbye, World!"
- PRINTF32 `%s\n\x0`, myGoodbyeString
+ PRINTF64 `%s\n\x0`, myGoodbyeString
+ xor rax, rax
+ leave
ret
diff --git a/labs/lab-04/tasks/conditional-jumps/support/Makefile b/labs/lab-04/tasks/conditional-jumps/support/Makefile
index a1e94397b..ef889026a 100644
--- a/labs/lab-04/tasks/conditional-jumps/support/Makefile
+++ b/labs/lab-04/tasks/conditional-jumps/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 ?= -no-pie
TARGET_EXEC = hello_world
diff --git a/labs/lab-04/tasks/conditional-jumps/support/hello_world.asm b/labs/lab-04/tasks/conditional-jumps/support/hello_world.asm
index 6e9362cdc..4b9af08b5 100644
--- a/labs/lab-04/tasks/conditional-jumps/support/hello_world.asm
+++ b/labs/lab-04/tasks/conditional-jumps/support/hello_world.asm
@@ -1,28 +1,36 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .data
myString: db "Hello, World!", 0
- N: dd 6 ; N = 6
+ N: dq 6 ; N = 6
section .text
global main
extern printf
main:
- mov ecx, DWORD [N] ; ecx will store the value of N
- PRINTF32 `%d\n\x0`, ecx ; DO NOT REMOVE/MODIFY THIS LINE
+ push rbp
+ mov rbp, rsp
- mov eax, 2
- mov ebx, 1
- cmp eax, ebx
- je print ; TODO1: eax > ebx?
+ mov rcx, QWORD [N] ; rcx will store the value of N
+ PRINTF64 `%d\n\x0`, rcx ; DO NOT REMOVE/MODIFY THIS LINE
+
+ mov rax, 2
+ mov r8, 1
+ cmp rax, r8
+ je print ; TODO1: rax > r8?
+ xor rax, rax
+
+ leave
ret
print:
- PRINTF32 `%s\n\x0`, myString
+ PRINTF64 `%s\n\x0`, myString
; TODO2.2: print "Hello, World!" N times
; TODO2.1: print "Goodbye, World!"
+ xor rax, rax
+ leave
ret
diff --git a/labs/lab-04/tasks/conditional-jumps/utils/printf32.asm b/labs/lab-04/tasks/conditional-jumps/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-04/tasks/conditional-jumps/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-04/tasks/conditional-jumps/utils/printf64.asm b/labs/lab-04/tasks/conditional-jumps/utils/printf64.asm
new file mode 100644
index 000000000..2bcf2712b
--- /dev/null
+++ b/labs/lab-04/tasks/conditional-jumps/utils/printf64.asm
@@ -0,0 +1,71 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-04/tasks/fibonacci/README.md b/labs/lab-04/tasks/fibonacci/README.md
index af737ecb9..29137feb7 100644
--- a/labs/lab-04/tasks/fibonacci/README.md
+++ b/labs/lab-04/tasks/fibonacci/README.md
@@ -7,13 +7,13 @@ nav_order: 5
You will solve this exercise starting from the `fibonacci.asm` file located in the `tasks/fibonacci` directory.
-Calculate the Nth Fibonacci number, where N is given through the `eax` register.
+Calculate the Nth Fibonacci number, where N is given through the `rcx` register.
>**NOTE**: The Nth Fibonacci number is `F[N]` for our chosen N.
> By definition, `F[0] = 0` and `F[1] = F[2] = 1`.
> Each following value is calculated with the formula `F[i] = F[i - 1] + F[i - 2]`.
>
->**TIP**: For example, if the value stored in `ecx` is equal to `5`, a correct solution will display `5` and for `7`, it will display `13`.
+>**TIP**: For example, if the value stored in `rcx` is equal to `5`, a correct solution will display `5` and for `7`, it will display `13`.
To test the implementation, enter the `tests/` directory and run:
diff --git a/labs/lab-04/tasks/fibonacci/solution/fibonacci.asm b/labs/lab-04/tasks/fibonacci/solution/fibonacci.asm
index f02d13d68..f6d341cd8 100644
--- a/labs/lab-04/tasks/fibonacci/solution/fibonacci.asm
+++ b/labs/lab-04/tasks/fibonacci/solution/fibonacci.asm
@@ -1,31 +1,36 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .data
- N: dd 7 ; N-th fibonacci number to calculate
+ N: dq 7 ; N-th fibonacci number to calculate
section .text
global main
extern printf
main:
- mov ecx, DWORD [N] ; we want to find the N-th fibonacci number; N = ECX = 7
+ push rbp
+ mov rbp, rsp
+
+ mov rcx, QWORD [N] ; we want to find the N-th fibonacci number; N = RCX = 7
; TODO: calculate the N-th fibonacci number (f(0) = 0, f(1) = 1)
- PRINTF32 `%d\n\x0`, ecx ; DO NOT REMOVE/MODIFY THIS LINE
+ PRINTF64 `%d\n\x0`, rcx ; DO NOT REMOVE/MODIFY THIS LINE
- mov eax, 0
- mov ebx, 1
+ mov rax, 0
+ mov r9, 1
fibonacci:
- dec ecx
- test ecx, ecx
+ dec rcx
+ test rcx, rcx
je print
- add eax, ebx
- xchg eax, ebx
+ add rax, r9
+ xchg rax, r9
jmp fibonacci
print:
- PRINTF32 `%d\n\x0`, ebx
- xor eax, eax
+ PRINTF64 `%d\n\x0`, r9
+ xor rax, rax
+
+ leave
ret
diff --git a/labs/lab-04/tasks/fibonacci/support/Makefile b/labs/lab-04/tasks/fibonacci/support/Makefile
index 31d4caede..2fb5e3a50 100644
--- a/labs/lab-04/tasks/fibonacci/support/Makefile
+++ b/labs/lab-04/tasks/fibonacci/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 ?= -no-pie
TARGET_EXEC = fibonacci
diff --git a/labs/lab-04/tasks/fibonacci/support/fibonacci.asm b/labs/lab-04/tasks/fibonacci/support/fibonacci.asm
index dc6ffa125..18bdf59b0 100644
--- a/labs/lab-04/tasks/fibonacci/support/fibonacci.asm
+++ b/labs/lab-04/tasks/fibonacci/support/fibonacci.asm
@@ -1,18 +1,24 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .data
- N: dd 7 ; N-th fibonacci number to calculate
+ N: dq 7 ; N-th fibonacci number to calculate
section .text
global main
extern printf
main:
- mov ecx, DWORD [N] ; we want to find the N-th fibonacci number; N = ECX = 7
- PRINTF32 `%d\n\x0`, ecx ; DO NOT REMOVE/MODIFY THIS LINE
+ push rbp
+ mov rbp, rsp
+
+ mov rcx, QWORD [N] ; we want to find the N-th fibonacci number; N = RCX = 7
+ PRINTF64 `%d\n\x0`, rcx ; DO NOT REMOVE/MODIFY THIS LINE
; TODO: calculate the N-th fibonacci number (f(0) = 0, f(1) = 1)
+ xor rax, rax
+
+ leave
ret
diff --git a/labs/lab-04/tasks/fibonacci/utils/printf32.asm b/labs/lab-04/tasks/fibonacci/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-04/tasks/fibonacci/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-04/tasks/fibonacci/utils/printf64.asm b/labs/lab-04/tasks/fibonacci/utils/printf64.asm
new file mode 100644
index 000000000..2bcf2712b
--- /dev/null
+++ b/labs/lab-04/tasks/fibonacci/utils/printf64.asm
@@ -0,0 +1,71 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-04/tasks/grumpy-jumps/README.md b/labs/lab-04/tasks/grumpy-jumps/README.md
index d6e05c694..1495b4271 100644
--- a/labs/lab-04/tasks/grumpy-jumps/README.md
+++ b/labs/lab-04/tasks/grumpy-jumps/README.md
@@ -7,13 +7,13 @@ nav_order: 2
You will solve the exercises starting from the `grumpy_jumps.asm` file located in the `tasks/grumpy-jumps` directory.
-1. Modify the values of the `eax` and `ebx` registers so that when the program is run, the message `Well done!` is displayed.
+1. Modify the values of the `rax` and `rbx` registers so that when the program is run, the message `Well done!` is displayed.
Follow the `TODO` comments.
1. Why does the wrong message still appear?
Modify the source so that the wrong message is not displayed anymore.
-> **TIP**: To determine the necessary values for the `eax` and `ebx` registers, we recommend using GDB.
+> **TIP**: To determine the necessary values for the `rax` and `rbx` registers, we recommend using GDB.
To test the implementation, enter the `tests/` directory and run:
diff --git a/labs/lab-04/tasks/grumpy-jumps/solution/grumpy_jumps.asm b/labs/lab-04/tasks/grumpy-jumps/solution/grumpy_jumps.asm
index 4a56ce184..216167a85 100644
--- a/labs/lab-04/tasks/grumpy-jumps/solution/grumpy_jumps.asm
+++ b/labs/lab-04/tasks/grumpy-jumps/solution/grumpy_jumps.asm
@@ -1,6 +1,6 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .data
wrong: db 'Not today, son.',0
@@ -11,21 +11,30 @@ section .text
extern printf
main:
- mov eax, 0x1 ; TODO3.1: modify eax register
- mov ebx, 0x4; ; TODO3.1: modify ebx register
- mov ecx, 0x5 ; hardcoded; DO NOT change
- cmp eax, ebx
+ push rbp
+ mov rbp, rsp
+
+ mov rax, 0x1 ; TODO3.1: modify rax register
+ mov rbx, 0x4; ; TODO3.1: modify rbx register
+ mov rcx, 0x5 ; hardcoded; DO NOT change
+ cmp rax, rbx
jns bad
- cmp ecx, ebx
+ cmp rcx, rbx
jb bad
- add eax, ebx
- xor eax, ecx
+ add rax, rbx
+ xor rax, rcx
jnz bad
good:
- PRINTF32 `%s\n\x0`, right
+ PRINTF64 `%s\n\x0`, right
+ xor rax, rax
+
+ leave
ret
bad:
- PRINTF32 `%s\n\x0`, wrong
+ PRINTF64 `%s\n\x0`, wrong
+ xor rax, rax
+
+ leave
ret
diff --git a/labs/lab-04/tasks/grumpy-jumps/support/Makefile b/labs/lab-04/tasks/grumpy-jumps/support/Makefile
index 5572f3474..d3783114e 100644
--- a/labs/lab-04/tasks/grumpy-jumps/support/Makefile
+++ b/labs/lab-04/tasks/grumpy-jumps/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 ?= -no-pie
TARGET_EXEC = grumpy_jumps
diff --git a/labs/lab-04/tasks/grumpy-jumps/support/grumpy_jumps.asm b/labs/lab-04/tasks/grumpy-jumps/support/grumpy_jumps.asm
index aa7dc661b..63d584a42 100644
--- a/labs/lab-04/tasks/grumpy-jumps/support/grumpy_jumps.asm
+++ b/labs/lab-04/tasks/grumpy-jumps/support/grumpy_jumps.asm
@@ -1,6 +1,6 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .data
wrong: db 'Not today, son.',0
@@ -11,20 +11,30 @@ section .text
extern printf
main:
- mov eax, 0xdeadc0de ; TODO3.1: modify eax register
- mov ebx, 0x1337ca5e ; TODO3.1: modify ebx register
- mov ecx, 0x5 ; hardcoded; DO NOT change
- cmp eax, ebx
+ push rbp
+ mov rbp, rsp
+
+ mov rax, 0xdeadc0de ; TODO3.1: modify rax register
+ mov rbx, 0x1337ca5e ; TODO3.1: modify rbx register
+ mov rcx, 0x5 ; hardcoded; DO NOT change
+ cmp rax, rbx
jns bad
- cmp ecx, ebx
+ cmp rcx, rbx
jb bad
- add eax, ebx
- xor eax, ecx
+ add rax, rbx
+ xor rax, rcx
jnz bad
good:
- PRINTF32 `%s\n\x0`, right
+ PRINTF64 `%s\n\x0`, right
+ xor rax, rax
+
+ leave
+ ret
bad:
- PRINTF32 `%s\n\x0`, wrong
+ PRINTF64 `%s\n\x0`, wrong
+ xor rax, rax
+
+ leave
ret
diff --git a/labs/lab-04/tasks/grumpy-jumps/utils/printf32.asm b/labs/lab-04/tasks/grumpy-jumps/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-04/tasks/grumpy-jumps/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-04/tasks/grumpy-jumps/utils/printf64.asm b/labs/lab-04/tasks/grumpy-jumps/utils/printf64.asm
new file mode 100644
index 000000000..2bcf2712b
--- /dev/null
+++ b/labs/lab-04/tasks/grumpy-jumps/utils/printf64.asm
@@ -0,0 +1,71 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-04/tasks/min/README.md b/labs/lab-04/tasks/min/README.md
index ad6901faf..8f9f8bf82 100644
--- a/labs/lab-04/tasks/min/README.md
+++ b/labs/lab-04/tasks/min/README.md
@@ -7,7 +7,7 @@ nav_order: 4
You will solve this exercise starting from the `min.asm` file located in the `tasks/min` directory.
-Calculate the minimum of the numbers in 2 registers (`eax` and `ebx`) using a comparison instruction, a jump instruction, and the `xchg` instruction.
+Calculate the minimum of the numbers in 2 registers (`r9` and `r10`) using a comparison instruction, a jump instruction, and the `xchg` instruction.
To test the implementation, enter the `tests/` directory and run:
diff --git a/labs/lab-04/tasks/min/solution/min.asm b/labs/lab-04/tasks/min/solution/min.asm
index 31b0b67a8..dac870bfa 100644
--- a/labs/lab-04/tasks/min/solution/min.asm
+++ b/labs/lab-04/tasks/min/solution/min.asm
@@ -1,27 +1,32 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .data
- FIRST_NUMBER dd 4 ; The first number
- SECOND_NUMBER dd 1 ; The second number
+ FIRST_NUMBER dq 4 ; The first number
+ SECOND_NUMBER dq 1 ; The second number
section .text
global main
extern printf
main:
- ; The two numbers can be found in the registers eax and ebx
- mov eax, DWORD [FIRST_NUMBER] ; The first number
- mov ebx, DWORD [SECOND_NUMBER] ; The second number
- PRINTF32 `%d\n\x0`, eax ; print the first number
- PRINTF32 `%d\n\x0`, ebx ; print the second number
+ push rbp
+ mov rbp, rsp
- ; TODO: find the minimum of the two numbers and store it in eax
- cmp eax, ebx
+ ; The two numbers can be found in the registers r9 and r10
+ mov r9, QWORD [FIRST_NUMBER] ; The first number
+ mov r10, QWORD [SECOND_NUMBER] ; The second number
+ PRINTF64 `%d\n\x0`, r9 ; print the first number
+ PRINTF64 `%d\n\x0`, r10 ; print the second number
+
+ ; TODO: find the minimum of the two numbers and store it in r9
+ cmp r9, r10
jl print_min
- xchg eax, ebx
+ xchg r9, r10
print_min:
- PRINTF32 `%d\n\x0`, eax ; print the minimum number
- xor eax, eax
+ PRINTF64 `%d\n\x0`, r9 ; print the minimum number
+ xor rax, rax
+
+ leave
ret
diff --git a/labs/lab-04/tasks/min/support/Makefile b/labs/lab-04/tasks/min/support/Makefile
index 6b08351ac..490c697ee 100644
--- a/labs/lab-04/tasks/min/support/Makefile
+++ b/labs/lab-04/tasks/min/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 ?= -no-pie
TARGET_EXEC = min
diff --git a/labs/lab-04/tasks/min/support/min.asm b/labs/lab-04/tasks/min/support/min.asm
index c99549cc8..3d5acf3da 100644
--- a/labs/lab-04/tasks/min/support/min.asm
+++ b/labs/lab-04/tasks/min/support/min.asm
@@ -1,25 +1,30 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .data
- FIRST_NUMBER dd 4 ; The first number
- SECOND_NUMBER dd 1 ; The second number
+ FIRST_NUMBER dq 4 ; The first number
+ SECOND_NUMBER dq 1 ; The second number
section .text
global main
extern printf
main:
- ; The two numbers can be found in the registers eax and ebx
- mov eax, DWORD [FIRST_NUMBER] ; The first number
- mov ebx, DWORD [SECOND_NUMBER] ; The second number
- PRINTF32 `%d\n\x0`, eax ; print the first number
+ push rbp
+ mov rbp, rsp
+
+ ; The two numbers can be found in the registers r9 and r10
+ mov r9, QWORD [FIRST_NUMBER] ; The first number
+ mov r10, QWORD [SECOND_NUMBER] ; The second number
+ PRINTF64 `%d\n\x0`, r9 ; print the first number
; DO NOT REMOVE/MODIFY THIS LINE
- PRINTF32 `%d\n\x0`, ebx ; print the second number
+ PRINTF64 `%d\n\x0`, r10 ; print the second number
; DO NOT REMOVE/MODIFY THIS LINE
- ; TODO: find the minimum of the two numbers and store it in eax
- PRINTF32 `%d\n\x0`, eax ; print the minimum
+ ; TODO: find the minimum of the two numbers and store it in r9
+ PRINTF64 `%d\n\x0`, r9 ; print the minimum
+ xor rax, rax
+ leave
ret
diff --git a/labs/lab-04/tasks/min/utils/printf32.asm b/labs/lab-04/tasks/min/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-04/tasks/min/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-04/tasks/min/utils/printf64.asm b/labs/lab-04/tasks/min/utils/printf64.asm
new file mode 100644
index 000000000..2bcf2712b
--- /dev/null
+++ b/labs/lab-04/tasks/min/utils/printf64.asm
@@ -0,0 +1,71 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-04/tasks/sets/README.md b/labs/lab-04/tasks/sets/README.md
index 88e07f053..3bd86ae94 100644
--- a/labs/lab-04/tasks/sets/README.md
+++ b/labs/lab-04/tasks/sets/README.md
@@ -7,11 +7,11 @@ nav_order: 3
You will solve the exercises starting from the `sets.asm` file located in the `tasks/sets` directory.
-You need to implement operations on sets that can contain elements between 0 and 31.
+You need to implement operations on sets that can contain elements between 0 and 63.
An efficient way to do this (both in terms of space and speed) would be to represent sets so that a register represents a set.
Each bit in the register represents an element in the set (if bit i is set, then the set contains element i).
-> **TIP**: For example: if `eax` contains the representation of the set `{0, 2, 4}`, the register value would be `2^0 + 2^2 + 2^4 = 1 + 4 + 16 = 21`.
+> **TIP**: For example: if `rax` contains the representation of the set `{0, 2, 4}`, the register value would be `2^0 + 2^2 + 2^4 = 1 + 4 + 16 = 21`.
> Educate yourself about the available instructions on the [x86 architecture](http://www.cs.virginia.edu/~evans/cs216/guides/x86.html).
- You have two defined sets.
@@ -19,23 +19,23 @@ What values do they contain?
You do not need to make the code print the actual values stored in the sets.
Perform the union of the two sets.
-- Use the `or` instruction to add two new elements to the first set (the set stored in the `eax` register).
+- Use the `or` instruction to add two new elements to the first set (the set stored in the `rax` register).
-> **NOTE**: Do not reset the `eax` register after this exercise.
+> **NOTE**: Do not reset the `rax` register after this exercise.
> Its new value will be the one used by the checker for further evaluation.
>
-> **TIP**: Take advantage of the fact that the current sets, although they have "space" for 32 bits, only use 8 bits.
+> **TIP**: Take advantage of the fact that the current sets, although they have "space" for 64 bits, only use 8 bits.
> If you `or` with a number greater than 255 (`0xff`, `2^8-1`) which has two active bits, you will effectively add two new elements to the set.
- Perform the intersection of the two sets.
-- Determine the elements missing from the `eax` set for it to be complete.
+- Determine the elements missing from the `rax` set for it to be complete.
> **TIP**: You need to take the complement of the number using the `not` instruction.
-- Remove an element from the first set (the set stored in the `eax` register).
+- Remove an element from the first set (the set stored in the `rax` register).
-> **NOTE**: Do not reset the `eax` register after this exercise.
+> **NOTE**: Do not reset the `rax` register after this exercise.
> Its new value will be the one used by the checker for further evaluation.
- Find the difference between the sets.
diff --git a/labs/lab-04/tasks/sets/solution/sets.asm b/labs/lab-04/tasks/sets/solution/sets.asm
index bf71668d0..f3b186e64 100644
--- a/labs/lab-04/tasks/sets/solution/sets.asm
+++ b/labs/lab-04/tasks/sets/solution/sets.asm
@@ -1,54 +1,59 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .data
- FIRST_SET: dd 139 ; The first set
- SECOND_SET: dd 169 ; The second set
+ FIRST_SET: dq 139 ; The first set
+ SECOND_SET: dq 169 ; The second set
section .text
global main
extern printf
main:
- ; The two sets can be found in the registers eax and ebx
- mov eax, DWORD [FIRST_SET]
- mov ebx, DWORD [SECOND_SET]
- PRINTF32 `%u\n\x0`, eax ; print the first set
- PRINTF32 `%u\n\x0`, ebx ; print the second set
+ push rbp
+ mov rbp, rsp
+
+ ; The two sets can be found in the registers rax and rbx
+ mov rax, QWORD [FIRST_SET]
+ mov rbx, QWORD [SECOND_SET]
+ PRINTF64 `%u\n\x0`, rax ; print the first set
+ PRINTF64 `%u\n\x0`, rbx ; print the second set
; TODO1: reunion of the two sets
- mov edx, eax
- or edx, ebx
- PRINTF32 `%u\n\x0`, edx
+ mov rdx, rax
+ or rdx, rbx
+ PRINTF64 `%u\n\x0`, rdx
; TODO2: adding an element to a set
- or eax, 0x300 ; We will add the elements 8 and 9 to the set
+ or rax, 0x300 ; We will add the elements 8 and 9 to the set
; 0x300 <==> ...11|0000|0000
- PRINTF32 `%u\n\x0`, eax
+ PRINTF64 `%u\n\x0`, rax
; TODO3: intersection of the two sets
- mov edx, eax
- and edx, ebx
- PRINTF32 `%u\n\x0`, edx
+ mov rdx, rax
+ and rdx, rbx
+ PRINTF64 `%u\n\x0`, rdx
; TODO4: the complement of a set
- mov edx, eax
- not edx
- PRINTF32 `%u\n\x0`, edx
+ mov rdx, rax
+ not rdx
+ PRINTF64 `%u\n\x0`, rdx
; TODO5: removal of an element from a set
; We will remove the 3rd element from the set
- mov edx, 1
- shl edx, 3
- not edx
- and eax, edx
- PRINTF32 `%u\n\x0`, eax
+ mov rdx, 1
+ shl rdx, 3
+ not rdx
+ and rax, rdx
+ PRINTF64 `%u\n\x0`, rax
; TODO6: difference of two sets
- not ebx
- and eax, ebx
- PRINTF32 `%u\n\x0`, eax
+ not rbx
+ and rax, rbx
+ PRINTF64 `%u\n\x0`, rax
+
+ xor rax, rax
- xor eax, eax
+ leave
ret
diff --git a/labs/lab-04/tasks/sets/support/Makefile b/labs/lab-04/tasks/sets/support/Makefile
index a4dfb815d..2b8bb3bb5 100644
--- a/labs/lab-04/tasks/sets/support/Makefile
+++ b/labs/lab-04/tasks/sets/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 ?= -no-pie
TARGET_EXEC = sets
diff --git a/labs/lab-04/tasks/sets/support/sets.asm b/labs/lab-04/tasks/sets/support/sets.asm
index 9485dee75..e034c29c0 100644
--- a/labs/lab-04/tasks/sets/support/sets.asm
+++ b/labs/lab-04/tasks/sets/support/sets.asm
@@ -1,21 +1,24 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .data
- FIRST_SET: dd 139 ; The first set
- SECOND_SET: dd 169 ; The second set
+ FIRST_SET: dq 139 ; The first set
+ SECOND_SET: dq 169 ; The second set
section .text
global main
extern printf
main:
+ push rbp
+ mov rbp, rsp
+
; The two sets can be found in the FIRST_SET and SECOND_SET variables
- mov eax, DWORD [FIRST_SET]
- mov ebx, DWORD [SECOND_SET]
- PRINTF32 `%u\n\x0`, eax ; print the first set
- PRINTF32 `%u\n\x0`, ebx ; print the second set
+ mov rax, QWORD [FIRST_SET]
+ mov rbx, QWORD [SECOND_SET]
+ PRINTF64 `%u\n\x0`, rax ; print the first set
+ PRINTF64 `%u\n\x0`, rbx ; print the second set
; TODO1: reunion of the two sets
@@ -34,6 +37,7 @@ main:
; TODO6: difference of two sets
+ xor rax, rax
- xor eax, eax
+ leave
ret
diff --git a/labs/lab-04/tasks/sets/utils/printf32.asm b/labs/lab-04/tasks/sets/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-04/tasks/sets/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-04/tasks/sets/utils/printf64.asm b/labs/lab-04/tasks/sets/utils/printf64.asm
new file mode 100644
index 000000000..2bcf2712b
--- /dev/null
+++ b/labs/lab-04/tasks/sets/utils/printf64.asm
@@ -0,0 +1,71 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-05/guides/addressing-arrays/README.md b/labs/lab-05/guides/addressing-arrays/README.md
index b20e0b65b..2a16647ba 100644
--- a/labs/lab-05/guides/addressing-arrays/README.md
+++ b/labs/lab-05/guides/addressing-arrays/README.md
@@ -9,5 +9,5 @@ To follow this guide, you'll need to use the `addressing_arrays.asm` file locate
The program increments the values of an array of 10 integers by 1 and iterates through the array before and after to show the changes.
-> **Note:** `ecx` is used as the loop counter.
+> **Note:** `rcx` is used as the loop counter.
Since the array contains `dwords` (4 bytes), the loop counter is multiplied by 4 to get the address of the next element in the array.
diff --git a/labs/lab-05/guides/addressing-arrays/support/Makefile b/labs/lab-05/guides/addressing-arrays/support/Makefile
index 290330081..5a7a42a8b 100644
--- a/labs/lab-05/guides/addressing-arrays/support/Makefile
+++ b/labs/lab-05/guides/addressing-arrays/support/Makefile
@@ -6,9 +6,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
TARGETS := $(OBJS:.o=)
diff --git a/labs/lab-05/guides/addressing-arrays/support/addressing_arrays.asm b/labs/lab-05/guides/addressing-arrays/support/addressing_arrays.asm
index 2f98ca9e4..9523cdff3 100644
--- a/labs/lab-05/guides/addressing-arrays/support/addressing_arrays.asm
+++ b/labs/lab-05/guides/addressing-arrays/support/addressing_arrays.asm
@@ -1,6 +1,6 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
%define ARRAY_SIZE 10
@@ -12,45 +12,46 @@ section .text
extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- xor eax, eax
+ xor rax, rax
- ; ecx - loop counter/array index, starting from 0
- ; [my_array + ecx*4] - since our array stores double-words (4 bytes)
- ; we multiply `ecx` by 4 to index the `ecx`-th element
- ; cmp ecx, ARRAY_SIZE - compare `ecx` with ARRAY_SIZE, sets EFLAGS accordingly
- ; jl for_print_before - `jl` instruction checks if `ecx` < ARRAY_SIZE (based on EFLAGS)
+ ; rcx - loop counter/array index, starting from 0
+ ; [my_array + rcx*4] - since our array stores double-words (4 bytes)
+ ; we multiply `rcx` by 4 to index the `rcx`-th element
+ ; cmp rcx, ARRAY_SIZE - compare `rcx` with ARRAY_SIZE, sets RFLAGS accordingly
+ ; jl for_print_before - `jl` instruction checks if `rcx` < ARRAY_SIZE (based on RFLAGS)
; and it jumps to the `for_print_before` label, otherwise it
; continues to the next instruction
; print out the array before incrementing its elements
- xor ecx, ecx
+ xor rcx, rcx
for_print_before:
- PRINTF32 `my_array[%d]: %d\n\x0`, ecx, [my_array + ecx*4]
- inc ecx
- cmp ecx, ARRAY_SIZE
+ mov rdx, [my_array + rcx*4] ; Load value into rdx for printing
+ PRINTF64 `my_array[%d]: %d\n\x0`, rcx, rdx
+ inc rcx
+ cmp rcx, ARRAY_SIZE
jl for_print_before
- PRINTF32 `\n\x0`
+ PRINTF64 `\n\x0`
; increment each element of the array
- xor ecx, ecx
+ xor rcx, rcx
for:
- inc dword [my_array + ecx*4]
- inc ecx
- cmp ecx, ARRAY_SIZE
+ inc dword [my_array + rcx*4]
+ inc rcx
+ cmp rcx, ARRAY_SIZE
jl for
; print out the array after incrementing its elements
- xor ecx, ecx
+ xor rcx, rcx
for_print_after:
- PRINTF32 `my_array[%d]: %d\n\x0`, ecx, [my_array + ecx*4]
- inc ecx
- cmp ecx, ARRAY_SIZE
+ mov rdx, [my_array + rcx*4] ; Load value into rdx for printing
+ PRINTF64 `my_array[%d]: %d\n\x0`, rcx, rdx
+ inc rcx
+ cmp rcx, ARRAY_SIZE
jl for_print_after
leave
ret
-
diff --git a/labs/lab-05/guides/addressing-arrays/utils/printf32.asm b/labs/lab-05/guides/addressing-arrays/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-05/guides/addressing-arrays/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-05/guides/addressing-arrays/utils/printf64.asm b/labs/lab-05/guides/addressing-arrays/utils/printf64.asm
new file mode 100644
index 000000000..2bcf2712b
--- /dev/null
+++ b/labs/lab-05/guides/addressing-arrays/utils/printf64.asm
@@ -0,0 +1,71 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-05/guides/declarations/support/Makefile b/labs/lab-05/guides/declarations/support/Makefile
index 290330081..5a7a42a8b 100644
--- a/labs/lab-05/guides/declarations/support/Makefile
+++ b/labs/lab-05/guides/declarations/support/Makefile
@@ -6,9 +6,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
TARGETS := $(OBJS:.o=)
diff --git a/labs/lab-05/guides/declarations/support/declarations.asm b/labs/lab-05/guides/declarations/support/declarations.asm
index fb00d7e58..017f9fc6f 100644
--- a/labs/lab-05/guides/declarations/support/declarations.asm
+++ b/labs/lab-05/guides/declarations/support/declarations.asm
@@ -1,6 +1,6 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
%define ARRAY_SIZE 13
%define DECIMAL_PLACES 5
@@ -25,9 +25,10 @@ section .data
decimal_point db ".",0
var db 64 ; Declare a byte with value 64
db 10 ; Declare a byte with value 10.
- ; This byte can be found at address (var + 1)
+ ; This byte can be found at address (var + 1)
Y dd 3000 ; Declare a double word (4 bytes)
Z dd 1, 2, 3 ; Declare a double word array
+ big_number dq 9000000000 ; Declare a quad word (8 bytes)
var5 equ 2
my_array times 3 db 8, 9, 10
@@ -36,15 +37,15 @@ section .text
extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- xor eax, eax
- mov ecx, ARRAY_SIZE
+ xor rax, rax
+ mov rcx, ARRAY_SIZE
mov al, [var]
- PRINTF32 `var: %d\n\x0`, eax
+ PRINTF64 `var: %d\n\x0`, rax
leave
ret
diff --git a/labs/lab-05/guides/declarations/utils/printf32.asm b/labs/lab-05/guides/declarations/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-05/guides/declarations/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-05/guides/declarations/utils/printf64.asm b/labs/lab-05/guides/declarations/utils/printf64.asm
new file mode 100644
index 000000000..2bcf2712b
--- /dev/null
+++ b/labs/lab-05/guides/declarations/utils/printf64.asm
@@ -0,0 +1,71 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-05/guides/floating-point-exception/support/Makefile b/labs/lab-05/guides/floating-point-exception/support/Makefile
index 43acbff58..01d412455 100644
--- a/labs/lab-05/guides/floating-point-exception/support/Makefile
+++ b/labs/lab-05/guides/floating-point-exception/support/Makefile
@@ -6,9 +6,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
TARGETS := $(OBJS:.o=)
diff --git a/labs/lab-05/guides/floating-point-exception/support/floating_point_exception.asm b/labs/lab-05/guides/floating-point-exception/support/floating_point_exception.asm
index 60a57d029..468eac6d6 100644
--- a/labs/lab-05/guides/floating-point-exception/support/floating_point_exception.asm
+++ b/labs/lab-05/guides/floating-point-exception/support/floating_point_exception.asm
@@ -1,34 +1,33 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .text
extern printf
global main
main:
- push ebp
- mov ebp, esp
- xor eax, eax
- xor ebx, ebx
+ push rbp
+ mov rbp, rsp
+ xor rax, rax
+ xor rbx, rbx
; using 8 bit unsigned division, the result/quotient needs to be in the range [0, 255]
; 22891 / 2 = 11445, thus we will have an overflow, causing a floating point exception
; Tip: 1) find out what is the minimum value for `bl` such that it does not overflow
- ; 2) change the register sizes such that the division does not overflow
+ ; 2) change the register sizes such that the division does not overflow
mov ax, 22891
mov bl, 2
div bl
; qutoient is stored in al
- PRINTF32 `Result is: %hhu\n\0`, eax
+ PRINTF64 `Result is: %hhu\n\0`, rax
; remainder is stored in ah, thus we need to shift it to the right by 8 bits
- shr eax, 8
- PRINTF32 `Result is: %hhu\n\0`, eax
+ shr rax, 8
+ PRINTF64 `Result is: %hhu\n\0`, rax
leave
ret
-
diff --git a/labs/lab-05/guides/floating-point-exception/utils/printf32.asm b/labs/lab-05/guides/floating-point-exception/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-05/guides/floating-point-exception/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-05/guides/floating-point-exception/utils/printf64.asm b/labs/lab-05/guides/floating-point-exception/utils/printf64.asm
new file mode 100644
index 000000000..2bcf2712b
--- /dev/null
+++ b/labs/lab-05/guides/floating-point-exception/utils/printf64.asm
@@ -0,0 +1,71 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-05/guides/loop/README.md b/labs/lab-05/guides/loop/README.md
index 50d204269..e918ca2ed 100644
--- a/labs/lab-05/guides/loop/README.md
+++ b/labs/lab-05/guides/loop/README.md
@@ -10,6 +10,6 @@ To follow this guide, you'll need to use the `loop.asm` file located in the `gui
This program illustrates how to use the `loop` instruction, as well as how to index an array of `dwords`.
>**Note**: The `loop` instruction jumps to the given label when the `count` register is not equal to 0.
-In the case of `x86` the `count` register is `ecx`.
+In the case of `x86` the `count` register is `rcx`.
>
>**Note**: For a detailed description of the `loop` instruction check out the [documentation](https://www.felixcloutier.com/x86/loop:loopcc).
diff --git a/labs/lab-05/guides/loop/support/Makefile b/labs/lab-05/guides/loop/support/Makefile
index 290330081..5a7a42a8b 100644
--- a/labs/lab-05/guides/loop/support/Makefile
+++ b/labs/lab-05/guides/loop/support/Makefile
@@ -6,9 +6,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
TARGETS := $(OBJS:.o=)
diff --git a/labs/lab-05/guides/loop/support/loop.asm b/labs/lab-05/guides/loop/support/loop.asm
index 782c8bac2..584ab2465 100644
--- a/labs/lab-05/guides/loop/support/loop.asm
+++ b/labs/lab-05/guides/loop/support/loop.asm
@@ -1,4 +1,4 @@
-%include "printf32.asm"
+%include "printf64.asm"
%define ARRAY_SIZE 9
; loop = loope
@@ -11,39 +11,40 @@ section .text
extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- xor eax, eax
+ xor rax, rax
; for simplicity, we display the array as it's starting from 1
- ; the true index is `ecx - 1`, one less then the one displayed
+ ; the true index is `rcx - 1`, one less then the one displayed
- ; ecx - loop counter
- ; [my_array + ecx*4 - 4] - the `-4` is required for
+ ; rcx - loop counter
+ ; [my_array + rcx*4 - 4] - the `-4` is required for
; indexing in the bounds of the array
; print the array before incrementing
- mov ecx, ARRAY_SIZE
+ mov rcx, ARRAY_SIZE
for_print_before:
- PRINTF32 `my_array[%d]: %d\n\x0`, ecx, [my_array + ecx*4 - 4]
+ mov rdx, rcx ; Move loop counter to rdx for printing
+ mov rsi, [my_array + rcx*4 - 4] ; Move array value to rsi for printing
+ PRINTF64 `my_array[%d]: %d\n\x0`, rdx, rsi
loop for_print_before
; increment all array elements except the first 3
- mov ecx, ARRAY_SIZE
+ mov rcx, ARRAY_SIZE
for:
- cmp ecx, 3
+ cmp rcx, 3
jle label1
- inc dword [my_array + ecx*4 - 4]
+ inc dword [my_array + rcx*4 - 4]
loop for
; print the array after incrementing
label1:
- mov ecx, ARRAY_SIZE
+ mov rcx, ARRAY_SIZE
for_print_after:
- PRINTF32 `my_array[%d]: %d\n\x0`, ecx, [my_array + ecx*4 - 4]
+ PRINTF64 `my_array[%d]: %d\n\x0`, rcx, qword [my_array + rcx*4 - 4]
loop for_print_after
leave
ret
-
diff --git a/labs/lab-05/guides/loop/utils/printf32.asm b/labs/lab-05/guides/loop/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-05/guides/loop/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-05/guides/loop/utils/printf64.asm b/labs/lab-05/guides/loop/utils/printf64.asm
new file mode 100644
index 000000000..2bcf2712b
--- /dev/null
+++ b/labs/lab-05/guides/loop/utils/printf64.asm
@@ -0,0 +1,71 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-05/guides/multiply-divide/support/Makefile b/labs/lab-05/guides/multiply-divide/support/Makefile
index 290330081..5a7a42a8b 100644
--- a/labs/lab-05/guides/multiply-divide/support/Makefile
+++ b/labs/lab-05/guides/multiply-divide/support/Makefile
@@ -6,9 +6,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
TARGETS := $(OBJS:.o=)
diff --git a/labs/lab-05/guides/multiply-divide/support/multiply_divide.asm b/labs/lab-05/guides/multiply-divide/support/multiply_divide.asm
index b9d9e318f..59ca7d714 100644
--- a/labs/lab-05/guides/multiply-divide/support/multiply_divide.asm
+++ b/labs/lab-05/guides/multiply-divide/support/multiply_divide.asm
@@ -1,36 +1,36 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .text
extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- ; edx:eax = eax * r/m32, where r/m32 is a 32-bit register or memory location
- mov eax, 10
- mov ebx, 30
- mul ebx
+ ; rdx:rax = rax * r/m64, where r/m64 is a 64-bit register or memory location
+ mov rax, 10
+ mov rbx, 30
+ mul rbx
- PRINTF32 `Result is: %u\n\x0`, eax
+ PRINTF64 `Result is: %u\n\x0`, rax
- ; make sure to always clear the edx register before performing a division
+ ; make sure to always clear the rdx register before performing a division
; there might be leftover data from previous operations
- xor edx, edx
+ xor rdx, rdx
- ; qutotient: eax = edx:eax / r/m32
- ; remainder: edx = edx:eax % r/m32
+ ; qutotient: rax = rdx:rax / r/m64
+ ; remainder: rdx = rdx:rax % r/m64
; both operations are performed at the same time, using the div instruction:w
- ; in this case the divisor is stored in ebx
- mov eax, 10
- mov ebx, 3
- div ebx
+ ; in this case the divisor is stored in rbx
+ mov rax, 10
+ mov rbx, 3
+ div rbx
- PRINTF32 `Quotient is: %u\n\x0`, eax
- PRINTF32 `Remainder is: %u\n\x0`, edx
+ PRINTF64 `Quotient is: %u\n\x0`, rax
+ PRINTF64 `Remainder is: %u\n\x0`, rdx
leave
ret
diff --git a/labs/lab-05/guides/multiply-divide/utils/printf32.asm b/labs/lab-05/guides/multiply-divide/utils/printf32.asm
deleted file mode 100644
index c32da02eb..000000000
--- a/labs/lab-05/guides/multiply-divide/utils/printf32.asm
+++ /dev/null
@@ -1,24 +0,0 @@
-;dSPDX-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-05/guides/multiply-divide/utils/printf64.asm b/labs/lab-05/guides/multiply-divide/utils/printf64.asm
new file mode 100644
index 000000000..2bcf2712b
--- /dev/null
+++ b/labs/lab-05/guides/multiply-divide/utils/printf64.asm
@@ -0,0 +1,71 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-05/media/registers-x86_64.svg b/labs/lab-05/media/registers-x86_64.svg
new file mode 100644
index 000000000..70d613824
--- /dev/null
+++ b/labs/lab-05/media/registers-x86_64.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/labs/lab-05/media/registers.svg b/labs/lab-05/media/registers.svg
deleted file mode 100644
index 62225e9fd..000000000
--- a/labs/lab-05/media/registers.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/labs/lab-05/reading/memory-addressing.md b/labs/lab-05/reading/memory-addressing.md
index ee2c2a9f2..5a3894d33 100644
--- a/labs/lab-05/reading/memory-addressing.md
+++ b/labs/lab-05/reading/memory-addressing.md
@@ -5,24 +5,24 @@ parent: Lab 5 - Registers and Memory Addressing
# Reading: Memory Addressing
-Modern x86 processors can address up to 2^32 bytes of memory, which means memory addresses are represented on 32 bits.
+Modern x86_64 processors can address up to 2^64 bytes of memory, which means memory addresses are represented on 64 bits.
To address memory, the processor uses addresses (implicitly, each label is translated into a corresponding memory address).
Besides labels, there are other forms of addressing memory:
```Assembly
-mov eax, [0xcafebab3] ; direct (displacement)
-mov eax, [esi] ; indirect (base)
-mov eax, [ebp-8] ; based (base + displacement)
-mov eax, [ebx*4 + 0xdeadbeef] ; indexed (index * scale + displacement)
-mov eax, [edx + ebx + 12] ; based and indexed without scale (base + index + displacement)
-mov eax, [edx + ebx*4 + 42] ; based and indexed with scale (base + index * scale + displacement)
+mov rax, [0xcafebabe12345678] ; direct (displacement)
+mov rax, [rsi] ; indirect (base)
+mov rax, [rbp-8] ; based (base + displacement)
+mov rax, [rbx*4 + 0xdeadbeef] ; indexed (index * scale + displacement)
+mov rax, [rdx + rbx + 12] ; based and indexed without scale (base + index + displacement)
+mov rax, [rdx + r8*4 + 42] ; based and indexed with scale (base + index * scale + displacement)
```
> **WARNING**: The following addressing modes are invalid:
>
> ```Assembly
->mov eax, [ebx-ecx] ; Registers can only be added
->mov [eax+esi+edi], ebx ; The address calculation can involve at most 2 registers
+>mov rax, [rbx-rcx] ; Registers can only be added
+>mov [rax+rsi+rdi], rbx ; The address calculation can involve at most 2 registers
> ```
## Size Directives
@@ -32,42 +32,44 @@ For example, in the above addressing modes, the size of the values could be infe
Let's consider the following instruction:
```Assembly
-mov [ebx], 2
+mov [rbx], 2
```
-As seen, it intends to store the value 2 at the address contained in the `ebx` register.
-The size of the register is 4 bytes.
-The value 2 can be represented on both 1 and 4 bytes.
-In this case, since both interpretations are valid, the processor needs additional information on how to treat this value.
+As seen, it intends to store the value 2 at the address contained in the `rbx` register.
+The size of the register is 8 bytes.
+The value 2 can be represented on 1, 2, 4, or 8 bytes.
+In this case, since multiple interpretations are valid, the processor needs additional information on how to treat this value.
This can be done through size directives:
```Assembly
-mov byte [ebx], 2 ; Move the value 2 into the byte at the address contained in ebx.
-mov word [ebx], 2 ; Move the entire 2 represented in 16 bits into the 2 bytes
- ; starting from the address contained in ebx.
-mov dword [ebx], 2 ; Move the entire 2 represented in 32 bits into the 4 bytes
- ; starting from the address contained in ebx.
+mov byte [rbx], 2 ; Move the value 2 into the byte at the address contained in rbx.
+mov word [rbx], 2 ; Move the entire 2 represented in 16 bits into the 2 bytes
+ ; starting from the address contained in rbx.
+mov dword [rbx], 2 ; Move the entire 2 represented in 32 bits into the 4 bytes
+ ; starting from the address contained in rbx.
+mov qword [rbx], 2 ; Move the entire 2 represented in 64 bits into the 8 bytes
+ ; starting from the address contained in rbx.
```
## Loop Instruction
-The loop instruction is used for loops with a predetermined number of iterations, loaded into the `ecx` register.
+The loop instruction is used for loops with a predetermined number of iterations, loaded into the `rcx` register.
Its syntax is as follows:
```Assembly
-mov ecx, 10 ; Initialize ecx with the number of iterations
+mov rcx, 10 ; Initialize rcx with the number of iterations
label:
; loop content
loop label
```
-At each iteration, the `ecx` register is decremented, and if it's not equal to 0, the execution jumps to the specified label.
+At each iteration, the `rcx` register is decremented, and if it's not equal to 0, the execution jumps to the specified label.
There are other forms of the instruction that additionally check the `ZF` flag:
Mnemonic | Description
--------------------- | -----------
-`loope/loopz label` | Decrement `ecx`, jump to label if `ecx != 0` and `ZF == 1`
-`loopne/loopnz label` | Decrement `ecx`, jump to label if `ecx != 0` and `ZF != 1`
+`loope/loopz label` | Decrement `rcx`, jump to label if `rcx != 0` and `ZF == 1`
+`loopne/loopnz label` | Decrement `rcx`, jump to label if `rcx != 0` and `ZF != 1`
> **NOTE**: When using jumps in an assembly language program, it's important to consider the difference between a `short jump` (near jump) and a `long jump` (far jump).
>
diff --git a/labs/lab-05/reading/registers.md b/labs/lab-05/reading/registers.md
index 50d5a0ed2..8f097d4d5 100644
--- a/labs/lab-05/reading/registers.md
+++ b/labs/lab-05/reading/registers.md
@@ -8,20 +8,20 @@ parent: Lab 5 - Registers and Memory Addressing
Registers are the primary "tools" used to write programs in assembly language.
They are like variables built into the processor.
Using registers instead of direct memory addressing makes developing and reading assembly-written programs faster and easier.
-The only disadvantage of programming in x86 assembly language is that there are few registers.
-Modern x86 processors have 8 general-purpose registers whose size is 32 bits.
-The names of the registers are of historical nature (for example: `eax` was called the accumulator register because it is used by a series of arithmetic instructions, such as [idiv](https://www.felixcloutier.com/x86/idiv)).
-While most registers have lost their special purpose, becoming "general purpose" in the modern ISA (`eax`, `ebx`, `ecx`, `edx`, `esi`, `edi`), by convention, 2 have retained their initial purpose: `esp` (stack pointer) and `ebp` (base pointer).
+Modern x86_64 processors have 16 general-purpose registers whose size is 64 bits.
+Some of these are just extensions of the original 32-bit registers, while others are newly added (`r8` to `r15`).
+The names of the registers are of historical nature (for example: `rax`'s ancestor, `eax`, was called the accumulator register because it is used by a series of arithmetic instructions, such as [idiv](https://www.felixcloutier.com/x86/idiv)).
+While most registers have lost their special purpose, becoming "general purpose" in the modern ISA (`rax`, `rbx`, `rcx`, `rdx`, `rsi`, `rdi`, `rsp`, `rbp`), by convention, 2 have retained their initial purpose: `rsp` (stack pointer) and `rbp` (base pointer).
## Register Subsections
-In certain cases, we want to manipulate values that are represented in less than 4 bytes (for example, working with character strings).
-For these situations, x86 processors offer us the possibility to work with subsections of 1 and 2 bytes of the `eax`, `ebx`, `ecx`, `edx` registers.
+In certain cases, we want to manipulate values that are represented in less than 8 bytes.
+For these situations, x86_64 processors offer us the possibility to work with subsections of the registers.
The image below represents the registers, their subsections, and their sizes.
-
+
>**WARNING**: Subsections are part of registers, which means that if we modify a register, we implicitly modify the value of the subsection.
>
@@ -33,36 +33,42 @@ The image below represents the registers, their subsections, and their sizes.
## Static Memory Region Declarations
-Static memory declarations (analogous to declaring global variables) in the x86 world are made through special assembly directives.
+Static memory declarations (analogous to declaring global variables) in the x86_64 world are made through special assembly directives.
These declarations are made in the data section (the `.data` region).
Names can be attached to the declared memory portions through a label to easily reference them later in the program. Follow the example below:
```Assembly
.DATA
- var `db` 64 ; Declares a byte containing the value 64. Labels
- ; the memory location as "var".
- var2 `db` ? ; Declares an uninitialized byte labeled "var2".
- `db` 10 ; Declares an unlabeled byte, initialized with 10. This
- ; byte will be placed at the address (var2 + 1).
- X `dw` ? ; Declares an uninitialized word (2 bytes), labeled "X".
- Y `dd` 3000 ; Declares a double word (4 bytes) labeled "Y",
- ; initialized with the value 3000.
- Z `dd` 1,2,3 ; Declares 3 double words (each 4 bytes)
- ; starting from address "Z" and initialized with 1, 2, and 3, respectively.
- ; For example, 3 will be placed at the address (Z + 8).
+ var db 64 ; Declares a byte containing the value 64. Labels
+ ; the memory location as "var".
+ var2 db ? ; Declares an uninitialized byte labeled "var2".
+ db 10 ; Declares an unlabeled byte, initialized with 10. This
+ ; byte will be placed at the address (var2 + 1).
+ X dw ? ; Declares an uninitialized word (2 bytes), labeled "X".
+ Y dd 3000 ; Declares a double word (4 bytes) labeled "Y",
+ ; initialized with the value 3000.
+ Z dq 4294967297 ; Declares a quad word (8 bytes) labeled "Z",
+ ; initialized with the value 4294967297 (2^32 + 1).
+ ARR dd 1,2,3 ; Declares 3 double words (each 4 bytes)
+ ; starting from address "ARR" and initialized with 1, 2, and 3, respectively.
+ ; For example, 3 will be placed at the address (ARR + 8).
+ ARR64 dq 1,2,3 ; Declares 3 quad words (each 8 bytes)
+ ; starting from address "ARR64" and initialized with 1, 2, and 3, respectively.
+ ; For example, 3 will be placed at the address (ARR64 + 16).
```
-> **NOTE**: DB, DW, DD are directives used to specify the size of the portion:
+> **NOTE**: DB, DW, DD, DQ are directives used to specify the size of the portion:
>
> Directive | Role | Size
> ----------- | ------------------ | ----
-> `db` | Define Byte | 1 bytes (8 bits)
+> `db` | Define Byte | 1 byte (8 bits)
> `dw` | Define Word | 2 bytes (16 bits)
> `dd` | Define Double Word | 4 bytes (32 bits)
+> `dq` | Define Quad Word | 8 bytes (64 bits)
>
> **NOTE**: There are multiple types of memory regions as can be seen in the image below:
>
> 
-The last declaration in the above example represents the declaration of an array.
+The last declarations in the above example represent the declaration of arrays.
Unlike higher-level languages, where arrays can have multiple dimensions and their elements are accessed by indices, in assembly language, arrays are represented as a number of cells located in a contiguous area of memory.
diff --git a/labs/lab-05/tasks/div/README.md b/labs/lab-05/tasks/div/README.md
index 2812d9470..040d6d814 100644
--- a/labs/lab-05/tasks/div/README.md
+++ b/labs/lab-05/tasks/div/README.md
@@ -5,37 +5,46 @@ parent: Lab 5 - Registers and Memory Addressing
# Task: Division of Two Numbers
-You will solve this exercise starting from the `divide.asm` file located in the `tasks/div/support` directory.
+You will solve this exercise starting from the `divide_64.asm` file located in the `tasks/div/support` directory.
-In the `divide.asm` program, the quotient and remainder of two numbers represented as bytes are calculated.
-Update the area marked with `TODO` to perform divisions `dividend2 / divisor2` (word-type divisor) and `dividend3 / divisor3` (dword-type divisor).
+In the `divide.asm` program, you'll implement division operations for various data sizes.
+Update the area marked with `TODO` in the code to perform the division of the numbers mentioned in the comments.
Similar to the `mul` instruction, the registers where the dividend is placed vary depending on the representation size of the divisor.
The divisor is passed as an argument to the `div` mnemonic.
-> **TIP**: If the divisor is of type `byte` (8 bits), the components are arranged as follows:
+> **TIP**: The division operation works as follows for different sizes:
>
-> - the dividend is placed in the `ax` register
-> - the argument of the `div` instruction is 8 bits and can be represented by a register or an immediate value
-> - the quotient is placed in `al`
-> - the remainder is placed in `ah`
+> **For byte (8-bit) division:**
>
-> If the divisor is of type `word` (16 bits), the components are arranged as follows:
+> - The dividend is placed in the `ax` register
+> - The divisor is 8 bits (e.g., `bl`)
+> - The quotient is placed in `al`
+> - The remainder is placed in `ah`
>
-> - the dividend is arranged in the `dx:ax` pair, meaning its `high` part is in the `dx` register, and the `low` part is in `ax`
-> - the argument of the `div` instruction is 16 bits and can be represented by a register or an immediate value
-> - the quotient is placed in `ax`
-> - the remainder is placed in `dx`
+> **For word (16-bit) division:**
>
-> If the divisor is of type `dword` (32 bits), the components are arranged as follows:
+> - The dividend is arranged in the `dx:ax` pair (high part in `dx`, low part in `ax`)
+> - The divisor is 16 bits (e.g., `bx`)
+> - The quotient is placed in `ax`
+> - The remainder is placed in `dx`
>
-> - the dividend is arranged in the `edx:eax` pair, meaning its `high` part is in the `edx` register, and the `low` part is in `eax`
-> - the argument of the `div` instruction is 32 bits and can be represented by a register or an immediate value
-> - the quotient is placed in `eax`
-> - the remainder is placed in `edx`
+> **For double word (32-bit) division:**
+>
+> - The dividend is arranged in the `edx:eax` pair (high part in `edx`, low part in `eax`)
+> - The divisor is 32 bits (e.g., `ebx`)
+> - The quotient is placed in `eax`
+> - The remainder is placed in `edx`
+>
+> **For quad word (64-bit) division:**
+>
+> - The dividend is arranged in the `rdx:rax` pair (high part in `rdx`, low part in `rax`)
+> - The divisor is 64 bits (e.g., `rbx`)
+> - The quotient is placed in `rax`
+> - The remainder is placed in `rdx`
>
> **TIP**: If the program gives you a `SIGFPE`.
-Arithmetic exception," you most likely forgot to initialize the upper part of the dividend (`ah`, `dx`, or `edx`).
+Arithmetic exception," you most likely forgot to initialize the upper part of the dividend (`ah`, `dx`, `edx`, `rdx`).
## Testing
@@ -48,9 +57,10 @@ make check
In case of a correct solution, you will get an output such as:
```text
-test_first_div ........................ passed ... 33
-test_second_div ........................ passed ... 33
-test_third_div ........................ passed ... 34
+test_first_div ........................ passed ... 25
+test_second_div ........................ passed ... 25
+test_third_div ........................ passed ... 25
+test_fourth_div ........................ passed ... 25
========================================================================
diff --git a/labs/lab-05/tasks/div/solution/divide.asm b/labs/lab-05/tasks/div/solution/divide.asm
index 4b6c56e78..501086829 100644
--- a/labs/lab-05/tasks/div/solution/divide.asm
+++ b/labs/lab-05/tasks/div/solution/divide.asm
@@ -1,6 +1,6 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
; https://en.wikibooks.org/wiki/X86_Assembly/Arithmetic
@@ -10,49 +10,60 @@ section .data
dividend2 dd 67254
divisor2 dw 1349
dividend3 dq 69094148
- divisor3 dd 87621
+ divisor3 dq 12345678
+ dividend4 dq 0x00000000FFFFFFFF, 0x0000000000000000
+ divisor4 dq 0x0000000000010000
section .text
extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- xor eax, eax
+ xor rax, rax
mov al, byte [dividend1]
mov bl, byte [divisor1]
div bl
- xor ebx, ebx
+ xor rbx, rbx
mov bl, al
- PRINTF32 `Quotient: %hhu\n\x0`, ebx
+ PRINTF64 `Quotient: %hhu\n\x0`, rbx
- xor ebx, ebx
+ xor rbx, rbx
mov bl, ah
- PRINTF32 `Remainder: %hhu\n\x0`, ebx
+ PRINTF64 `Remainder: %hhu\n\x0`, rbx
- mov edx, [dividend2]
- mov ax, dx
- shr edx, 16
+ xor rdx, rdx
+ mov eax, dword [dividend2]
+ mov dx, ax
+ shr eax, 16
+ xchg ax, dx
mov bx, word [divisor2]
div bx
- xor ebx, ebx
+ xor rbx, rbx
mov bx, ax
- PRINTF32 `Quotient: %hu\n\x0`, ebx
+ PRINTF64 `Quotient: %hu\n\x0`, rbx
- xor ebx, ebx
+ xor rbx, rbx
mov bx, dx
- PRINTF32 `Remainder: %hu\n\x0`, ebx
+ PRINTF64 `Remainder: %hu\n\x0`, rbx
- mov eax, dword [dividend3]
- mov edx, dword [dividend3 + 4]
+ mov rax, qword [dividend3]
+ xor rdx, rdx
mov ebx, dword [divisor3]
div ebx
- PRINTF32 `Quotient: %u\nRemainder: %u\n\x0`, eax, edx
+ PRINTF64 `Quotient: %lu\nRemainder: %lu\n\x0`, rax, rdx
+
+ mov rax, qword [dividend4]
+ mov rdx, qword [dividend4 + 8]
+ mov rbx, qword [divisor4]
+ div rbx
+
+ PRINTF64 `Quotient: 0x%lx\nRemainder: 0x%lx\n\x0`, rax, rdx
leave
- ret
+ ret
\ No newline at end of file
diff --git a/labs/lab-05/tasks/div/support/Makefile b/labs/lab-05/tasks/div/support/Makefile
index 290330081..5a7a42a8b 100644
--- a/labs/lab-05/tasks/div/support/Makefile
+++ b/labs/lab-05/tasks/div/support/Makefile
@@ -6,9 +6,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
TARGETS := $(OBJS:.o=)
diff --git a/labs/lab-05/tasks/div/tests/test.sh b/labs/lab-05/tasks/div/tests/test.sh
index 7820ef45d..cf9e74f1f 100755
--- a/labs/lab-05/tasks/div/tests/test.sh
+++ b/labs/lab-05/tasks/div/tests/test.sh
@@ -17,6 +17,10 @@ remainder2=$(echo "$OUTPUT" | grep "Remainder:" | sed -n '2p' | awk '{print $2}'
quotient3=$(echo "$OUTPUT" | grep "Quotient:" | sed -n '3p' | awk '{print $2}')
remainder3=$(echo "$OUTPUT" | grep "Remainder:" | sed -n '3p' | awk '{print $2}')
+quotient4=$(echo "$OUTPUT" | grep "Quotient:" | sed -n '4p' | awk '{print $2}')
+remainder4=$(echo "$OUTPUT" | grep "Remainder:" | sed -n '4p' | awk '{print $2}')
+
+
test_first_div() {
if [[ $quotient1 -eq 3 && $remainder1 -eq 10 ]]; then
exit 0
@@ -34,7 +38,15 @@ test_second_div() {
}
test_third_div() {
- if [[ $quotient3 -eq 788 && $remainder3 -eq 48800 ]]; then
+ if [[ $quotient3 -eq 5 && $remainder3 -eq 7365758 ]]; then
+ exit 0
+ else
+ exit 1
+ fi
+}
+
+test_fourth_div() {
+ if [[ $quotient4 -eq 0xffff && $remainder4 -eq 0xffff ]]; then
exit 0
else
exit 1
@@ -42,9 +54,9 @@ test_third_div() {
}
run_tests() {
- local tests=(test_first_div test_second_div test_third_div)
- local scores=(33 33 34)
- for i in {0..2}; do
+ local tests=(test_first_div test_second_div test_third_div test_fourth_div)
+ local scores=(25 25 25 25)
+ for i in {0..3}; do
run_test "${tests[i]}" "${scores[i]}"
done
}
diff --git a/labs/lab-05/tasks/div/utils/printf32.asm b/labs/lab-05/tasks/div/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-05/tasks/div/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-05/tasks/div/utils/printf64.asm b/labs/lab-05/tasks/div/utils/printf64.asm
new file mode 100644
index 000000000..2bcf2712b
--- /dev/null
+++ b/labs/lab-05/tasks/div/utils/printf64.asm
@@ -0,0 +1,71 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-05/tasks/mul/README.md b/labs/lab-05/tasks/mul/README.md
index 7c752f1a5..924da514e 100644
--- a/labs/lab-05/tasks/mul/README.md
+++ b/labs/lab-05/tasks/mul/README.md
@@ -5,7 +5,7 @@ parent: Lab 5 - Registers and Memory Addressing
# Task: Multiplying Two Numbers
-## Multiplying Two Numbers represented as Bytes
+## Multiplying Two Numbers of Different Sizes
You will solve this exercise starting from the `multiply.asm` file located in the `tasks/mul/support` directory.
@@ -19,30 +19,47 @@ When performing multiplication, the process is as follows, as described [here](h
- if we're operating on a byte (8 bits, one byte), we place the multiplicand in the `al` register;
- if we're operating on a word (16 bits, 2 bytes), we place the multiplicand in the `ax` register;
- if we're operating on a double word (32 bits, 4 bytes), we place the multiplicand in the `eax` register.
+ - if we're operating on a quad word (64 bits, 8 bytes), we place the multiplicand in the `rax` register.
1. The multiplier is passed as an argument to the `mul` mnemonic.
The multiplier must have the same size as the multiplicand.
1. The result is placed in two registers (the high part and the low part).
-## Multiplying Two Numbers represented as Words / Double Words
+## Implementing Multiplication for Different Data Types
-Update the area marked with `TODO` in the file `multiply.asm` to allow multiplication of `word` and `dword` numbers, namely `num1_dw` with `num2_dw`, and `num1_dd` with `num2_dd`.
+The file `multiply.asm` already contains the code for multiplying bytes.
+Update the area marked with `TODO` to implement multiplication for word (16-bit), double word (32-bit), and quad word (64-bit) numbers.
-> **TIP**: For multiplying word numbers (16 bits), the components are arranged as follows:
+You'll need to multiply:
+
+- `num1_w` with `num2_w` (word)
+- `num1_d` with `num2_d` (double word)
+- `num1_q` with `num2_q` (quad word)
+
+> **TIP**: For each data type, the components are arranged as follows:
+>
+> **For word (16-bit) multiplication:**
>
> - Place the multiplicand in the `ax` register.
-> - The argument of the `mul` instruction, the multiplier (possibly another register), is 16 bits (either a value or a register such as `bx`, `cx`, `dx`).
-> - The result of the multiplication is arranged in the pair `dx:ax`, where the high part of the result is in the `dx` register, and the low part of the result is in the `ax` register.
+> - The multiplier should be 16 bits (e.g., `bx`).
+> - The result will be in `dx:ax` (high part in `dx`, low part in `ax`).
>
-> For multiplying `dword` numbers (32 bits), the components are arranged as follows:
+> **For double word (32-bit) multiplication:**
>
> - Place the multiplicand in the `eax` register.
-> - The argument of the `mul` instruction, the multiplier (possibly another register), is 32 bits (either a value or a register such as `ebx`, `ecx`, `edx`).
-> - The result of the multiplication is arranged in the pair `edx:eax`, where the high part of the result is in the `edx` register, and the low part of the result is in the `eax` register.
+> - The multiplier should be 32 bits (e.g., `ebx`).
+> - The result will be in `edx:eax` (high part in `edx`, low part in `eax`).
+>
+> **For quad word (64-bit) multiplication:**
+>
+> - Place the multiplicand in the `rax` register.
+> - The multiplier should be 64 bits (e.g., `rbx`).
+> - The result will be in `rdx:rax` (high part in `rdx`, low part in `rax`).
>
-> **NOTE**: When displaying the result, use the `PRINTF32` macro to display the two registers containing the result:
+> **NOTE**: When displaying the results, use the appropriate format specifiers with the PRINTF64 macro:
>
-> - Registers `dx` and `ax` for multiplying word numbers.
-> - Registers `edx` and `eax` for multiplying dword numbers.
+> - For word multiplication: `PRINTF64 \`Result is: 0x%hx%hx\n\x0\`, rdx, rax`
+> - For double word multiplication: `PRINTF64 \`Result is: 0x%x%x\n\x0\`, rdx, rax`
+> - For quad word multiplication: `PRINTF64 \`Result is: 0x%lx%016lx\n\x0\`, rdx, rax`
## Testing
@@ -55,9 +72,10 @@ make check
In case of a correct solution, you will get an output such as:
```text
-test_byte_mul ........................ passed ... 33
-test_short_mul ........................ passed ... 33
-test_int_mul ........................ passed ... 34
+test_byte_mul ........................ passed ... 25
+test_short_mul ........................ passed ... 25
+test_int_mul ........................ passed ... 25
+test_long_mul ........................ passed ... 25
========================================================================
diff --git a/labs/lab-05/tasks/mul/solution/multiply.asm b/labs/lab-05/tasks/mul/solution/multiply.asm
index 81728ce83..5eb30d77e 100644
--- a/labs/lab-05/tasks/mul/solution/multiply.asm
+++ b/labs/lab-05/tasks/mul/solution/multiply.asm
@@ -1,6 +1,6 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
; https://en.wikibooks.org/wiki/X86_Assembly/Arithmetic
@@ -11,13 +11,15 @@ section .data
num2_w dw 9949
num1_d dd 134932
num2_d dd 994912
+ num1_q dq 9223372036854775800
+ num2_q dq 12345678
section .text
extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
; Multiplication for db
mov al, byte [num1]
@@ -26,9 +28,9 @@ main:
; Print result in hexa
; NOTE: The `%hx` format specifier tells printf to print only the lower half
- ; (lower 16 bits) of eax - i.e., the ax register - by treating the value as
+ ; (lower 16 bits) of rax - i.e., the ax register - by treating the value as
; a 16-bit unsigned short.
- PRINTF32 `Result is: 0x%hx\n\x0`, eax
+ PRINTF64 `Result is: 0x%hx\n\x0`, rax
; Multiplication for dw
@@ -38,8 +40,8 @@ main:
; Print result in hexa
; NOTE: The `%hx` format specifier is used in the same way as in the
- ; previous PRINTF32 statement, only now for both dx and ax registers
- PRINTF32 `Result is: 0x%hx%hx\n\x0`, edx, eax
+ ; previous PRINTF64 statement, only now for both dx and ax registers
+ PRINTF64 `Result is: 0x%hx%hx\n\x0`, rdx, rax
; Multiplication for dd
@@ -48,7 +50,18 @@ main:
mul ebx
; Print result in hexa
- PRINTF32 `Result is: 0x%x%x\n\x0`, edx, eax
+ PRINTF64 `Result is: 0x%x%x\n\x0`, rdx, rax
+
+
+ ; Multiplication for dq
+ mov rax, qword [num1_q]
+ mov rbx, qword [num2_q]
+ mul rbx
+
+ ; Print result in hexa
+ ; NOTE: For 64-bit multiplication, the 128-bit result is stored in rdx:rax
+ ; We use %lx format specifier for 64-bit long values
+ PRINTF64 `Result is: 0x%lx%016lx\n\x0`, rdx, rax
leave
- ret
+ ret
\ No newline at end of file
diff --git a/labs/lab-05/tasks/mul/support/Makefile b/labs/lab-05/tasks/mul/support/Makefile
index 43acbff58..01d412455 100644
--- a/labs/lab-05/tasks/mul/support/Makefile
+++ b/labs/lab-05/tasks/mul/support/Makefile
@@ -6,9 +6,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
TARGETS := $(OBJS:.o=)
diff --git a/labs/lab-05/tasks/mul/support/multiply.asm b/labs/lab-05/tasks/mul/support/multiply.asm
index e70455c18..4948cf412 100644
--- a/labs/lab-05/tasks/mul/support/multiply.asm
+++ b/labs/lab-05/tasks/mul/support/multiply.asm
@@ -1,6 +1,6 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
; https://en.wikibooks.org/wiki/X86_Assembly/Arithmetic
@@ -11,13 +11,15 @@ section .data
num2_w dw 9949
num1_d dd 134932
num2_d dd 994912
+ num1_q dq 9223372036854775800
+ num2_q dq 12345678
section .text
extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
; Multiplication for db
mov al, byte [num1]
@@ -25,10 +27,11 @@ main:
mul bl
; Print result in hexa
- PRINTF32 `Result is: 0x%hx\n\x0`, eax
+ PRINTF64 `Result is: 0x%hx\n\x0`, rax
- ; TODO: Implement multiplication for dw and dd data types.
+ ; TODO: Implement multiplication for dw, dd and dq data types.
+
leave
ret
diff --git a/labs/lab-05/tasks/mul/tests/test.sh b/labs/lab-05/tasks/mul/tests/test.sh
index e593c804b..420223996 100755
--- a/labs/lab-05/tasks/mul/tests/test.sh
+++ b/labs/lab-05/tasks/mul/tests/test.sh
@@ -11,6 +11,7 @@ OUTPUT=$($binary)
result1=$(echo "$OUTPUT" | grep "R" | sed -n '1p' | awk '{print $3}')
result2=$(echo "$OUTPUT" | grep "R" | sed -n '2p' | awk '{print $3}')
result3=$(echo "$OUTPUT" | grep "R" | sed -n '3p' | awk '{print $3}')
+result4=$(echo "$OUTPUT" | grep "R" | sed -n '4p' | awk '{print $3}')
test_byte_mul() {
if [[ -z "$result1" ]]; then
@@ -48,10 +49,22 @@ test_int_mul() {
fi
}
+test_long_mul() {
+ if [[ -z "$result4" ]]; then
+ exit 1
+ fi
+
+ if [[ $result4 -eq $((0x5e30a6fffffffffa1cf590)) ]]; then
+ exit 0
+ else
+ exit 1
+ fi
+}
+
run_tests() {
- local tests=(test_byte_mul test_short_mul test_int_mul)
- local scores=(33 33 34)
- for i in {0..2}; do
+ local tests=(test_byte_mul test_short_mul test_int_mul test_long_mul)
+ local scores=(25 25 25 25)
+ for i in {0..3}; do
run_test "${tests[i]}" "${scores[i]}"
done
}
diff --git a/labs/lab-05/tasks/mul/utils/printf32.asm b/labs/lab-05/tasks/mul/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-05/tasks/mul/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-05/tasks/mul/utils/printf64.asm b/labs/lab-05/tasks/mul/utils/printf64.asm
new file mode 100644
index 000000000..2bcf2712b
--- /dev/null
+++ b/labs/lab-05/tasks/mul/utils/printf64.asm
@@ -0,0 +1,71 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-05/tasks/sum-array/README.md b/labs/lab-05/tasks/sum-array/README.md
index 3726ada70..747deaa81 100644
--- a/labs/lab-05/tasks/sum-array/README.md
+++ b/labs/lab-05/tasks/sum-array/README.md
@@ -7,20 +7,23 @@ parent: Lab 5 - Registers and Memory Addressing
## Introduction
-You will solve this exercise starting from the `sum-array.asm` file located in the `tasks/sum-array/support` directory.
+You will solve this exercise starting from the `sum_array.asm` file located in the `tasks/sum-array/support` directory.
-In the `sum-array.asm` file the sum of elements in an array of bytes (8-bit representation) is calculated.
+In the `sum_array.asm` file, the sum of elements in arrays of different data types is calculated.
-Follow the code, observe the constructions and registers specific for working with bytes.
+Follow the code, observe the constructions and registers specific for working with different data types in 64-bit mode.
Run the code.
> **IMPORTANT**: Proceed to the next step only after thoroughly understanding what the code does.
It will be difficult for you to complete the following exercises if you have difficulty understanding the current exercise.
-## Sum of Elements in an Array of types word and dword
+## Working with Arrays of Different Sizes
-In the `TODO` section of the `sum-array.asm` file, complete the code to calculate the sum of arrays with elements of type word (16 bits) and dword (32 bits);
-namely, the `word_array` and `dword_array`.
+In the `TODO` section of the `sum-array.asm` file, complete the code to calculate the sum of:
+
+1. `word_array` (16-bit elements)
+1. `dword_array` (32-bit elements)
+1. `qword_array` (64-bit elements)
> **TIP**: When calculating the address of an element in an array, you will use a construction like:
>
@@ -28,39 +31,31 @@ namely, the `word_array` and `dword_array`.
>
> In the construction above:
>
-> - base is the address of the array (i.e., `word_array` or `dword_array`)
+> - base is the address of the array (i.e., `word_array`, `dword_array` etc.)
> - size is the length of the array element (i.e., 2 for a word array (16 bits, 2 bytes) and 4 for a dword array (32 bits, 4 bytes))
> - index is the current index within the array
>
-> **NOTE**: The sum of elements in the three arrays should be:
+> **NOTE**: The expected sums for each array are:
>
> - `sum(byte_array): 575`
> - `sum(word_array): 65799`
-> - `sum(dword_array): 74758117`
-
-## Sum of Squares of Elements in an Array
+> - `sum(dword_array): 140975`
+> - `sum(qword_array): 49782475293`
-Starting from the program in the previous exercise, calculate the sum of squares of elements in an array.
+## 128-bit Addition Exercise
-> **NOTE**: You can use the `dword_array2` array, ensuring that the sum of squares of the contained elements can be represented in 32 bits.
->
-> **NOTE**: If you use the construction below (array with 10 elements)
->
-> ```Assembly
-> dword_array dd 1392, 12544, 7992, 6992, 7202, 27187, 28789, 17897, 12988, 17992
-> ```
->
-> the sum of squares will be 2704560839.
+The final part of this lab requires you to implement a 128-bit addition operation.
-## 64 Bits Sum of Squares
+You need to add three very large 64-bit values stored in the `big_qword_array`:
-Compute the sum of squares of the elements from `big_numbers_array`.
+```assembly
+big_qword_array dq 9223372036854775800, 8223372036854775800, 7223372036854775800
+```
-> **NOTE**: The sum of the array can be represented on 64 bits, but we only have 32 bits registers.
+> **NOTE**: When adding these values, the sum will exceed the capacity of a single 64-bit register (rax).
+> You will also have to track and handle the carry bits.
>
-> **HINT**: Split the sum in 2 variables (the mul operator for 32 bits multiplication).
->
-> the sum of squares will be 1610691026282151079.
+> **NOTE**: The expected result of adding these three values is: `0x1565ddbe509d3ffe8`.
## Testing
@@ -73,14 +68,16 @@ make check
In case of a correct solution, you will get an output such as:
```text
-first_test ........................ passed ... 20
-second_test ........................ passed ... 20
-third_test ........................ passed ... 30
-fourth_test ........................ passed ... 30
+word_sum_test ........................ passed ... 20
+dword_sum_test ........................ passed ... 20
+qword_sum_test ........................ passed ... 30
+big_sum_test ........................ passed ... 30
========================================================================
Total: 100/100
```
+## Additional Resources
+
If you're having difficulties solving this exercise, go through [this](/reading/memory-addressing.md) reading material.
diff --git a/labs/lab-05/tasks/sum-array/solution/.gitignore b/labs/lab-05/tasks/sum-array/solution/.gitignore
index 8c0c005dd..ddeb385af 100644
--- a/labs/lab-05/tasks/sum-array/solution/.gitignore
+++ b/labs/lab-05/tasks/sum-array/solution/.gitignore
@@ -1,3 +1 @@
-sum-array-squared-64
-sum-array-squared
-sum-array
+sum-_array
diff --git a/labs/lab-05/tasks/sum-array/solution/sum_array.asm b/labs/lab-05/tasks/sum-array/solution/sum_array.asm
index 8d2a7dccb..ad0a8a06a 100644
--- a/labs/lab-05/tasks/sum-array/solution/sum_array.asm
+++ b/labs/lab-05/tasks/sum-array/solution/sum_array.asm
@@ -1,89 +1,86 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
%define ARRAY_SIZE 10
section .data
byte_array db 8, 19, 12, 3, 6, 200, 128, 19, 78, 102
word_array dw 1893, 9773, 892, 891, 3921, 8929, 7299, 720, 2590, 28891
- dword_array dd 1392849, 12544, 879923, 8799279, 7202277, 971872, 28789292, 17897892, 12988, 8799201
- dword_array2 dd 1392, 12544, 7992, 6992, 7202, 27187, 28789, 17897, 12988, 17992 ; for squares
- big_numbers_array dd 20000001, 3000000, 3000000, 23456789, 56789123, 123456789, 987654321, 56473829, 87564836, 777777777
- low_bits dd 0
- high_bits dd 0
+ dword_array dd 1392, 12544, 7992, 6992, 7202, 27187, 28789, 17897, 12988, 17992
+ qword_array dq 1392849893, 1254400000, 8799230000, 8799279000, 7202277000, 9718720000, 2878929200, 1789789200, 1298800000, 8799201000
+ big_qword_array dq 9223372036854775800, 8223372036854775800, 7223372036854775800
section .text
extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- mov ecx, ARRAY_SIZE ; Use ecx as loop counter.
- xor eax, eax ; Use eax to store the sum.
- xor edx, edx ; Store current value in dl; zero entire edx.
+ ; Byte array sum (original implementation)
+ mov rcx, ARRAY_SIZE ; Use rcx as loop counter
+ xor rax, rax ; Use rax to store the sum
+ xor rdx, rdx ; Store current value in dl; zero entire rdx
add_byte_array_element:
- mov dl, byte [byte_array + ecx - 1]
- add eax, edx
- loop add_byte_array_element ; Decrement ecx, if not zero, add another element.
+ mov dl, byte [byte_array + rcx - 1]
+ add rax, rdx
+ loop add_byte_array_element
- PRINTF32 `Array sum is %u\n\x0`, eax
+ PRINTF64 `Byte array sum: %u\n\x0`, rax
+
+ ; Word array sum
+ mov rcx, ARRAY_SIZE
+ xor rax, rax
+ xor rdx, rdx
- mov ecx, ARRAY_SIZE
- xor eax, eax
- xor edx, edx
add_word_array_element:
- mov dx, word [word_array + 2 * ecx - 2]
- add eax, edx
- loop add_word_array_element ; Decrement ecx, if not zero, add another element.
+ mov dx, word [word_array + 2 * rcx - 2]
+ add rax, rdx
+ loop add_word_array_element
- PRINTF32 `Array sum is %u\n\x0`, eax
+ PRINTF64 `Word array sum: %u\n\x0`, rax
- mov ecx, ARRAY_SIZE
- xor eax, eax
- xor edx, edx
+ ; Dword array sum
+ mov rcx, ARRAY_SIZE
+ xor rax, rax
+ xor rdx, rdx
add_dword_array_element:
- mov edx, dword [dword_array + 4 * ecx - 4]
- add eax, edx
- loop add_dword_array_element ; Decrement ecx, if not zero, add another element.
-
- PRINTF32 `Array sum is %u\n\x0`, eax
-
- xor eax, eax
- mov ecx, ARRAY_SIZE
- xor eax, eax
- xor edx, edx
-
-add_dword_array_element_squares:
- push eax
- mov eax, dword [dword_array2 + 4 * ecx - 4]
- mov edx, dword [dword_array2 + 4 * ecx - 4]
- mul edx
- mov edx, eax
- pop eax
- add eax, edx
- loop add_dword_array_element_squares
-
- PRINTF32 `Array sum is %u\n\x0`, eax
-
- xor eax, eax
- mov ecx, ARRAY_SIZE
- xor eax, eax
- xor ebx, ebx
-
-add_dword_array_element_big:
- xor edx, edx
- mov eax, dword [big_numbers_array + 4 * ecx - 4]
- mov ebx, dword [big_numbers_array + 4 * ecx - 4]
- mul ebx ; Compute array element square.
- add [low_bits], eax ; Add lowest 32 bits of squared element to final result.
- adc [high_bits], edx ; Add higher 32 bits of squared element with carry to final result.
- loop add_dword_array_element_big
-
- PRINTF32 `Array sum is %lld\n\x0`, [low_bits], [high_bits]
+ mov edx, dword [dword_array + 4 * rcx - 4]
+ add rax, rdx
+ loop add_dword_array_element
+
+ PRINTF64 `Dword array sum: %u\n\x0`, rax
+
+ ; Qword array sum
+ mov rcx, ARRAY_SIZE
+ xor rax, rax
+
+add_qword_array_element:
+ add rax, qword [qword_array + 8 * rcx - 8]
+ loop add_qword_array_element
+
+ PRINTF64 `Qword array sum: %lu\n\x0`, rax
+
+ ; 128-bit addition example (sum of all three big_qword values)
+ mov r8, 0 ; Use r8 to track carries
+
+ mov rax, qword [big_qword_array] ; Load first value
+ add rax, qword [big_qword_array + 8] ; Add second value
+ jnc no_first_carry
+ inc r8 ; Increment carry counter
+no_first_carry:
+
+ add rax, qword [big_qword_array + 16] ; Add third value
+ jnc no_second_carry
+ inc r8 ; Increment carry counter
+no_second_carry:
+
+ mov rdx, r8 ; Move final carry count to rdx for output
+
+ PRINTF64 `128-bit addition example: 0x%lx%016lx\n\x0`, rdx, rax
leave
- ret
+ ret
\ No newline at end of file
diff --git a/labs/lab-05/tasks/sum-array/solution/sum_array_square.asm b/labs/lab-05/tasks/sum-array/solution/sum_array_square.asm
deleted file mode 100644
index 7fa139510..000000000
--- a/labs/lab-05/tasks/sum-array/solution/sum_array_square.asm
+++ /dev/null
@@ -1,35 +0,0 @@
-; SPDX-License-Identifier: BSD-3-Clause
-
-%include "printf32.asm"
-
-%define ARRAY_SIZE 10
-
-section .data
- dword_array dd 1392, 12544, 7992, 6992, 7202, 27187, 28789, 17897, 12988, 17992
-
-section .text
-extern printf
-global main
-main:
- push ebp
- mov ebp, esp
- xor eax, eax
-
- mov ecx, ARRAY_SIZE
- xor eax, eax
- xor edx, edx
-
-add_dword_array_element:
- push eax
- mov eax, dword [dword_array + 4 * ecx - 4]
- mov edx, dword [dword_array + 4 * ecx - 4]
- mul edx
- mov edx, eax
- pop eax
- add eax, edx
- loop add_dword_array_element
-
- PRINTF32 `Array sum is %u\n\x0`, eax
-
- leave
- ret
diff --git a/labs/lab-05/tasks/sum-array/solution/sum_array_square_64.asm b/labs/lab-05/tasks/sum-array/solution/sum_array_square_64.asm
deleted file mode 100644
index 39d75571a..000000000
--- a/labs/lab-05/tasks/sum-array/solution/sum_array_square_64.asm
+++ /dev/null
@@ -1,36 +0,0 @@
-; SPDX-License-Identifier: BSD-3-Clause
-
-%include "printf32.asm"
-
-%define ARRAY_SIZE 10
-
-section .data
- big_numbers_array dd 20000001, 3000000, 3000000, 23456789, 56789123, 123456789, 987654321, 56473829, 87564836, 777777777
- low_bits dd 0
- high_bits dd 0
-
-section .text
-extern printf
-global main
-main:
- push ebp
- mov ebp, esp
-
- xor eax, eax
- mov ecx, ARRAY_SIZE
- xor eax, eax
- xor ebx, ebx
-
-add_dword_array_element:
- xor edx, edx
- mov eax, dword [big_numbers_array + 4 * ecx - 4]
- mov ebx, dword [big_numbers_array + 4 * ecx - 4]
- mul ebx ; Compute array element square.
- add [low_bits], eax ; Add lowest 32 bits of squared element to final result.
- adc [high_bits], edx ; Add higher 32 bits of squared element with carry to final result.
- loop add_dword_array_element ; Decrement ecx, if not zero, go to next element.
-
- PRINTF32 `Array sum is %lld\n\x0`, [low_bits], [high_bits]
-
- leave
- ret
diff --git a/labs/lab-05/tasks/sum-array/support/.gitignore b/labs/lab-05/tasks/sum-array/support/.gitignore
index 8c0c005dd..c8142c975 100644
--- a/labs/lab-05/tasks/sum-array/support/.gitignore
+++ b/labs/lab-05/tasks/sum-array/support/.gitignore
@@ -1,3 +1 @@
-sum-array-squared-64
-sum-array-squared
-sum-array
+sum_array
diff --git a/labs/lab-05/tasks/sum-array/support/Makefile b/labs/lab-05/tasks/sum-array/support/Makefile
index 43acbff58..01d412455 100644
--- a/labs/lab-05/tasks/sum-array/support/Makefile
+++ b/labs/lab-05/tasks/sum-array/support/Makefile
@@ -6,9 +6,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
TARGETS := $(OBJS:.o=)
diff --git a/labs/lab-05/tasks/sum-array/tests/test.sh b/labs/lab-05/tasks/sum-array/tests/test.sh
index 20d3c7202..4846d206e 100755
--- a/labs/lab-05/tasks/sum-array/tests/test.sh
+++ b/labs/lab-05/tasks/sum-array/tests/test.sh
@@ -8,12 +8,12 @@ binary="../support/sum_array"
OUTPUT=$($binary)
-word_sum=$(echo "$OUTPUT" | grep "A" | sed -n '2p' | awk '{print $4}')
-dword_sum=$(echo "$OUTPUT" | grep "A" | sed -n '3p' | awk '{print $4}')
-squares_sum=$(echo "$OUTPUT" | grep "A" | sed -n '4p' | awk '{print $4}')
-big_sum=$(echo "$OUTPUT" | grep "A" | sed -n '5p' | awk '{print $4}')
+word_sum=$(echo "$OUTPUT" | grep "Word array sum:" | awk '{print $4}')
+dword_sum=$(echo "$OUTPUT" | grep "Dword array sum:" | awk '{print $4}')
+qword_sum=$(echo "$OUTPUT" | grep "Qword array sum:" | awk '{print $4}')
+big_sum=$(echo "$OUTPUT" | grep "128-bit addition example:" | awk '{print $4}')
-first_test() {
+word_sum_test() {
if [[ -z $word_sum ]]; then
exit 1
fi
@@ -25,36 +25,36 @@ first_test() {
fi
}
-second_test() {
+dword_sum_test() {
if [[ -z $dword_sum ]]; then
exit 1
fi
- if [[ $dword_sum -eq 74758117 ]]; then
+ if [[ $dword_sum -eq 140975 ]]; then
exit 0
else
exit 1
fi
}
-third_test() {
- if [[ -z $squares_sum ]]; then
+qword_sum_test() {
+ if [[ -z $qword_sum ]]; then
exit 1
fi
- if [[ $squares_sum -eq 2704560839 ]]; then
+ if [[ $qword_sum -eq 51933475293 ]]; then
exit 0
else
exit 1
fi
}
-fourth_test() {
+big_sum_test() {
if [[ -z $big_sum ]]; then
exit 1
fi
- if [[ $big_sum -eq 1610691026282151079 ]]; then
+ if [[ $big_sum -eq 0x1565ddbe509d3ffe8 ]]; then
exit 0
else
exit 1
@@ -62,7 +62,7 @@ fourth_test() {
}
run_tests() {
- local tests=(first_test second_test third_test fourth_test)
+ local tests=(word_sum_test dword_sum_test qword_sum_test big_sum_test)
local scores=(20 20 30 30)
for i in {0..3}; do
run_test "${tests[i]}" "${scores[i]}"
diff --git a/labs/lab-05/tasks/sum-array/utils/printf32.asm b/labs/lab-05/tasks/sum-array/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-05/tasks/sum-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-05/tasks/sum-array/utils/printf64.asm b/labs/lab-05/tasks/sum-array/utils/printf64.asm
new file mode 100644
index 000000000..2bcf2712b
--- /dev/null
+++ b/labs/lab-05/tasks/sum-array/utils/printf64.asm
@@ -0,0 +1,71 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-05/tasks/sum-squared/README.md b/labs/lab-05/tasks/sum-squared/README.md
index 383cad8be..8aa061c2f 100644
--- a/labs/lab-05/tasks/sum-squared/README.md
+++ b/labs/lab-05/tasks/sum-squared/README.md
@@ -9,25 +9,25 @@ You will solve this exercise starting from the `sum_n.asm` file located in the `
In the `sum_n.asm` program, the sum of the first `num` natural numbers is calculated.
-Follow the code, observe the constructions and registers specific to working with bytes.
+Follow the code, observe the constructions and registers specific to working with 64-bit values.
Run the code.
> **IMPORTANT**: Proceed to the next step only after you have understood very well what the code does.
It will be difficult for you to do the next exercise if you have difficulties understanding the current one.
-Start with the program `sum_n.asm` and create a program `sum_n_squared.asm` that calculates the sum of squares of the first `num` natural numbers (`num` <= 100).
+Start with the program `sum_n.asm` and create a program `sum_n_squared.asm` that calculates the sum of the squares of the first `num = 100000` natural numbers.
-> **TIP**: You will use the `eax` and `edx` registers for multiplication to compute the squares (using the `mul` instruction).
-Therefore, you cannot easily use the `eax` register to store the sum of squares. To retain the sum of squares, you have two options:
+> **TIP**: You will use the `rax` and `rdx` registers for multiplication to compute the squares (using the `mul` instruction).
+Therefore, you cannot easily use the `rax` register to store the sum of squares. To retain the sum of squares, you have two options:
>
-> 1. (easier) Use the `ebx` register to store the sum of squares.
-> 1. (more complex) Before performing operations on the `eax` register, save its value on the stack (using the `push` instruction), then perform the necessary operations, and finally restore the saved value (using the `pop` instruction).
+> 1. (easier) Use the `rbx` register to store the sum of squares.
+> 1. (more complex) Before performing operations on the `rax` register, save its value on the stack (using the `push` instruction), then perform the necessary operations, and finally restore the saved value (using the `pop` instruction).
>
-> **NOTE**: For verification, the sum of squares of the first 100 natural numbers is `338350`.
+> **NOTE**: For verification, the sum of squares of the first 100,000 natural numbers is `333,338,333,350,000`, which requires 64-bit registers to represent.
## Testing
-To test the implementation, enter the `tests/` directory and run:
+To test your implementation, enter the `tests/` directory and run:
```console
make check
@@ -36,8 +36,8 @@ make check
In case of a correct solution, you will get an output such as:
```text
-test_sum_100 ........................ passed ... 50
-test_sum_squares_100 ........................ passed ... 50
+test_sum ........................ passed ... 50
+test_sum_squares ........................ passed ... 50
========================================================================
diff --git a/labs/lab-05/tasks/sum-squared/solution/.gitignore b/labs/lab-05/tasks/sum-squared/solution/.gitignore
index 2d6888e7d..6375b9439 100644
--- a/labs/lab-05/tasks/sum-squared/solution/.gitignore
+++ b/labs/lab-05/tasks/sum-squared/solution/.gitignore
@@ -1,3 +1,2 @@
-sum_n_squared_stack
sum_n_squared
sum_n
diff --git a/labs/lab-05/tasks/sum-squared/solution/sum_n.asm b/labs/lab-05/tasks/sum-squared/solution/sum_n.asm
index 13120dcfb..7f435286d 100644
--- a/labs/lab-05/tasks/sum-squared/solution/sum_n.asm
+++ b/labs/lab-05/tasks/sum-squared/solution/sum_n.asm
@@ -1,26 +1,26 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .data
- num dd 100
+ num dq 100000
section .text
extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- mov ecx, [num] ; Use ecx as counter for computing the sum.
- xor eax, eax ; Use eax to store the sum. Start from 0.
+ mov rcx, [num] ; Use rcx as counter for computing the sum.
+ xor rax, rax ; Use rax to store the sum. Start from 0.
add_to_sum:
- add eax, ecx
- loop add_to_sum ; Decrement ecx. If not zero, add it to sum.
+ add rax, rcx
+ loop add_to_sum ; Decrement rcx. If not zero, add it to sum.
- mov ecx, [num]
- PRINTF32 `Sum(%u): %u\n\x0`, ecx, eax
+ mov rcx, [num]
+ PRINTF64 `Sum(%lu): %lu\n\x0`, rcx, rax
leave
ret
diff --git a/labs/lab-05/tasks/sum-squared/solution/sum_n_squared.asm b/labs/lab-05/tasks/sum-squared/solution/sum_n_squared.asm
index a59538b1d..404a89575 100644
--- a/labs/lab-05/tasks/sum-squared/solution/sum_n_squared.asm
+++ b/labs/lab-05/tasks/sum-squared/solution/sum_n_squared.asm
@@ -1,28 +1,28 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .data
- num dd 100
+ num dq 100000
section .text
extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- mov ecx, [num] ; Use ecx as counter for computing the sum.
- xor ebx, ebx ; Use ebx to store the sum. Start from 0.
+ mov rcx, [num] ; Use rcx as counter.
+ xor rbx, rbx ; Use rbx to store the sum of squares. Start from 0.
-add_to_sum:
- mov eax, ecx
- mul eax
- add ebx, eax
- loop add_to_sum ; Decrement ecx. If not zero, add it to sum.
+add_square_to_sum:
+ mov rax, rcx ; Move current number to rax for multiplication
+ mul rax ; Square the number (rax = rax * rax)
+ add rbx, rax ; Add the square to our sum
+ loop add_square_to_sum ; Decrement rcx. If not zero, continue.
- mov ecx, [num]
- PRINTF32 `Sum(%u): %u\n\x0`, ecx, ebx
+ mov rcx, [num]
+ PRINTF64 `Sum of squares(%lu): %lu\n\x0`, rcx, rbx
leave
ret
diff --git a/labs/lab-05/tasks/sum-squared/solution/sum_n_squared_stack.asm b/labs/lab-05/tasks/sum-squared/solution/sum_n_squared_stack.asm
index 07a45215d..1bf6242a9 100644
--- a/labs/lab-05/tasks/sum-squared/solution/sum_n_squared_stack.asm
+++ b/labs/lab-05/tasks/sum-squared/solution/sum_n_squared_stack.asm
@@ -1,31 +1,31 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .data
- num dd 100
+ num dq 100000
section .text
extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- mov ecx, [num] ; Use ecx as counter for computing the sum.
- xor eax, eax ; Use eax to store the sum. Start from 0.
+ mov rcx, [num] ; Use rcx as counter for computing the sum.
+ xor rax, rax ; Use rax to store the sum. Start from 0.
add_to_sum:
- push eax
- mov eax, ecx
- mul eax
- mov edx, eax
- pop eax
- add eax, edx
- loop add_to_sum ; Decrement ecx. If not zero, add it to sum.
+ push rax ; Save current sum on stack
+ mov rax, rcx ; Move counter to rax
+ mul rax ; Square the value (rax = rax * rax)
+ mov rdx, rax ; Move squared value to rdx
+ pop rax ; Restore sum from stack
+ add rax, rdx ; Add squared value to sum
+ loop add_to_sum ; Decrement rcx. If not zero, continue.
- mov ecx, [num]
- PRINTF32 `Sum(%u): %u\n\x0`, ecx, eax
+ mov rcx, [num]
+ PRINTF64 `Sum of squares(%lu): %lu\n\x0`, rcx, rax
leave
ret
diff --git a/labs/lab-05/tasks/sum-squared/support/.gitignore b/labs/lab-05/tasks/sum-squared/support/.gitignore
index 2d6888e7d..6375b9439 100644
--- a/labs/lab-05/tasks/sum-squared/support/.gitignore
+++ b/labs/lab-05/tasks/sum-squared/support/.gitignore
@@ -1,3 +1,2 @@
-sum_n_squared_stack
sum_n_squared
sum_n
diff --git a/labs/lab-05/tasks/sum-squared/support/Makefile b/labs/lab-05/tasks/sum-squared/support/Makefile
index 43acbff58..01d412455 100644
--- a/labs/lab-05/tasks/sum-squared/support/Makefile
+++ b/labs/lab-05/tasks/sum-squared/support/Makefile
@@ -6,9 +6,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
TARGETS := $(OBJS:.o=)
diff --git a/labs/lab-05/tasks/sum-squared/support/sum_n.asm b/labs/lab-05/tasks/sum-squared/support/sum_n.asm
index 13120dcfb..7f435286d 100644
--- a/labs/lab-05/tasks/sum-squared/support/sum_n.asm
+++ b/labs/lab-05/tasks/sum-squared/support/sum_n.asm
@@ -1,26 +1,26 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .data
- num dd 100
+ num dq 100000
section .text
extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- mov ecx, [num] ; Use ecx as counter for computing the sum.
- xor eax, eax ; Use eax to store the sum. Start from 0.
+ mov rcx, [num] ; Use rcx as counter for computing the sum.
+ xor rax, rax ; Use rax to store the sum. Start from 0.
add_to_sum:
- add eax, ecx
- loop add_to_sum ; Decrement ecx. If not zero, add it to sum.
+ add rax, rcx
+ loop add_to_sum ; Decrement rcx. If not zero, add it to sum.
- mov ecx, [num]
- PRINTF32 `Sum(%u): %u\n\x0`, ecx, eax
+ mov rcx, [num]
+ PRINTF64 `Sum(%lu): %lu\n\x0`, rcx, rax
leave
ret
diff --git a/labs/lab-05/tasks/sum-squared/tests/test.sh b/labs/lab-05/tasks/sum-squared/tests/test.sh
index 16ab8d397..6f4605694 100755
--- a/labs/lab-05/tasks/sum-squared/tests/test.sh
+++ b/labs/lab-05/tasks/sum-squared/tests/test.sh
@@ -15,27 +15,27 @@ else
OUTPUT2="Not yet"
fi
-sum_100=$(echo "$OUTPUT1" | grep "S" | sed -n '1p' | awk '{print $2}')
-sum_squares_100=$(echo "$OUTPUT2" | grep "S" | sed -n '1p' | awk '{print $2}')
+sum=$(echo "$OUTPUT1" | grep "Sum" | awk '{print $2}' | tr -d '():')
+sum_squares=$(echo "$OUTPUT2" | grep "Sum" | awk '{print $4}' | tr -d '():')
-test_sum_100() {
- if [[ -z $sum_100 ]]; then
+test_sum() {
+ if [[ -z $sum ]]; then
exit 1
fi
- if [[ $sum_100 -eq 5050 ]]; then
+ if [[ $sum -eq 5000050000 ]]; then
exit 0
else
exit 1
fi
}
-test_sum_squares_100() {
- if [[ -z $sum_squares_100 ]]; then
+test_sum_squares() {
+ if [[ -z $sum_squares ]]; then
exit 1
fi
- if [[ $sum_squares_100 -eq 338350 ]]; then
+ if [[ $sum_squares -eq 333338333350000 ]]; then
exit 0
else
exit 1
@@ -43,7 +43,7 @@ test_sum_squares_100() {
}
run_tests() {
- local tests=(test_sum_100 test_sum_squares_100)
+ local tests=(test_sum test_sum_squares)
local scores=(50 50)
for i in {0..1}; do
run_test "${tests[i]}" "${scores[i]}"
diff --git a/labs/lab-05/tasks/sum-squared/utils/printf32.asm b/labs/lab-05/tasks/sum-squared/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-05/tasks/sum-squared/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-05/tasks/sum-squared/utils/printf64.asm b/labs/lab-05/tasks/sum-squared/utils/printf64.asm
new file mode 100644
index 000000000..2bcf2712b
--- /dev/null
+++ b/labs/lab-05/tasks/sum-squared/utils/printf64.asm
@@ -0,0 +1,71 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-05/tasks/vec-count-if/solution/count_even_odd.asm b/labs/lab-05/tasks/vec-count-if/solution/count_even_odd.asm
index 50d17fb46..d554d82ea 100644
--- a/labs/lab-05/tasks/vec-count-if/solution/count_even_odd.asm
+++ b/labs/lab-05/tasks/vec-count-if/solution/count_even_odd.asm
@@ -1,38 +1,42 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
%define ARRAY_SIZE 10
section .data
- dword_array dd 1392, 12544, 7991, 6992, 7202, 27187, 28789, 17897, 12988, 17992
+ qword_array dq 1392, 12544, 7991, 6992, 7202, 27187, 28789, 17897, 12988, 17992
+ fmt_str db "Num even is %lu, num odd is %lu", 10, 0
section .text
extern printf
global main
main:
- mov ecx, ARRAY_SIZE ; Use ecx as loop counter.
- xor esi, esi ; Store even number in `esi`.
- xor edi, edi ; Store odd number in `edi`.
-next_element:
-
- ; We need to initialize the dividend (edx:eax) to 0:array_element
- xor edx, edx
- mov eax, dword [dword_array + ecx*4 - 4]
- ; Store the divisor (2) in `ebx`.
- mov ebx, 2
- div ebx
+ push rbp
+ mov rbp, rsp
- ; edx stores remainder. If remainder is 0, number is even, otherwise number is odd.
- test edx, edx
+ mov rcx, ARRAY_SIZE ; Use rcx as loop counter.
+ xor rsi, rsi ; Store even number in `rsi`.
+ xor rdi, rdi ; Store odd number in `rdi`.
+next_element:
+ ; We need to initialize the dividend (rdx:rax) to 0:array_element
+ xor rdx, rdx
+ mov rax, qword [qword_array + rcx*8 - 8]
+ ; Store the divisor (2) in `rbx`.
+ mov rbx, 2
+ div rbx
+
+ ; rdx stores remainder. If remainder is 0, number is even, otherwise number is odd.
+ test rdx, rdx
jne add_to_odd
- inc esi
+ inc rsi
jmp test_end
add_to_odd:
- inc edi
+ inc rdi
test_end:
- loop next_element ; Decrement `ecx`, if not zero, go to next element.
+ loop next_element ; Decrement `rcx`, if not zero, go to next element.
- PRINTF32 `Num even is %u, num odd is %u\n\x0`, esi, edi
+ PRINTF64 `Num even is %u, num odd is %u\n\x0`, rsi, rdi
+ leave
ret
diff --git a/labs/lab-05/tasks/vec-count-if/solution/count_pos_neg.asm b/labs/lab-05/tasks/vec-count-if/solution/count_pos_neg.asm
index 5b1dfe9af..f1d555cbb 100644
--- a/labs/lab-05/tasks/vec-count-if/solution/count_pos_neg.asm
+++ b/labs/lab-05/tasks/vec-count-if/solution/count_pos_neg.asm
@@ -1,30 +1,35 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "../utils/printf32.asm"
+%include "printf64.asm"
%define ARRAY_SIZE 10
section .data
- dword_array dd 1392, -12544, -7992, -6992, 7202, 27187, 28789, -17897, 12988, 17992
+ qword_array dq 1392, -12544, -7992, -6992, 7202, 27187, 28789, -17897, 12988, 17992
+ fmt_str db "Num pos is %lu, num neg is %lu", 10, 0
section .text
extern printf
global main
main:
- mov ecx, ARRAY_SIZE ; Use ecx as loop counter.
- xor ebx, ebx ; Store positive number in ebx.
- xor edx, edx ; Store negative number in edx.
+ push rbp
+ mov rbp, rsp
+
+ mov rcx, ARRAY_SIZE ; Use rcx as loop counter.
+ xor rbx, rbx ; Store positive number in rbx.
+ xor rdx, rdx ; Store negative number in rdx.
next_element:
- mov eax, dword [dword_array + ecx*4 - 4]
- cmp eax, 0
+ mov rax, qword [qword_array + rcx*8 - 8]
+ cmp rax, 0
jl add_to_neg
- inc ebx
+ inc rbx
jmp test_end
add_to_neg:
- inc edx
+ inc rdx
test_end:
- loop next_element ; Decrement ecx, if not zero, go to next element.
+ loop next_element ; Decrement rcx, if not zero, go to next element.
- PRINTF32 `Num pos is %u, num neg is %u\n\x0`, ebx, edx
+ PRINTF64 `Num even is %u, num odd is %u\n\x0`, rbx, rdx
+ leave
ret
diff --git a/labs/lab-05/tasks/vec-count-if/support/.gitignore b/labs/lab-05/tasks/vec-count-if/support/.gitignore
index d551f7ae7..daf3965a4 100644
--- a/labs/lab-05/tasks/vec-count-if/support/.gitignore
+++ b/labs/lab-05/tasks/vec-count-if/support/.gitignore
@@ -1,2 +1,2 @@
-count-even-odd
-count-pos-neg
+count_even_odd
+count_pos_neg
diff --git a/labs/lab-05/tasks/vec-count-if/support/Makefile b/labs/lab-05/tasks/vec-count-if/support/Makefile
index 43acbff58..01d412455 100644
--- a/labs/lab-05/tasks/vec-count-if/support/Makefile
+++ b/labs/lab-05/tasks/vec-count-if/support/Makefile
@@ -6,9 +6,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
TARGETS := $(OBJS:.o=)
diff --git a/labs/lab-05/tasks/vec-count-if/support/count_pos_neg.asm b/labs/lab-05/tasks/vec-count-if/support/count_pos_neg.asm
index bea90c37b..d5f2a263e 100644
--- a/labs/lab-05/tasks/vec-count-if/support/count_pos_neg.asm
+++ b/labs/lab-05/tasks/vec-count-if/support/count_pos_neg.asm
@@ -1,11 +1,11 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
%define ARRAY_SIZE 10
section .data
- dword_array dd 1392, -12544, -7992, -6992, 7202, 27187, 28789, -17897, 12988, 17992
+ qword_array dq 1392, -12544, -7992, -6992, 7202, 27187, 28789, -17897, 12988, 17992
section .text
extern printf
diff --git a/labs/lab-05/tasks/vec-count-if/utils/printf32.asm b/labs/lab-05/tasks/vec-count-if/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-05/tasks/vec-count-if/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-05/tasks/vec-count-if/utils/printf64.asm b/labs/lab-05/tasks/vec-count-if/utils/printf64.asm
new file mode 100644
index 000000000..2bcf2712b
--- /dev/null
+++ b/labs/lab-05/tasks/vec-count-if/utils/printf64.asm
@@ -0,0 +1,71 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-06/guides/max/README.md b/labs/lab-06/guides/max/README.md
index 6445c8410..2c041dec9 100644
--- a/labs/lab-06/guides/max/README.md
+++ b/labs/lab-06/guides/max/README.md
@@ -9,6 +9,6 @@ To follow this guide, you'll need to use the `max.asm` file located in the `guid
The program finds the maximum value in an array of 16-bit integers (`array`).
It iterates through the array, updating the maximum value (`dx`) when it finds a larger value.
-Finally, it prints the maximum value using the `printf()` function.
+Finally, it prints the maximum value using the `PRINTF64` macro.
>**Note**: For a detailed description of the instruction, check out the following page: [Assembly Arrays Tutorial](https://www.tutorialspoint.com/assembly_programming/assembly_arrays.htm)
diff --git a/labs/lab-06/guides/max/support/Makefile b/labs/lab-06/guides/max/support/Makefile
index 6851e023d..a7119bcd2 100644
--- a/labs/lab-06/guides/max/support/Makefile
+++ b/labs/lab-06/guides/max/support/Makefile
@@ -1,9 +1,9 @@
NASM = nasm
AFILES = max.asm
OBJS = $(AFILES:.asm=.o)
-ASM_FLAGS = -f elf32 -g
+ASM_FLAGS = -f elf64 -g
LD=gcc
-LDFLAGS = -m32 -g
+LDFLAGS = -g -no-pie
BINARIES = max
all : $(BINARIES)
diff --git a/labs/lab-06/guides/max/support/max.asm b/labs/lab-06/guides/max/support/max.asm
index 8b98a2e90..034b4e1d6 100644
--- a/labs/lab-06/guides/max/support/max.asm
+++ b/labs/lab-06/guides/max/support/max.asm
@@ -1,6 +1,6 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "../utils/printf32.asm"
+%include "../utils/printf64.asm"
section .data
array dw 10, 20, 30, 17, 277, 127, 17792, 1781, 2891, 2129
@@ -11,29 +11,29 @@ extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- ; ecx -> iterator through vector (ecx -> 0..9)
- xor ecx, ecx
+ ; rcx -> iterator through vector (rcx -> 0..9)
+ xor rcx, rcx
- ; edx -> store max
- xor edx, edx
+ ; rdx -> store max
+ xor rdx, rdx
again:
- cmp dx, [array + 2*ecx]
+ cmp dx, [array + 2*rcx]
ja noaction
- ; Load new value in edx (max).
- mov dx, [array + 2*ecx]
+ ; Load new value in rdx (max).
+ mov dx, [array + 2*rcx]
noaction:
- inc ecx
- cmp ecx, len
+ inc rcx
+ cmp rcx, len
jb again
- PRINTF32 `%u\x0`, edx
+ PRINTF64 `%lu\n\x0`, rdx
- xor eax, eax
+ xor rax, rax
leave
ret
diff --git a/labs/lab-06/guides/max/utils/printf32.asm b/labs/lab-06/guides/max/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-06/guides/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-06/guides/max/utils/printf64.asm b/labs/lab-06/guides/max/utils/printf64.asm
new file mode 100644
index 000000000..358881592
--- /dev/null
+++ b/labs/lab-06/guides/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-06/guides/students/support/Makefile b/labs/lab-06/guides/students/support/Makefile
index 5abc99d22..88e5c7275 100644
--- a/labs/lab-06/guides/students/support/Makefile
+++ b/labs/lab-06/guides/students/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 ?= -no-pie
TARGET_EXEC = students
diff --git a/labs/lab-06/guides/students/support/students.asm b/labs/lab-06/guides/students/support/students.asm
index 10a2c68a0..6b9aaa13b 100644
--- a/labs/lab-06/guides/students/support/students.asm
+++ b/labs/lab-06/guides/students/support/students.asm
@@ -1,48 +1,48 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
extern printf
section .bss:
; the structure for a student
struc student_t
- name: resb 10 ; char[10] - student name
- id_course: resd 1 ; integer - the id of the course where a student is assigned
- check: resd 1 ; "bool" - check if the student is assigned to the course
+ name: resb 10 ; char[10] - student name
+ id_course: resq 1 ; integer - the id of the course where a student is assigned
+ check: resd 1 ; "bool" - check if the student is assigned to the course
endstruc
section .data
- v_students_count: dd 5
+ v_students_count: dq 5
students:
istruc student_t
at name, db "Vlad", 0
- at id_course, dd 0
+ at id_course, dq 0
at check, dd 1
iend
istruc student_t
at name, db "Andrew", 0
- at id_course, dd 1
+ at id_course, dq 1
at check, dd 1
iend
istruc student_t
at name, db "Kim", 0
- at id_course, dd 1
+ at id_course, dq 1
at check, dd 1
iend
istruc student_t
at name, db "George", 0
- at id_course, dd 2
+ at id_course, dq 2
at check, dd 1
iend
istruc student_t
at name, db "Kate", 0
- at id_course, dd 0
+ at id_course, dq 0
at check, dd 0
iend
@@ -50,19 +50,24 @@ section .text
global main
main:
- push ebp
- mov ebp, esp
- PRINTF32 `The students list is:\n\x0`
- xor ecx, ecx
- afisare:
- mov ebx, students ; save the starting address of the vector in ebx
- mov edx, ecx ; save the index in edx
- imul edx, student_t_size ; multiply the index by the size of the student_t structure
- add ebx, edx ; save the starting address of the structure with the index ecx from the list of structures in ebx
- add ebx, name ; extract the field where the student's name is stored in each structure
- PRINTF32 `%s\n\x0`, ebx
- inc ecx
- cmp ecx, [v_students_count]
+ push rbp
+ mov rbp, rsp
+ PRINTF64 `The students list is:\n\x0`
+ xor rcx, rcx
+ print:
+ mov rbx, students ; save the starting address of the vector in rbx
+
+ mov rdx, rcx ; save the index in rdx
+
+ imul rdx, student_t_size ; multiply the index by the size of the student_t structure
+
+ add rbx, rdx ; save the starting address of the structure with the index rcx from the list of structures in rbx
+
+ add rbx, name ; extract the field where the student's name is stored in each structure
+
+ PRINTF64 `%s\n\x0`, rbx
+ inc rcx
+ cmp rcx, [v_students_count]
jl afisare
leave
ret
diff --git a/labs/lab-06/guides/students/utils/printf32.asm b/labs/lab-06/guides/students/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-06/guides/students/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-06/guides/students/utils/printf64.asm b/labs/lab-06/guides/students/utils/printf64.asm
new file mode 100644
index 000000000..358881592
--- /dev/null
+++ b/labs/lab-06/guides/students/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-06/reading/arrays.md b/labs/lab-06/reading/arrays.md
index db29ad2dd..59084aef5 100644
--- a/labs/lab-06/reading/arrays.md
+++ b/labs/lab-06/reading/arrays.md
@@ -77,19 +77,20 @@ section .bss
As mentioned before, to access a field of an element in an array, we need to use normal addressing (particularly "based-indexed with scale" addressing).
The formula to find the address of the element is `base_of_array + i * size_of_struct`.
-Assuming we have the start address of the array in the `ebx` register and the index of the element we want to access in the `eax` register, the following example demonstrates printing the value of the y field of this element.
+Assuming we have the start address of the array in the `rbx` register and the index of the element we want to access in the `rax` register, the following example demonstrates printing the value of the y field of this element.
```Assembly
-mov ebx, point_array ; Move the start address of the array into ebx
-mov eax, 13 ; Assume we want the 14th element
-mov edx, [ebx + point_size * eax + point.y] ; Calculate the address of the desired field between []
- ; and then transfer the value from that address
- ; into the edx register
-
-PRINTF32 `%u\n\x0`, edx
+mov rbx, point_array ; Move the start address of the array into rbx
+mov rax, 13 ; Assume we want the 14th element
+xor rax, rax ; Clear the rax register
+mov rdx, dword [rbx + point_size * rax + point.y] ; Calculate the address of the desired field between []
+ ; and then transfer the value from that address
+ ; into the rdx register
+
+PRINTF64 `%lu\n\x0`, rdx
```
-We traverse the array, having the current index in the eax register at each iteration.
+We traverse the array, having the current index in the rax register at each iteration.
We can print the values from both fields of each element in the array with the following program:
```Assembly
@@ -105,21 +106,21 @@ section .text
global CMAIN
CMAIN:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- xor edx, edx
- xor eax, eax
+ xor rdx, rdx
+ xor rax, rax
label:
- mov edx, [point_array + point_size * eax + point.x] ; access x member
- PRINTF32 `%u\n\x0`, edx
+ mov edx, dword [point_array + point_size * rax + point.x] ; access x member
+ PRINTF64 `%lu\n\x0`, rdx
- mov edx, [point_array + point_size * eax + point.y] ; access y member
- PRINTF32 `%u\n\x0`, edx
+ mov edx, dword [point_array + point_size * rax + point.y] ; access y member
+ PRINTF64 `%lu\n\x0`, rdx
- inc eax ; increment input index
- cmp eax, 100
+ inc rax ; increment input index
+ cmp rax, 100
jl label
leave
diff --git a/labs/lab-06/reading/structures.md b/labs/lab-06/reading/structures.md
index 65144dbf5..efb3906da 100644
--- a/labs/lab-06/reading/structures.md
+++ b/labs/lab-06/reading/structures.md
@@ -26,7 +26,7 @@ struc mystruct
a: resw 1 ; a will refer to a single word-sized element
b: resd 1 ; b will refer to a single double-word-sized element
c: resb 1 ; c will refer to a single byte-sized element
- d: resd 1 ; d will refer to a single double-word-sized element
+ d: resq 1 ; d will refer to a single quad-word-sized element
e: resb 6 ; e will refer to 6 byte-sized elements
endstruc
```
@@ -66,7 +66,7 @@ struct_var:
at a, dw -1
at b, dd 0x12345678
at c, db ' '
- at d, dd 23
+ at d, dq 23
at e, db 'Gary', 0
iend
```
@@ -79,7 +79,7 @@ struct_var:
at mystruct.a, dw -1
at mystruct.b, dd 0x12345678
at mystruct.c, db ' '
- at mystruct.d, dd 23
+ at mystruct.d, dq 23
at mystruct.e, db 'Gary', 0
iend
```
@@ -91,12 +91,12 @@ struct_var:
To access and/or modify a specific member of the instantiated structure, we need to know its address.
This address can be obtained by calculating the sum of the starting address of the structure and the offset within the structure of the desired member.
-The following code sequence demonstrates setting a value in the `b` field of the structure and subsequently displaying the value of this field.
+The following code sequence demonstrates setting a value in the `d` field of the structure and subsequently displaying the value of this field.
```Assembly
-mov eax, 12345
-mov dword [mystruct + b], eax ; the address of field b is the base address of the statically instantiated structure + the offset of the field (given by the label 'b')
+mov rax, 12345
+mov [mystruct + d], rax ; the address of field d is the base address of the statically instantiated structure + the offset of the field (given by the label 'd')
-mov ebx, dword [mystruct + b] ; putting the value from field b into the ebx register for display
-PRINTF32 `%d\n\x0`, ebx
+mov rbx, [mystruct + d] ; putting the value from field d into the rbx register for display
+PRINTF64 `%ld\n\x0`, rbx
```
diff --git a/labs/lab-06/tasks/courses/solution/courses.asm b/labs/lab-06/tasks/courses/solution/courses.asm
index 0a820c5c6..e75f7b8b4 100644
--- a/labs/lab-06/tasks/courses/solution/courses.asm
+++ b/labs/lab-06/tasks/courses/solution/courses.asm
@@ -1,6 +1,6 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
extern printf
@@ -8,65 +8,65 @@ section .bss
; the structure for a student
struc student_t
name: resb 10 ; char[10] - student name
- id_course: resd 1 ; integer - the id of the course where a student is assigned
+ id_course: resq 1 ; integer - the id of the course where a student is assigned
check: resd 1 ; "bool" - check if the student is assigned to any course
endstruc
; the structure for a course
struc course_t
- id: resd 1 ; id = index in courses (the list of courses)
+ id: resq 1 ; id = index in courses (the list of courses)
name_course: resb 15 ; char[10] - the name of the course
endstruc
section .data
unassigned: db "Student unassigned :(", 0
- v_students_count: dd 5
- v_courses_count: dd 3
+ v_students_count: dq 5
+ v_courses_count: dq 3
students:
istruc student_t
at name, db "Vlad", 0
- at id_course, dd 0
+ at id_course, dq 0
at check, dd 1
iend
istruc student_t
at name, db "Andrew", 0
- at id_course, dd 1
+ at id_course, dq 1
at check, dd 1
iend
istruc student_t
at name, db "Kim", 0
- at id_course, dd 1
+ at id_course, dq 1
at check, dd 1
iend
istruc student_t
at name, db "George", 0
- at id_course, dd 2
+ at id_course, dq 2
at check, dd 1
iend
istruc student_t
at name, db "Kate", 0
- at id_course, dd 0
+ at id_course, dq 0
at check, dd 0
iend
courses:
istruc course_t
- at id, dd 0
+ at id, dq 0
at name_course, db "Assembly", 0
iend
istruc course_t
- at id, dd 1
+ at id, dq 1
at name_course, db "Linear Algebra", 0
iend
istruc course_t
- at id, dd 2
+ at id, dq 2
at name_course, db "Physics", 0
iend
@@ -74,43 +74,44 @@ section .text
global main
main:
- push ebp
- mov ebp, esp
- PRINTF32 `The students list is:\n\x0`
+ push rbp
+ mov rbp, rsp
+ PRINTF64 `The students list is:\n\x0`
- xor ecx, ecx
+ xor rcx, rcx
final_print:
- mov ebx, students ; put the address of students array into ebx
- mov edx, ecx ; save the index value in edx
- imul edx, student_t_size ; multiply the index with the size of the student_t structure
- add ebx, edx ; this addition save into ebx the address of the structure from an index in the students array
- mov eax, ebx ; move this address into ebx to use ebx for something else and to have the address saved in eax
- add ebx, name ; add to ebx `name` so that to get the name of the student
- ; it is possible to add name because in ebx is saved the address of start of an element from students array
+ mov rbx, students ; put the address of students array into rbx
+ mov rdx, rcx ; save the index value in rdx
+ imul rdx, student_t_size ; multiply the index with the size of the student_t structure
+ add rbx, rdx ; this addition save into rbx the address of the structure from an index in the students array
+ mov rax, rbx ; move this address into rbx to use rbx for something else and to have the address saved in rax
+ add rbx, name ; add to rbx `name` so that to get the name of the student
+ ; it is possible to add name because in rbx is saved the address of start of an element from students array
; and student_t structure contains name field
- PRINTF32 `%s ----\x0`, ebx
+ PRINTF64 `%s ----\x0`, rbx
- mov ebx, eax
- add ebx, check
- mov ebx, [ebx] ; extract the value from check field (it's by default a dword)
- cmp ebx, 0
+ mov r8, rax
+ add r8, check
+ xor rbx, rbx
+ mov ebx, dword [r8] ; extract the value from check field (it's by default a dword)
+ cmp rbx, 0
jne step
- PRINTF32 ` %s\n\x0`, unassigned
+ PRINTF64 ` %s\n\x0`, unassigned
jmp finish
step:
- mov ebx, eax
- add ebx, id_course
- mov ebx, [ebx] ; extract the index of the course in the courses array
- mov esi, courses
- imul ebx, course_t_size
- add esi, ebx
- add esi, name_course ; get the name of the student
- PRINTF32 ` %s\n\x0`, esi
+ mov rbx, rax
+ add rbx, id_course
+ mov rbx, [rbx] ; extract the index of the course in the courses array
+ mov rsi, courses
+ imul rbx, course_t_size
+ add rsi, rbx
+ add rsi, name_course ; get the name of the student
+ PRINTF64 ` %s\n\x0`, rsi
finish:
- inc ecx
- cmp ecx, [v_students_count] ; it's converted by default to dword
+ inc rcx
+ cmp rcx, [v_students_count] ; it's converted by default to dword
jl final_print
leave
diff --git a/labs/lab-06/tasks/courses/support/Makefile b/labs/lab-06/tasks/courses/support/Makefile
index cf1acae85..365240ec6 100644
--- a/labs/lab-06/tasks/courses/support/Makefile
+++ b/labs/lab-06/tasks/courses/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 = courses
diff --git a/labs/lab-06/tasks/courses/support/courses.asm b/labs/lab-06/tasks/courses/support/courses.asm
index 1a890245c..378094386 100644
--- a/labs/lab-06/tasks/courses/support/courses.asm
+++ b/labs/lab-06/tasks/courses/support/courses.asm
@@ -1,6 +1,6 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
extern printf
@@ -8,65 +8,65 @@ section .bss:
; the structure for a student
struc student_t
name: resb 10 ; char[10] - student name
- id_course: resd 1 ; integer - the id of the course where a student is assigned
+ id_course: resq 1 ; integer - the id of the course where a student is assigned
check: resd 1 ; "bool" - check if the student is assigned to any course
endstruc
; the structure for a course
struc course_t
- id: resd 1 ; id = index in courses (the list of courses)
+ id: resq 1 ; id = index in courses (the list of courses)
name_course: resb 15 ; char[10] - the name of the course
endstruc
section .data
unassigned: db "Student unassigned :(", 0
- v_students_count: dd 5
- v_courses_count: dd 3
+ v_students_count: dq 5
+ v_courses_count: dq 3
students:
istruc student_t
at name, db "Vlad", 0
- at id_course, dd 0
+ at id_course, dq 0
at check, dd 1
iend
istruc student_t
at name, db "Andrew", 0
- at id_course, dd 1
+ at id_course, dq 1
at check, dd 1
iend
istruc student_t
at name, db "Kim", 0
- at id_course, dd 1
+ at id_course, dq 1
at check, dd 1
iend
istruc student_t
at name, db "George", 0
- at id_course, dd 2
+ at id_course, dq 2
at check, dd 1
iend
istruc student_t
at name, db "Kate", 0
- at id_course, dd 0
+ at id_course, dq 0
at check, dd 0
iend
courses:
istruc course_t
- at id, dd 0
+ at id, dq 0
at name_course, db "Assembly", 0
iend
istruc course_t
- at id, dd 1
+ at id, dq 1
at name_course, db "Linear Algebra", 0
iend
istruc course_t
- at id, dd 2
+ at id, dq 2
at name_course, db "Physics", 0
iend
@@ -74,9 +74,9 @@ section .text
global main
main:
- push ebp
- mov ebp, esp
- PRINTF32 `The students list is:\n\x0`
+ push rbp
+ mov rbp, rsp
+ PRINTF64 `The students list is:\n\x0`
; TODO: Print the list of students and the courses where they are assigned
leave
ret
diff --git a/labs/lab-06/tasks/courses/utils/printf32.asm b/labs/lab-06/tasks/courses/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-06/tasks/courses/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-06/tasks/courses/utils/printf64.asm b/labs/lab-06/tasks/courses/utils/printf64.asm
new file mode 100644
index 000000000..358881592
--- /dev/null
+++ b/labs/lab-06/tasks/courses/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-06/tasks/fibonacci/solution/fibo_sum.asm b/labs/lab-06/tasks/fibonacci/solution/fibo_sum.asm
index 3c64a0bd8..5a4078c2b 100644
--- a/labs/lab-06/tasks/fibonacci/solution/fibo_sum.asm
+++ b/labs/lab-06/tasks/fibonacci/solution/fibo_sum.asm
@@ -1,47 +1,43 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .data
- N dd 9 ; compute the sum of the first N fibonacci numbers
- sum_print_format db "Sum first %d fibonacci numbers is %d", 10, 0
+ N dq 9 ; compute the sum of the first N fibonacci numbers
+ sum_print_format db "Sum first %ld fibonacci numbers is %ld", 10, 0
section .text
extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- ; The calling convention requires saving and restoring `ebx` if modified
- push ebx
+ ; The calling convention requires saving and restoring `rbx` if modified
+ push rbx
- xor eax, eax ;store the sum in eax
- mov ecx, [N]
- mov ebx, 0
- mov edx, 1
+ xor rax, rax ;store the sum in rax
+ mov rcx, [N]
+ mov rbx, 0
+ mov rdx, 1
calc_fibo:
- add eax, ebx
- add ebx, edx
- xchg ebx, edx
+ add rax, rbx
+ add rbx, rdx
+ xchg rbx, rdx
; The `xhcg` above is equivalent to the following:
- ; push eax
- ; mov eax, ebx
- ; mov ebx, edx
- ; mov edx, eax
- ; pop eax
+ ; push rax
+ ; mov rax, rbx
+ ; mov rbx, rdx
+ ; mov rdx, rax
+ ; pop rax
loop calc_fibo
- push eax
- push dword [N]
- push sum_print_format
- call printf
- add esp, 12
+ PRINTF64 `Sum first %d fibonacci numbers is %d\n\x0`, qword [N], rax
- ; Restore the `ebx` that was previously saved
- pop ebx
+ ; Restore the `rbx` that was previously saved
+ pop rbx
- xor eax, eax
+ xor rax, rax
leave
ret
diff --git a/labs/lab-06/tasks/fibonacci/support/Makefile b/labs/lab-06/tasks/fibonacci/support/Makefile
index 3f2aff5c9..e6a9c37cd 100644
--- a/labs/lab-06/tasks/fibonacci/support/Makefile
+++ b/labs/lab-06/tasks/fibonacci/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 = fibo_sum
diff --git a/labs/lab-06/tasks/fibonacci/support/fibo_sum.asm b/labs/lab-06/tasks/fibonacci/support/fibo_sum.asm
index 0de69efc8..08340b863 100644
--- a/labs/lab-06/tasks/fibonacci/support/fibo_sum.asm
+++ b/labs/lab-06/tasks/fibonacci/support/fibo_sum.asm
@@ -1,9 +1,9 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .data
- N dd 9 ; DO NOT MOFIDY THIS LINE EXCEPT FOR THE VALUE OF N!
+ N dq 9 ; DO NOT MOFIDY THIS LINE EXCEPT FOR THE VALUE OF N!
; compute the sum of the first N fibonacci numbers
sum_print_format db "Sum first %d fibonacci numbers is %d", 10, 0
@@ -11,21 +11,20 @@ section .text
extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
; TODO: calculate the sum of first N fibonacci numbers
; (f(0) = 0, f(1) = 1)
- xor eax, eax ;store the sum in eax
+ xor rax, rax ;store the sum in rax
; Use the loop instruction
- push eax
- push dword [N]
- push sum_print_format
+ mov rdx, rax
+ mov rsi, qword [N]
+ mov rdi, sum_print_format
call printf
- add esp, 12
- xor eax, eax
+ xor rax, rax
leave
ret
diff --git a/labs/lab-06/tasks/fibonacci/tests/tests.sh b/labs/lab-06/tasks/fibonacci/tests/tests.sh
index 29b722392..fa90c438b 100755
--- a/labs/lab-06/tasks/fibonacci/tests/tests.sh
+++ b/labs/lab-06/tasks/fibonacci/tests/tests.sh
@@ -20,7 +20,7 @@ test_fibo_sum()
SOL=$2
# Modify the assembly code's N value
- sed -i "s/N dd [0-9]\+/N dd $N/w sedlog" "$SRC_PATH"/fibo_sum.asm
+ sed -i "s/N dq [0-9]\+/N dq $N/w sedlog" "$SRC_PATH"/fibo_sum.asm
if ! [ -s sedlog ] ; then
return 2
fi
@@ -71,7 +71,7 @@ run_test "test_fibo_sum_1_0" 25
run_test "test_fibo_sum_40_165580140" 25
if [ $? -eq 2 ] ; then
- printf "\nERROR: Make sure the declaration of variable N in section .data follows the format \"N dd \"\n"
+ printf "\nERROR: Make sure the declaration of variable N in section .data follows the format \"N dq \"\n"
fi
mv ./fibo_sum.asm "$SRC_PATH"
diff --git a/labs/lab-06/tasks/fibonacci/utils/printf32.asm b/labs/lab-06/tasks/fibonacci/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-06/tasks/fibonacci/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-06/tasks/fibonacci/utils/printf64.asm b/labs/lab-06/tasks/fibonacci/utils/printf64.asm
new file mode 100644
index 000000000..358881592
--- /dev/null
+++ b/labs/lab-06/tasks/fibonacci/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-06/tasks/find-substring/solution/find_substring.asm b/labs/lab-06/tasks/find-substring/solution/find_substring.asm
index dd67e40f3..0e5954e36 100644
--- a/labs/lab-06/tasks/find-substring/solution/find_substring.asm
+++ b/labs/lab-06/tasks/find-substring/solution/find_substring.asm
@@ -1,6 +1,6 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .data
source_text: db "ABCABCBABCBABCBBBABABBCBABCBAAACCCB", 0
@@ -12,39 +12,45 @@ section .text
extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- mov esi, source_text
- mov edi, substring
+ mov r8, source_text
+ mov r9, substring
source_loop:
- mov eax, esi
- mov edx, edi
+ mov rax, r8
+ mov rdx, r9
substr_loop:
- cmp byte [edx], 0
+ cmp byte [rdx], 0
je found_substr
- mov bl, byte [eax]
- cmp byte [edx], bl
+ mov bl, byte [rax]
+ cmp byte [rdx], bl
jne exit_substr_loop
- inc eax
- inc edx
+ inc rax
+ inc rdx
jmp substr_loop
found_substr:
- pusha
- mov ecx, esi
- sub ecx, source_text
- push ecx
- push print_format
- call printf
- add esp, 8
- popa
+ push rax ; Save the registers that may be modified by printf according to the
+ push rdx ; calling convention.
+ push r8 ; Make sure to write and extra push-pop pair in case of segfault
+ push r9 ; (because calling convention states the stack must be have a 16 or 32
+ mov rsi, r8 ; byte alignment)
+ sub rsi, source_text
+ mov rdi, print_format
+ xor al, al ; al is used to indicate the number of vector arguments passed
+ ; to a function requiring a variable number of arguments
+ call printf ; MORE ON CALLING CONVENTIONS IN THE FUNCTIONS LAB
+ pop r9
+ pop r8
+ pop rdx
+ pop rax
exit_substr_loop:
- inc esi
- cmp byte [esi], 0
+ inc r8
+ cmp byte [r8], 0
je exit
jmp source_loop
diff --git a/labs/lab-06/tasks/find-substring/support/Makefile b/labs/lab-06/tasks/find-substring/support/Makefile
index 1e1b21ea8..d56fe8478 100644
--- a/labs/lab-06/tasks/find-substring/support/Makefile
+++ b/labs/lab-06/tasks/find-substring/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 = find_substring
diff --git a/labs/lab-06/tasks/find-substring/support/find_substring.asm b/labs/lab-06/tasks/find-substring/support/find_substring.asm
index c544fbb17..46bc74454 100644
--- a/labs/lab-06/tasks/find-substring/support/find_substring.asm
+++ b/labs/lab-06/tasks/find-substring/support/find_substring.asm
@@ -1,6 +1,6 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .data
source_text: db "ABCABCBABCBABCBBBABABBCBABCBAAACCCB", 0 ; DO NOT MODIFY THIS LINE EXCEPT FOR THE STRING IN QUOTES
@@ -12,8 +12,8 @@ section .text
extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
; TODO: Print the start indices for all occurrences of the substring in source_text
diff --git a/labs/lab-06/tasks/find-substring/utils/printf32.asm b/labs/lab-06/tasks/find-substring/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-06/tasks/find-substring/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-06/tasks/find-substring/utils/printf64.asm b/labs/lab-06/tasks/find-substring/utils/printf64.asm
new file mode 100644
index 000000000..358881592
--- /dev/null
+++ b/labs/lab-06/tasks/find-substring/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-06/tasks/getters-setters/solution/getter_setter_printf.asm b/labs/lab-06/tasks/getters-setters/solution/getter_setter_printf.asm
index 0d698d648..457032b75 100644
--- a/labs/lab-06/tasks/getters-setters/solution/getter_setter_printf.asm
+++ b/labs/lab-06/tasks/getters-setters/solution/getter_setter_printf.asm
@@ -1,6 +1,6 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
struc my_struct
int_x: resb 4
@@ -25,33 +25,33 @@ extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- PRINTF32 `int_x: %d\n\x0`, [sample_obj + int_x]
- PRINTF32 `char_y: %c\n\x0`, [sample_obj + char_y]
- lea eax, [sample_obj + string_s]
- PRINTF32 `string_s: %s\n\x0`, eax
+ PRINTF64 `int_x: %d\n\x0`, qword [sample_obj + int_x]
+ PRINTF64 `char_y: %c\n\x0`, qword [sample_obj + char_y]
+ lea rax, [sample_obj + string_s]
+ PRINTF64 `string_s: %s\n\x0`, rax
- mov eax, [new_int]
- mov [sample_obj + int_x], eax
+ mov rax, [new_int]
+ mov [sample_obj + int_x], rax
mov al, [new_char]
mov [sample_obj + char_y], al
- mov ecx, 0
+ mov rcx, 0
copy:
- mov bl, [new_string + ecx]
- mov [sample_obj + string_s + ecx], bl
- inc ecx
+ mov bl, [new_string + rcx]
+ mov [sample_obj + string_s + rcx], bl
+ inc rcx
cmp bl, 0
jnz copy
- PRINTF32 `int_x: %d\n\x0`, [sample_obj + int_x]
- PRINTF32 `char_y: %c\n\x0`, [sample_obj + char_y]
- lea eax, [sample_obj + string_s]
- PRINTF32 `string_s: %s\n\x0`, eax
+ PRINTF64 `int_x: %d\n\x0`, qword [sample_obj + int_x]
+ PRINTF64 `char_y: %c\n\x0`, qword [sample_obj + char_y]
+ lea rax, [sample_obj + string_s]
+ PRINTF64 `string_s: %s\n\x0`, rax
- xor eax, eax
+ xor rax, rax
leave
ret
diff --git a/labs/lab-06/tasks/getters-setters/support/Makefile b/labs/lab-06/tasks/getters-setters/support/Makefile
index d81d7cb61..f6071ff13 100644
--- a/labs/lab-06/tasks/getters-setters/support/Makefile
+++ b/labs/lab-06/tasks/getters-setters/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 = getter_setter_printf
diff --git a/labs/lab-06/tasks/getters-setters/support/getter_setter_printf.asm b/labs/lab-06/tasks/getters-setters/support/getter_setter_printf.asm
index 086fa0521..c5a83fa28 100644
--- a/labs/lab-06/tasks/getters-setters/support/getter_setter_printf.asm
+++ b/labs/lab-06/tasks/getters-setters/support/getter_setter_printf.asm
@@ -1,6 +1,6 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
struc my_struct
int_x: resb 4
@@ -25,8 +25,8 @@ extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
; Print all three values (int_x, char_y, string_s) from sample_obj.
; Hint: use "lea reg, [base + offset]" to save the result of
@@ -41,6 +41,6 @@ main:
; TODO: print all three values again to validate the results of the
; three set operations above.
- xor eax, eax
+ xor rax, rax
leave
ret
diff --git a/labs/lab-06/tasks/getters-setters/utils/printf32.asm b/labs/lab-06/tasks/getters-setters/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-06/tasks/getters-setters/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-06/tasks/getters-setters/utils/printf64.asm b/labs/lab-06/tasks/getters-setters/utils/printf64.asm
new file mode 100644
index 000000000..358881592
--- /dev/null
+++ b/labs/lab-06/tasks/getters-setters/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-06/tasks/mul-arrays/solution/mul_arrays.asm b/labs/lab-06/tasks/mul-arrays/solution/mul_arrays.asm
index 763c17778..2f59a00df 100644
--- a/labs/lab-06/tasks/mul-arrays/solution/mul_arrays.asm
+++ b/labs/lab-06/tasks/mul-arrays/solution/mul_arrays.asm
@@ -1,6 +1,6 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .bss
array3: resw 10
@@ -14,34 +14,33 @@ extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- xor ecx, ecx
+ xor rcx, rcx
iterate_arrays:
- xor eax, eax
- xor ebx, ebx
- xor edx, edx
- mov al, byte[array1 + ecx]
- mov bl, byte[array2 + ecx]
+ xor rax, rax
+ xor rbx, rbx
+ xor rdx, rdx
+ mov al, [array1 + rcx]
+ mov bl, [array2 + rcx]
mul bl
- mov word[array3 + ecx * 2], ax
- inc ecx
- cmp ecx, 10
+ mov word[array3 + rcx * 2], ax
+ inc rcx
+ cmp rcx, 10
jl iterate_arrays
- PRINTF32 `The array that results from the product of the corresponding elements in array1 and array2 is:\n\x0`
+ PRINTF64 `The array that results from the product of the corresponding elements in array1 and array2 is:\n\x0`
- xor ecx, ecx
- xor eax, eax
+ xor rcx, rcx
+ xor rax, rax
display:
- mov ax, word[array3 + ecx * 2]
- PRINTF32 `%hu \x0`, eax
- inc ecx
- cmp ecx, 10
+ PRINTF64 `%hu \x0`, qword [array3 + rcx * 2]
+ inc rcx
+ cmp rcx, 10
jl display
- PRINTF32 `\n\x0`
+ PRINTF64 `\n\x0`
leave
ret
diff --git a/labs/lab-06/tasks/mul-arrays/support/Makefile b/labs/lab-06/tasks/mul-arrays/support/Makefile
index a2b26d676..e9f9955a0 100644
--- a/labs/lab-06/tasks/mul-arrays/support/Makefile
+++ b/labs/lab-06/tasks/mul-arrays/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 = mul_arrays
diff --git a/labs/lab-06/tasks/mul-arrays/support/mul_arrays.asm b/labs/lab-06/tasks/mul-arrays/support/mul_arrays.asm
index 7fe864a8f..4d73a846b 100644
--- a/labs/lab-06/tasks/mul-arrays/support/mul_arrays.asm
+++ b/labs/lab-06/tasks/mul-arrays/support/mul_arrays.asm
@@ -1,6 +1,6 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
section .bss
array3: resw 10
@@ -14,11 +14,11 @@ extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
; TODO: Traversing array1 and array2 and putting the result in array3
- PRINTF32 `The array that results from the product of the corresponding elements in array1 and array2 is:\n\x0`
+ PRINTF64 `The array that results from the product of the corresponding elements in array1 and array2 is:\n\x0`
; TODO: Traversing array3 and displaying its elements
- PRINTF32 `\n\x0`
+ PRINTF64 `\n\x0`
leave
ret
diff --git a/labs/lab-06/tasks/mul-arrays/utils/printf32.asm b/labs/lab-06/tasks/mul-arrays/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-06/tasks/mul-arrays/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-06/tasks/mul-arrays/utils/printf64.asm b/labs/lab-06/tasks/mul-arrays/utils/printf64.asm
new file mode 100644
index 000000000..358881592
--- /dev/null
+++ b/labs/lab-06/tasks/mul-arrays/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-06/tasks/print-structure/solution/print_structure.asm b/labs/lab-06/tasks/print-structure/solution/print_structure.asm
index 34b4b37c8..44c76464f 100644
--- a/labs/lab-06/tasks/print-structure/solution/print_structure.asm
+++ b/labs/lab-06/tasks/print-structure/solution/print_structure.asm
@@ -1,6 +1,6 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
struc stud_struct
name: resb 32
@@ -33,48 +33,36 @@ section .text
extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
mov word [sample_student + birth_year], 1993
mov byte [sample_student + age], 22
mov byte [sample_student + group + 2], '3'
- lea eax, [sample_student + name]
- push eax
- push format_name
+ lea rsi, [sample_student + name]
+ mov rdi, format_name
call printf
- add esp, 8
- lea eax, [sample_student + surname]
- push eax
- push format_surname
+ lea rsi, [sample_student + surname]
+ mov rdi, format_surname
call printf
- add esp, 8
- movzx eax, byte [sample_student + age]
- push eax
- push format_age
+ movzx rsi, byte [sample_student + age]
+ mov rdi, format_age
call printf
- add esp, 8
- lea eax, [sample_student + group]
- push eax
- push format_group
+ lea rsi, [sample_student + group]
+ mov rdi, format_group
call printf
- add esp, 8
- movzx eax, byte [sample_student + gender]
- push eax
- push format_gender
+ movzx rsi, byte [sample_student + gender]
+ mov rdi, format_gender
call printf
- add esp, 8
- movzx eax, word [sample_student + birth_year]
- push eax
- push format_year
+ movzx rsi, word [sample_student + birth_year]
+ mov rdi, format_year
call printf
- add esp, 8
leave
ret
diff --git a/labs/lab-06/tasks/print-structure/support/Makefile b/labs/lab-06/tasks/print-structure/support/Makefile
index c4f4eb079..dd62bac98 100644
--- a/labs/lab-06/tasks/print-structure/support/Makefile
+++ b/labs/lab-06/tasks/print-structure/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 = print_structure
diff --git a/labs/lab-06/tasks/print-structure/support/print_structure.asm b/labs/lab-06/tasks/print-structure/support/print_structure.asm
index 132034430..bc112d03d 100644
--- a/labs/lab-06/tasks/print-structure/support/print_structure.asm
+++ b/labs/lab-06/tasks/print-structure/support/print_structure.asm
@@ -1,6 +1,6 @@
; SPDX-License-Identifier: BSD-3-Clause
-%include "printf32.asm"
+%include "printf64.asm"
struc stud_struct
name: resb 32
@@ -33,49 +33,37 @@ section .text
extern printf
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
; TODO: Update name, surname, birth_year, gender and age such that:
; birth_year is 1993
; age is 22
; group is '323CA'
- lea eax, [sample_student + name]
- push eax
- push format_name
+ lea rsi, [sample_student + name]
+ mov rdi, format_name
call printf
- add esp, 8
- lea eax, [sample_student + surname]
- push eax
- push format_surname
+ lea rsi, [sample_student + surname]
+ mov rdi, format_surname
call printf
- add esp, 8
- movzx eax, byte [sample_student + age]
- push eax
- push format_age
+ movzx rsi, byte [sample_student + age]
+ mov rdi, format_age
call printf
- add esp, 8
- lea eax, [sample_student + group]
- push eax
- push format_group
+ lea rsi, [sample_student + group]
+ mov rdi, format_group
call printf
- add esp, 8
- movzx eax, byte [sample_student + gender]
- push eax
- push format_gender
+ movzx rsi, byte [sample_student + gender]
+ mov rdi, format_gender
call printf
- add esp, 8
- movzx eax, word [sample_student + birth_year]
- push eax
- push format_year
+ movzx rsi, word [sample_student + birth_year]
+ mov rdi, format_year
call printf
- add esp, 8
leave
ret
diff --git a/labs/lab-06/tasks/print-structure/utils/printf32.asm b/labs/lab-06/tasks/print-structure/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-06/tasks/print-structure/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-06/tasks/print-structure/utils/printf64.asm b/labs/lab-06/tasks/print-structure/utils/printf64.asm
new file mode 100644
index 000000000..358881592
--- /dev/null
+++ b/labs/lab-06/tasks/print-structure/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-08/guides/disassembling-c/README.md b/labs/lab-08/guides/disassembling-c/README.md
index 1c8863a85..ec0f718ca 100644
--- a/labs/lab-08/guides/disassembling-c/README.md
+++ b/labs/lab-08/guides/disassembling-c/README.md
@@ -23,7 +23,7 @@ We'll use the `test.c` program from the lab archive.
1. Use the command:
```Bash
-gcc -m32 -o
+gcc -fno-PIC -o
```
where `` is the name of the source file (`test.c`) and `` is the name of the result executable.
@@ -31,7 +31,7 @@ where `` is the name of the source file (`test.c`) and `` is t
If you **only** want to compile (**without** linking it), use:
```Bash
-gcc -m32 -c -o
+gcc -fno-PIC -c -o
```
where `` is the name of the source file and `` is the name of the desired output object file.
@@ -39,7 +39,7 @@ where `` is the name of the source file and `` is the name
Since we want to transform `test.c` into an object file, we'll run:
```Bash
-gcc -m32 -c -o test.o test.c
+gcc -fno-PIC -c -o test.o test.c
```
After running the above command, we should see a file named `test.o`.
@@ -47,7 +47,7 @@ After running the above command, we should see a file named `test.o`.
Furthermore, we can use `gcc` to transform the `C` code in `Assembly` code:
```Bash
-gcc -m32 -masm=intel -S -o test.asm test.c
+gcc -fno-PIC -masm=intel -S -o test.asm test.c
```
After running the above command we'll have a file called `test.asm`, which we can inspect using any text editor/reader, such as cat:
@@ -69,80 +69,64 @@ Afterwards, you'll see an output similar to the following:
```console
$ objdump -M intel -d test.o
-test.o: file format elf32-i386
+test.o: file format elf64-x86-64
Disassembly of section .text:
-00000000 :
- 0: 55 push ebp
- 1: 89 e5 mov ebp,esp
- 3: e8 fc ff ff ff call 4
- 8: 05 01 00 00 00 add eax,0x1
- d: 8b 45 08 mov eax,DWORD PTR [ebp+0x8]
- 10: 8b 10 mov edx,DWORD PTR [eax]
- 12: 8b 45 0c mov eax,DWORD PTR [ebp+0xc]
- 15: 01 c2 add edx,eax
- 17: 8b 45 08 mov eax,DWORD PTR [ebp+0x8]
- 1a: 89 10 mov DWORD PTR [eax],edx
- 1c: 90 nop
- 1d: 5d pop ebp
- 1e: c3 ret
-
-0000001f :
- 1f: 55 push ebp
- 20: 89 e5 mov ebp,esp
- 22: 53 push ebx
- 23: 83 ec 14 sub esp,0x14
- 26: e8 fc ff ff ff call 27
- 2b: 05 01 00 00 00 add eax,0x1
- 30: c7 45 f4 03 00 00 00 mov DWORD PTR [ebp-0xc],0x3
- 37: 83 ec 0c sub esp,0xc
- 3a: 8d 90 00 00 00 00 lea edx,[eax+0x0]
- 40: 52 push edx
- 41: 89 c3 mov ebx,eax
- 43: e8 fc ff ff ff call 44
- 48: 83 c4 10 add esp,0x10
- 4b: 83 ec 08 sub esp,0x8
- 4e: ff 75 f4 push DWORD PTR [ebp-0xc]
- 51: 8d 45 08 lea eax,[ebp+0x8]
- 54: 50 push eax
- 55: e8 a6 ff ff ff call 0
- 5a: 83 c4 10 add esp,0x10
- 5d: 8b 45 08 mov eax,DWORD PTR [ebp+0x8]
- 60: 8b 5d fc mov ebx,DWORD PTR [ebp-0x4]
- 63: c9 leave
- 64: c3 ret
-
-00000065 :
- 65: 8d 4c 24 04 lea ecx,[esp+0x4]
- 69: 83 e4 f0 and esp,0xfffffff0
- 6c: ff 71 fc push DWORD PTR [ecx-0x4]
- 6f: 55 push ebp
- 70: 89 e5 mov ebp,esp
- 72: 53 push ebx
- 73: 51 push ecx
- 74: e8 fc ff ff ff call 75
- 79: 81 c3 02 00 00 00 add ebx,0x2
- 7f: 83 ec 0c sub esp,0xc
- 82: 6a 0f push 0xf
- 84: e8 96 ff ff ff call 1f
- 89: 83 c4 10 add esp,0x10
- 8c: 83 ec 08 sub esp,0x8
- 8f: 50 push eax
- 90: 8d 83 0e 00 00 00 lea eax,[ebx+0xe]
- 96: 50 push eax
- 97: e8 fc ff ff ff call 98
- 9c: 83 c4 10 add esp,0x10
- 9f: b8 00 00 00 00 mov eax,0x0
- a4: 8d 65 f8 lea esp,[ebp-0x8]
- a7: 59 pop ecx
- a8: 5b pop ebx
- a9: 5d pop ebp
- aa: 8d 61 fc lea esp,[ecx-0x4]
- ad: c3 ret
+0000000000000000 :
+ 0: f3 0f 1e fa endbr64
+ 4: 55 push rbp
+ 5: 48 89 e5 mov rbp,rsp
+ 8: 48 89 7d f8 mov QWORD PTR [rbp-0x8],rdi
+ c: 89 75 f4 mov DWORD PTR [rbp-0xc],esi
+ f: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8]
+ 13: 8b 10 mov edx,DWORD PTR [rax]
+ 15: 8b 45 f4 mov eax,DWORD PTR [rbp-0xc]
+ 18: 01 c2 add edx,eax
+ 1a: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8]
+ 1e: 89 10 mov DWORD PTR [rax],edx
+ 20: 90 nop
+ 21: 5d pop rbp
+ 22: c3 ret
+
+0000000000000023 :
+ 23: f3 0f 1e fa endbr64
+ 27: 55 push rbp
+ 28: 48 89 e5 mov rbp,rsp
+ 2b: 48 83 ec 20 sub rsp,0x20
+ 2f: 89 7d ec mov DWORD PTR [rbp-0x14],edi
+ 32: c7 45 fc 03 00 00 00 mov DWORD PTR [rbp-0x4],0x3
+ 39: bf 00 00 00 00 mov edi,0x0
+ 3e: e8 00 00 00 00 call 43
+ 43: 8b 55 fc mov edx,DWORD PTR [rbp-0x4]
+ 46: 48 8d 45 ec lea rax,[rbp-0x14]
+ 4a: 89 d6 mov esi,edx
+ 4c: 48 89 c7 mov rdi,rax
+ 4f: e8 ac ff ff ff call 0
+ 54: 8b 45 ec mov eax,DWORD PTR [rbp-0x14]
+ 57: c9 leave
+ 58: c3 ret
+
+0000000000000059 :
+ 59: f3 0f 1e fa endbr64
+ 5d: 55 push rbp
+ 5e: 48 89 e5 mov rbp,rsp
+ 61: bf 0f 00 00 00 mov edi,0xf
+ 66: e8 b8 ff ff ff call 23
+ 6b: 89 c6 mov esi,eax
+ 6d: bf 00 00 00 00 mov edi,0x0
+ 72: b8 00 00 00 00 mov eax,0x0
+ 77: e8 00 00 00 00 call 7c
+ 7c: b8 00 00 00 00 mov eax,0x0
+ 81: 5d pop rbp
+ 82: c3 ret
```
+You may notice the repeated occurrences of the `endbr64` instruction.
+It is part of `Intel's Control-Flow Enforcement Technology(CET)` and its purpose is to prevent malicious function executions (such as corrupting buffers and trying to alter the normal execution flow of the program).
+Detailed explanations about this instruction can be found in the [Buffer Management](https://cs-pub-ro.github.io/hardware-software-interface/labs/lab-10/README.html) lab.
+
There are many other utilities that allow disassembly of object modules, most of them with a graphical interface and offering debugging support.
`objdump` is a simple utility that can be quickly used from the command-line.
diff --git a/labs/lab-08/guides/disassembling-c/support/Makefile b/labs/lab-08/guides/disassembling-c/support/Makefile
index da01c2a93..cf8d1b06e 100644
--- a/labs/lab-08/guides/disassembling-c/support/Makefile
+++ b/labs/lab-08/guides/disassembling-c/support/Makefile
@@ -1,7 +1,7 @@
CC = gcc
-CFLAGS ?= -m32 -g -Wall -Wextra -Werror -fno-pic -masm=intel
-LDFLAGS ?= -m32 -no-pie
+CFLAGS ?= -g -Wall -Wextra -Werror -fno-pic -masm=intel
+LDFLAGS ?= -fno-PIC -no-pie
all: test
diff --git a/labs/lab-08/guides/hello-world/support/Makefile b/labs/lab-08/guides/hello-world/support/Makefile
index 55f0f26d0..d03974a7f 100644
--- a/labs/lab-08/guides/hello-world/support/Makefile
+++ b/labs/lab-08/guides/hello-world/support/Makefile
@@ -6,9 +6,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 ?= -fno-PIC -no-pie
all: hello_world
diff --git a/labs/lab-08/guides/hello-world/support/hello_world.asm b/labs/lab-08/guides/hello-world/support/hello_world.asm
index 4fd172d3f..34c86aca5 100644
--- a/labs/lab-08/guides/hello-world/support/hello_world.asm
+++ b/labs/lab-08/guides/hello-world/support/hello_world.asm
@@ -1,4 +1,4 @@
-%include "../utils/printf32.asm"
+%include "../utils/printf64.asm"
section .data
msg db 'Hello, world!', 0
@@ -12,12 +12,11 @@ extern puts
global main
main:
- push ebp ; Since main is a function, it has to adhere to the same convention
- mov ebp, esp
+ push rbp ; Since main is a function, it has to adhere to the same convention
+ mov rbp, rsp
- push msg
+ mov rdi, msg ; store the address of the string in rdi
call puts
- add esp, 4 ; The pushed msg argument takes up 4 bytes on the stack
leave
ret
diff --git a/labs/lab-08/guides/hello-world/utils/printf32.asm b/labs/lab-08/guides/hello-world/utils/printf32.asm
deleted file mode 100644
index 61a930ed7..000000000
--- a/labs/lab-08/guides/hello-world/utils/printf32.asm
+++ /dev/null
@@ -1,22 +0,0 @@
-;;; 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-08/guides/hello-world/utils/printf64.asm b/labs/lab-08/guides/hello-world/utils/printf64.asm
new file mode 100644
index 000000000..e799a46e0
--- /dev/null
+++ b/labs/lab-08/guides/hello-world/utils/printf64.asm
@@ -0,0 +1,73 @@
+; SPDX-License-Identifier: BSD-3-Clause
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-08/guides/registers-terminator/README.md b/labs/lab-08/guides/registers-terminator/README.md
new file mode 100644
index 000000000..31d7c79e4
--- /dev/null
+++ b/labs/lab-08/guides/registers-terminator/README.md
@@ -0,0 +1,49 @@
+---
+nav_order: 9
+parent: Lab 8 - Functions
+---
+
+# Guide: Registers Terminator
+
+Navigate to `guides/registers-terminator/support/`.
+
+Open the `registers_terminator.asm` file, assemble it, and run it.
+
+The purpose of this guide is to really make you aware how caller-saved registers **need to** be saved by the `caller`.
+It is also important to notice that the `rbx` and `r12-r15` registers are preserved(`callee saved`).
+
+In the presented assembly file, we set some values to the `rax`, `rcx`, `rdx`, `rsi`, `rdi`, `r8` and `r9` simulating a normal program flow.
+We print their values and then call the libc `printf` function and then print their values again.
+The output can look similar to this one:
+
+```console
+rax=1
+rcx=2
+rdx=3
+rsi=4
+rdi=404018
+r8=6
+r9=7
+rbx=8
+r12=9
+r13=a
+r14=b
+r15=c
+Hello, world!
+rax=e
+rcx=0
+rdx=0
+rsi=13e5b2a0
+rdi=1463ae00
+r8=6
+r9=7
+rbx=8
+r12=9
+r13=a
+r14=b
+r15=c
+```
+
+We can easily notice that the values of the `rax`, `rcx`, `rdx`, `rsi` and `rdi` registers have been completely altered.
+If those were real values and we would have needed them after the `printf` call, the results would be unpredictable but, certainly, wrong.
+However, we can observe that the `callee-saved` registers remained untouched.
diff --git a/labs/lab-08/guides/registers-terminator/support/.gitignore b/labs/lab-08/guides/registers-terminator/support/.gitignore
new file mode 100644
index 000000000..0900dce2e
--- /dev/null
+++ b/labs/lab-08/guides/registers-terminator/support/.gitignore
@@ -0,0 +1 @@
+registers_terminator
diff --git a/labs/lab-08/guides/registers-terminator/support/Makefile b/labs/lab-08/guides/registers-terminator/support/Makefile
new file mode 100644
index 000000000..0811ea119
--- /dev/null
+++ b/labs/lab-08/guides/registers-terminator/support/Makefile
@@ -0,0 +1,23 @@
+AS = nasm
+CC = gcc
+
+SRCS := $(shell find . -name "*.asm")
+OBJS := $(SRCS:.asm=.o)
+
+UTILSDIR := ..utils/
+
+ASFLAGS ?= -f elf64 -F dwarf -I "$(UTILSDIR)"
+CFLAGS ?= -Wall
+LDFLAGS ?= -fno-PIC -no-pie
+
+all: registers_terminator
+
+registers_terminator: registers_terminator.o
+
+%.o: %.asm
+ $(AS) $(ASFLAGS) $< -o $@
+
+.PHONY: clean
+
+clean:
+ -rm -f *.o registers_terminator
diff --git a/labs/lab-08/guides/registers-terminator/support/registers_terminator.asm b/labs/lab-08/guides/registers-terminator/support/registers_terminator.asm
new file mode 100644
index 000000000..caf8ba984
--- /dev/null
+++ b/labs/lab-08/guides/registers-terminator/support/registers_terminator.asm
@@ -0,0 +1,53 @@
+%include "../utils/printf64.asm"
+
+section .data
+ msg db 10, 'printf called now', 10, 10, 0
+
+section .text
+
+; We need to mark "printf()" as an external function. This means it is not implemented in this file.
+; The linker will resolve this symbol by looking for it in other object files.
+extern printf
+
+global main
+
+main:
+ push rbp ; Since main is a function, it has to adhere to the same convention
+ mov rbp, rsp
+
+ ; store information in registers that should be caller saved,
+ ; rax, rcx, rdx, rsi, rdi, r8, r9
+ mov rax, 0x1
+ mov rcx, 0x2
+ mov rdx, 0x3
+ mov rsi, 0x4
+ mov rdi, msg
+ mov r8, 0x6
+ mov r9, 0x7
+
+ ; store information in registers that should be callee saved,
+ ; rbx, r12, r13, r14, r15
+ mov rbx, 0x8
+ mov r12, 0x9
+ mov r13, 0xa
+ mov r14, 0xb
+ mov r15, 0xc
+
+ ; print the caller-saved registers before the call
+ PRINTF64 `rax=%x\nrcx=%x\nrdx=%x\nrsi=%x\nrdi=%x\n`, rax, rcx, rdx, rsi, rdi
+ PRINTF64 `r8=%x\nr9=%x\n`, r8, r9
+
+ ; print the callee-saved registers before the call
+ PRINTF64 `rbx=%x\nr12=%x\nr13=%x\nr14=%x\nr15=%x\n`, rbx, r12, r13, r14, r15
+
+ call printf
+
+ ; print the registers after the call
+ PRINTF64 `rax=%x\nrcx=%x\nrdx=%x\nrsi=%x\nrdi=%x\n`, rax, rcx, rdx, rsi, rdi
+ PRINTF64 `r8=%x\nr9=%x\n`, r8, r9
+
+ ; print the callee-saved registers after the call
+ PRINTF64 `rbx=%x\nr12=%x\nr13=%x\nr14=%x\nr15=%x\n`, rbx, r12, r13, r14, r15
+
+ leave
+ ret
diff --git a/labs/lab-08/guides/registers-terminator/utils/printf64.asm b/labs/lab-08/guides/registers-terminator/utils/printf64.asm
new file mode 100644
index 000000000..e799a46e0
--- /dev/null
+++ b/labs/lab-08/guides/registers-terminator/utils/printf64.asm
@@ -0,0 +1,73 @@
+; SPDX-License-Identifier: BSD-3-Clause
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-08/media/stack.svg b/labs/lab-08/media/stack.svg
index 0a4d6aaa8..288a44f37 100644
--- a/labs/lab-08/media/stack.svg
+++ b/labs/lab-08/media/stack.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/labs/lab-08/reading/functions.md b/labs/lab-08/reading/functions.md
index ab0430c3d..f48975f3f 100644
--- a/labs/lab-08/reading/functions.md
+++ b/labs/lab-08/reading/functions.md
@@ -38,13 +38,14 @@ When it comes to calling a function with parameters, there are two major options
> **NOTE:** For **32-bit** architectures, the stack passing method is used, while for **64-bit** architectures, the register passing method is used for the first 6 arguments.
> Starting from the 7th, the stack has to be used.
-> We will use the convention for 32-bit architecture.
+> We will use the convention for 64-bit architecture.
## Function Call
When we call a function, the steps are as follows:
-- We put the arguments on the stack, pushing them in the reverse order in which they are sent as function arguments.
+- We put the first 6 arguments(if there are at least 6 arguments) in the following registers in left-to-right order: `rdi`, `rsi`, `rdx`, `rcx`, `r8` and `r9`.
+- We put the remaining arguments on the stack, pushing them in the reverse order in which they are sent as function arguments.
- We call `call`.
- We restore the stack at the end of the call.
@@ -56,32 +57,36 @@ As we know, stack operations fall into two types:
- `pop reg/mem` where what is on the top of the stack is placed into a register or memory area
When we `push`, we say that the stack **grows** (elements are added).
-For reasons that will be better explained later, the stack pointer (indicated by the `esp` register in 32-bit mode) decreases in value when the stack grows (on `push`).
+For reasons that will be better explained later, the stack pointer (indicated by the `rsp` register in 64-bit mode) decreases in value when the stack grows (on `push`).
However, this contradiction in naming comes from the fact that the stack is typically represented vertically, with smaller values at the top and larger values at the bottom.
Similarly, when we `pop`, we say that the stack **shrinks** (elements are removed).
-Now the stack pointer (indicated by the `esp` register in 32-bit mode) increases in value.
+Now the stack pointer (indicated by the `rsp` register in 64-bit mode) increases in value.
-A summary of this is explained very well [here](https://en.wikibooks.org/wiki/X86_Disassembly/The_Stack).
+A summary of this is explained very well [here](https://en.wikibooks.org/wiki/X86_Disassembly/The_Stack) and [here](https://medium.com/@_neerajpal/explained-difference-between-x86-x64-disassembly-49e9678e1ae2).
For example, if we have the function `foo` with the following signature (in C language):
```C
-int foo(int a, int b, int c);
+long foo(long a, long b, long c, long d,
+ long e, long f, long g, long h);
```
The call to this function will look like this:
```Assembly
-mov ecx, [c] ; take the value of parameter c from a memory location
-mov ebx, [b]
-mov eax, [a]
+mov rdi, [a] ; store the first 6 arguments in the assigned registers
+mov rsi, [b]
+mov rdx, [c]
+mov rcx, [d]
+mov r8, [e]
+mov r9, [f]
+
+push qword [h] ; put the last 2 arguments onto the stack in reverse order, first h
+push qworg [g] ; then g
-push ecx ; put parameters in reverse order, starting with c
-push ebx ; then b
-push eax ; then a
call foo ; call the function
-add esp, 12 ; restore the stack
+add rsp, 16 ; restore the stack
```
## Caller and Callee
@@ -94,22 +99,24 @@ Until the `call` instruction, the stack contains the function's parameters.
The `call` can be roughly equated to the following sequence:
```Assembly
-push eip
+push rip
jmp function_name
```
That is, even the `call` uses the stack and saves the address of the next instruction, the one after the `call`, also known as the **return address**.
This is necessary for the callee to know where to return to in the caller.
-In the callee, at its beginning (called preamble), the frame pointer is saved (in the i386 architecture, this is the `ebp` register), with the frame pointer then referring to the current function stack frame.
+In the callee, at its beginning (called preamble), the frame pointer is saved (in the X86_64 architecture, this is the `rbp` register), with the frame pointer then referring to the current function stack frame.
This is crucial for accessing parameters and local variables via an offset from the frame pointer.
Although not mandatory, saving the frame pointer helps in debugging and is used in most cases.
+Also, in order to avoid any issues at runtime, it is imperative to keep the stack `16-byte aligned` by saving the `rbp` register in the preamble of the function.
+Not having the stack `16-byte aligned` may cause some `libc` functions (such as `printf`) to end up causing a `Segmentation Fault` for a program that, besides that misalignment, would be correct.
For these reasons, any function call will generally have a preamble:
```Assembly
-push ebp
-mov ebp, esp
+push rbp
+mov rbp, rsp
```
These modifications take place in the callee.
@@ -124,12 +131,12 @@ After this instruction, the stack is as it was at the beginning of the function
It is equivalent to the following code, which undoes the functions's preamble:
```Assembly
-mov esp, ebp
-pop ebp
+mov rsp, rbp
+pop rbp
```
To conclude the function, it is necessary for the execution to return and continue from the instruction following the `call` that started the function.
-This involves influencing the `eip` register and putting back the value that was saved on the stack initially by the `call` instruction.
+This involves influencing the `rip` register and putting back the value that was saved on the stack initially by the `call` instruction.
This is achieved using the instruction:
```Assembly
@@ -139,23 +146,27 @@ ret
which is roughly equivalent to the instruction:
```Assembly
-pop eip
+pop rip
```
-For example, the definition and body of the function foo, which calculates the sum of 3 numbers, would look like this:
+For example, the definition and body of the function foo, which calculates the sum of 8 numbers, would look like this:
```Assembly
foo:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- mov eax, [ebp + 8]
- mov ebx, [ebp + 12]
- mov ecx, [ebp + 16]
+ mov rax, [rbp + 16] ; get the two arguments pushed onto the stack
+ mov rbx, [rbp + 24]
- add eax, ebx
- add eax, ecx
+ add rax, rdi
+ add rax, rsi
+ add rax, rdx
+ add rax, rcx
+ add rax, r8
+ add rax, r9
+ add rax, rbx ; the result is stored in rax
leave
ret
@@ -172,19 +183,23 @@ foo:
1. Note that during the execution of the function, what does not change is the position of the frame pointer.
This is the reason for its name: it points to the current function's frame.
Therefore, it is common to access a function's parameters through the frame pointer.
-Assuming a 32-bit system and processor word-sized parameters (32 bits, 4 bytes), we will have:
-
- - the first argument is found at address `ebp+8`
- - the second argument is found at address `ebp+12`
- - the third argument is found at address `ebp+16`
+Assuming a 64-bit system and processor word-sized parameters (64 bits, 8 bytes), we will have:
+
+ - the first argument is found in the `rdi` register
+ - the second argument is found in the `rsi` register
+ - the third argument is found in the `rdx` register
+ - the fourth argument is found in the `rcx` register
+ - the fifth argument is found in the `r8` register
+ - the sixth argument is found in the `r9` register
+ - the seventh argument is found at address `rbp + 16`
+ - the eighth argument is found at address `rbp + 24`
- etc.
- This is why, to get the parameters of the foo function in the eax, ebx, ecx registers, we use the constructions:
+ This is why, to get the parameters of the foo function in the rax and rbx registers, we use the constructions:
```Assembly
- mov eax, dword [ebp+8] ; first argument in eax
- mov ebx, dword [ebp+12] ; second argument in ebx
- mov ecx, dword [ebp+16] ; third argument in ecx
+ mov rax, qword [rbp + 16] ; seventh argument in rax
+ mov rbx, qword [rbp + 24] ; eighth argument in rbx
```
1. The return value of a function is placed in registers (generally in eax).
@@ -192,21 +207,25 @@ Assuming a 32-bit system and processor word-sized parameters (32 bits, 4 bytes),
- If the return value is **8 bits**, the function's result is placed in `al`.
- If the return value is **16 bits**, the function's result is placed in `ax`.
- If the return value is **32 bits**, the function's result is placed in `eax`.
- - If the return value is **64 bits**, the result is placed in the `edx` and `eax` registers.
- The most significant 32 bits are placed in `edx`, and the rest in the `eax` register.
+ - If the return value is **64 bits**, the function's result is placed in `rax`.
+ - If the return value is **>= 128 bits**, the result is placed in the `rdx` and `rax` registers.
+ The most significant bits are placed in `rdx` and the rest in `rax`.
_Additionally, in some cases, a memory address can be returned to the stack/heap (e.g. `malloc()`), or other memory areas, which refer to the desired object after the function call._
1. A function uses the same hardware registers;
therefore, when exiting the function, the values of the registers are no longer the same.
To avoid this situation, some/all registers can be saved on the stack.
-You can push all registers to the stack using the [`pusha` instruction - "push all"](https://c9x.me/x86/html/file_module_x86_id_270.html).
-And you can pop them all in the same order using [`popa`](https://c9x.me/x86/html/file_module_x86_id_249.html).
+If we consider a 32-bit architecture, one can push all registers to the stack using the [`pusha` instruction - "push all"](https://c9x.me/x86/html/file_module_x86_id_270.html).
+And one can pop them all in the same order using [`popa`](https://c9x.me/x86/html/file_module_x86_id_249.html).
The disadvantage of doing so is that writing all registers to the stack is going to be slower than only explicitly saving the registers used by the function.
-For this reason, the `cdecl` calling convention specifies that functions are allowed to change the values of the `eax`, `ecx` and `edx` registers.
+However, on a 64-bit architecture, those two instructions are not available and the preserving must be done by hand.
+More details on the behaviour of these functions on a 64-bit architecture can be found [here](https://www.felixcloutier.com/x86/pusha:pushad).
+For this reason, the `System V AMD64 ABI` calling convention specifies that functions are allowed to change the values of the `rax`, `rcx`, `rdx`, `rsi`, `rdi` and `r8-r11` registers.
> **NOTE:** Since assembly languages offer more opportunities, there is a need for calling conventions in x86.
> The difference between them may consist of the parameter order, how the parameters are passed to the function, which registers need to be preserved by the callee or whether the caller or callee handles stack preparation.
-> More details can be found [here](https://en.wikipedia.org/wiki/X86_calling_conventions) or [here](https://levelup.gitconnected.com/x86-calling-conventions-a34812afe097) if Wikipedia is too mainstream for you.
-> For us, the registers `eax`, `ecx`, `edx` are considered **clobbered** (or volatile), and the callee can do whatever it wants to them.
-> On the other hand, the callee has to ensure that `ebx` exits the function with the same value it has entered with.
+> More details can be found [here](https://en.wikipedia.org/wiki/X86_calling_conventions) or [here](https://aaronbloomfield.github.io/pdr/book/x86-64bit-ccc-chapter.pdf) and [here](https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170) if Wikipedia is too mainstream for you.
+> For us, the registers `rax`, `rcx`, `rdx`, `rsi`, `rdi` and `r8-r11` are considered **clobbered** (or volatile), and the callee can do whatever it wants to them.
+> On the other hand, the callee has to ensure that `rbx` and `r12-r15` exit the function with the same value they have entered with.
+> If you want to read more about why the `stack alignment` is needed, you can check out [this](https://stackoverflow.com/questions/49391001/why-does-the-x86-64-amd64-system-v-abi-mandate-a-16-byte-stack-alignment).
diff --git a/labs/lab-08/tasks/print-rev-string/README.md b/labs/lab-08/tasks/print-rev-string/README.md
index cb0ca9712..ee635a74d 100644
--- a/labs/lab-08/tasks/print-rev-string/README.md
+++ b/labs/lab-08/tasks/print-rev-string/README.md
@@ -1,5 +1,5 @@
---
-nav_order: 3
+nav_order: 4
parent: Lab 8 - Functions
---
@@ -17,38 +17,41 @@ extern puts
global print_reverse_string
reverse_string:
- push ebp
- mov ebp, esp
- push ebx ; preserve ebx as required by cdecl
-
- mov eax, [ebp + 8]
- mov ecx, [ebp + 12]
- add eax, ecx
- dec eax
- mov edx, [ebp + 16]
-
-copy_one_byte:
- mov bl, [eax]
- mov [edx], bl
- dec eax
- inc edx
- loopnz copy_one_byte
-
- inc edx
- mov byte [edx], 0
-
- pop ebx ; restore ebx
+ push rbp
+ mov rbp, rsp
+
+ mov rax, rdi ; get the address of the string
+ mov rcx, rsi ; get the length of the string
+ ; the address of the buffer to store the reversed string is already in rdx
+
+ test rcx, rcx ; check if length is zero
+ jz done ; if zero, skip to null termination
+
+ add rax, rcx ; point to one past the last character
+ dec rax ; point to the last character
+
+copy_loop:
+ mov bl, [rax] ; get a byte from the source
+ mov [rdx], bl ; store it in the destination
+ dec rax ; move to previous character in source
+ inc rdx ; move to next character in destination
+ dec rcx ; decrease counter
+ jnz copy_loop ; if counter not zero, continue loop
+
+done:
+ mov byte [rdx], 0 ; null-terminate the destination string
+
leave
ret
print_reverse_string:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
[...]
```
> **IMPORTANT:** When copying the `reverse_string()` function into your program, remember that the function starts at the `reverse_string()` label and ends at the `print_reverse_string` label.
-> The `copy_one_byte` label is part of the `reverse_string()` function.
+> The `copy_loop` and `done` labels are part of the `reverse_string()` function.
The `reverse_string()` function reverses a string and has the following signature: `void reverse_string(const char *src, size_t len, char *dst);`.
This means that the first `len` characters of the `src` string are reversed into the `dst` string.
@@ -62,19 +65,32 @@ Reverse the `mystring` string into a new string and display that new string.
> ```
>
> This creates a string of 64 zero bytes, enough to store the reverse of the string.
-> The equivalent C function call is `reverse_string(mystring, ecx, store_string);`.
-> We assume that the length of the string is calculated and stored in the `ecx` register.
+> The equivalent C function call is `reverse_string(mystring, rcx, store_string);`.
+> We assume that the length of the string is calculated and stored in the `rcx` register.
>
-> You cannot directly use the value of `ecx` in its current form.
-> After the `printf()` function call for displaying the length, the value of `ecx` is not preserved.
+> You cannot directly use the value of `rcx` in its current form.
+> After the `printf()` function call for displaying the length, the value of `rcx` is not preserved.
> To retain it, you have two options:
>
-> 1. Store the value of the `ecx` register on the stack beforehand (using `push ecx` before the `printf` call) and then restore it after the `printf` call (using `pop ecx`).
-> 1. Store the value of the `ecx` register in a global variable, which you define in the `.data` section.
+> 1. Store the value of the `rcx` register on the stack beforehand (using `push rcx` before the `printf` call) and decrease the value of `rsp` by `8` in order to align the stack and then increase the value of `rsp` by `8` and restore it after the `printf` call (using `pop rcx`).
+> 1. Store the value of the `rcx` register in a global variable, which you define in the `.data` section.
>
> You cannot use another register because there is a high chance that even that register will be modified by the `printf` call to display the length of the string.
-To test the implementation, enter the `tests/` directory and run:
+After you consider your implementation complete, it is recommended to first run it `manually` in order to assess its correctness.
+In order to do so, enter the `support/` directory and run:
+
+```console
+make
+```
+
+If your code successfully compiled, you can then run the binary like so:
+
+```console
+./print_reverse_string
+```
+
+To fully test the implementation, enter the `tests/` directory and run:
```console
make check
diff --git a/labs/lab-08/tasks/print-rev-string/solution/main.asm b/labs/lab-08/tasks/print-rev-string/solution/main.asm
index bba49131d..8f0af9e57 100644
--- a/labs/lab-08/tasks/print-rev-string/solution/main.asm
+++ b/labs/lab-08/tasks/print-rev-string/solution/main.asm
@@ -1,6 +1,6 @@
section .data
mystring db "This is my string", 0
- print_format db "String length is %d", 10, 0
+ fmt_str db "[before]: %s", 10, "[after]: ", 0
section .text
@@ -9,34 +9,37 @@ extern print_reverse_string
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
+
+ mov rax, mystring
+ xor rcx, rcx
- mov eax, mystring
- xor ecx, ecx
test_one_byte:
- mov bl, [eax]
+ mov bl, [rax]
test bl, bl
je out
- inc eax
- inc ecx
+ inc rax
+ inc rcx
jmp test_one_byte
out:
- ; save ecx's value since it can be changed by printf
- push ecx
+ ; save rcx's value since it can be changed by printf
+ push rcx
+ ; align the stack
+ sub rsp, 8
- push ecx
- push print_format
+ mov rdi, fmt_str
+ mov rsi, mystring
call printf
- add esp, 8
- pop ecx
+ add rsp, 8
+ ; restore rcx's value
+ pop rcx
- push ecx
- push mystring
+ mov rdi, mystring
+ mov rsi, rcx
call print_reverse_string
- add esp, 8
leave
ret
diff --git a/labs/lab-08/tasks/print-rev-string/solution/print_reverse_string.asm b/labs/lab-08/tasks/print-rev-string/solution/print_reverse_string.asm
index a85784e6c..99031e3f1 100644
--- a/labs/lab-08/tasks/print-rev-string/solution/print_reverse_string.asm
+++ b/labs/lab-08/tasks/print-rev-string/solution/print_reverse_string.asm
@@ -7,53 +7,53 @@ extern puts
global print_reverse_string
reverse_string:
- push ebp
- mov ebp, esp
- push ebx ; preserve ebx as required by cdecl
+ push rbp
+ mov rbp, rsp
- mov eax, [ebp + 8] ; get the address of the string
- mov ecx, [ebp + 12] ; get the length of the string
- mov edx, [ebp + 16] ; get the address of the buffer
+ sub rsp, 8 ; leave room in order to align the stack
+ push rbx ; preserve rbx as required by the System V AMD64 ABI
- test ecx, ecx ; check if length is zero
+ mov rax, rdi ; get the address of the string
+ mov rcx, rsi ; get the length of the string
+ ; the address of the buffer to store the reversed string is already in rdx
+
+ test rcx, rcx ; check if length is zero
jz done ; if zero, skip to null termination
- add eax, ecx ; point to one past the last character
- dec eax ; point to the last character
+ add rax, rcx ; point to one past the last character
+ dec rax ; point to the last character
copy_loop:
- mov bl, [eax] ; get a byte from the source
- mov [edx], bl ; store it in the destination
- dec eax ; move to previous character in source
- inc edx ; move to next character in destination
- dec ecx ; decrease counter
+ mov bl, [rax] ; get a byte from the source
+ mov [rdx], bl ; store it in the destination
+ dec rax ; move to previous character in source
+ inc rdx ; move to next character in destination
+ dec rcx ; decrease counter
jnz copy_loop ; if counter not zero, continue loop
done:
- mov byte [edx], 0 ; null-terminate the destination string
+ mov byte [rdx], 0 ; null-terminate the destination string
+
+ pop rbx ; restore rbx
+ add rsp, 8
- pop ebx ; restore ebx
leave
ret
print_reverse_string:
- push ebp
- mov ebp, esp
- push ebx ; preserve ebx as required by cdecl
+ push rbp
+ mov rbp, rsp
- mov eax, [ebp + 8] ; get the address of the string
- mov ecx, [ebp + 12] ; get the length of the string
+ mov rax, rdi ; get the address of the string
+ mov rcx, rsi ; get the length of the string
- push store_string
- push ecx
- push eax
+ mov rdi, rax
+ mov rsi, rcx
+ mov rdx, store_string
call reverse_string
- add esp, 12
- push store_string
+ mov rdi, store_string
call puts
- add esp, 4
- pop ebx
leave
ret
diff --git a/labs/lab-08/tasks/print-rev-string/support/Makefile b/labs/lab-08/tasks/print-rev-string/support/Makefile
index 3e10d1fe8..ba85d96c0 100644
--- a/labs/lab-08/tasks/print-rev-string/support/Makefile
+++ b/labs/lab-08/tasks/print-rev-string/support/Makefile
@@ -3,9 +3,9 @@ CC = gcc
UTILSDIR := ../utils/
-ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)"
+ASFLAGS ?= -f elf64 -F dwarf -I "$(UTILSDIR)"
CFLAGS ?= -Wall
-LDFLAGS ?= -m32 -no-pie
+LDFLAGS ?= -fno-PIC -no-pie
TARGET := print_reverse_string
OBJS := main.o print_reverse_string.o
diff --git a/labs/lab-08/tasks/print-rev-string/support/main.asm b/labs/lab-08/tasks/print-rev-string/support/main.asm
index 3d2dc036b..8f0af9e57 100644
--- a/labs/lab-08/tasks/print-rev-string/support/main.asm
+++ b/labs/lab-08/tasks/print-rev-string/support/main.asm
@@ -1,6 +1,6 @@
section .data
mystring db "This is my string", 0
- fmt_str db "[before]: %s\n[after]: ", 0
+ fmt_str db "[before]: %s", 10, "[after]: ", 0
section .text
@@ -9,29 +9,37 @@ extern print_reverse_string
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
+
+ mov rax, mystring
+ xor rcx, rcx
- mov eax, mystring
- xor ecx, ecx
test_one_byte:
- mov bl, [eax]
+ mov bl, [rax]
test bl, bl
je out
- inc eax
- inc ecx
+ inc rax
+ inc rcx
jmp test_one_byte
out:
- push mystring
- push fmt_str
+ ; save rcx's value since it can be changed by printf
+ push rcx
+ ; align the stack
+ sub rsp, 8
+
+ mov rdi, fmt_str
+ mov rsi, mystring
call printf
- add esp, 8
- push ecx
- push mystring
+ add rsp, 8
+ ; restore rcx's value
+ pop rcx
+
+ mov rdi, mystring
+ mov rsi, rcx
call print_reverse_string
- add esp, 8
leave
ret
diff --git a/labs/lab-08/tasks/print-rev-string/support/print_reverse_string.asm b/labs/lab-08/tasks/print-rev-string/support/print_reverse_string.asm
index c9a149044..49bd687c5 100644
--- a/labs/lab-08/tasks/print-rev-string/support/print_reverse_string.asm
+++ b/labs/lab-08/tasks/print-rev-string/support/print_reverse_string.asm
@@ -6,12 +6,14 @@ global print_reverse_string
; TODO: add the reverse_string() function
print_reverse_string:
- push ebp
- mov ebp, esp
- push ebx ; preserve ebx as required by cdecl
+ push rbp
+ mov rbp, rsp
+
+ ; TODO: save the used registers and align the stack, if needed
; TODO: call the reverse_string() function and print the reversed string
- pop ebx
+ ; TODO: restore the used registers and the stack pointer, if altered
+
leave
ret
diff --git a/labs/lab-08/tasks/print-rev-string/tests/.gitignore b/labs/lab-08/tasks/print-rev-string/tests/.gitignore
new file mode 100644
index 000000000..3f1376bb1
--- /dev/null
+++ b/labs/lab-08/tasks/print-rev-string/tests/.gitignore
@@ -0,0 +1,3 @@
+graded_test.o
+test_print_reverse_string.o
+test_print_reverse_string
diff --git a/labs/lab-08/tasks/print-rev-string/tests/Makefile b/labs/lab-08/tasks/print-rev-string/tests/Makefile
index af5297b1e..ba8c96746 100644
--- a/labs/lab-08/tasks/print-rev-string/tests/Makefile
+++ b/labs/lab-08/tasks/print-rev-string/tests/Makefile
@@ -1,8 +1,8 @@
SRC_PATH ?= ../support
FULL_SRC_PATH = "$(realpath $(SRC_PATH))"
CPPFLAGS = -I. -I$(FULL_SRC_PATH) -I../utils
-CFLAGS = -Wall -Wextra -m32
-LDFLAGS = -m32
+CFLAGS = -Wall -Wextra -m64
+LDFLAGS = -m64 -no-pie
# Remove the line below to disable debugging support.
CFLAGS += -g -O0
diff --git a/labs/lab-08/tasks/print-rev-string/utils/printf32.asm b/labs/lab-08/tasks/print-rev-string/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-08/tasks/print-rev-string/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-08/tasks/print-rev-string/utils/printf64.asm b/labs/lab-08/tasks/print-rev-string/utils/printf64.asm
new file mode 100644
index 000000000..e799a46e0
--- /dev/null
+++ b/labs/lab-08/tasks/print-rev-string/utils/printf64.asm
@@ -0,0 +1,73 @@
+; SPDX-License-Identifier: BSD-3-Clause
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-08/tasks/rot13/README.md b/labs/lab-08/tasks/rot13/README.md
index ff0ee8278..c8ebf6ef4 100644
--- a/labs/lab-08/tasks/rot13/README.md
+++ b/labs/lab-08/tasks/rot13/README.md
@@ -1,5 +1,5 @@
---
-nav_order: 5
+nav_order: 6
parent: Lab 8 - Functions
---
@@ -31,7 +31,20 @@ Thus, the initial string `lorem\0ipsum\0dolor\0` will translate to `yberz vcfhz
>
> where you either store the total length of the string (from the beginning to the last `NULL` byte) or the number of strings in the array.
-To test the implementation, enter the `tests/` directory and run:
+After you consider your implementation complete, it is recommended to first run it `manually` in order to assess its correctness.
+In order to do so, enter the `support/` directory and run:
+
+```console
+make
+```
+
+If your code successfully compiled, you can then run the binary like so:
+
+```console
+./rot13
+```
+
+To fully test the implementation, enter the `tests/` directory and run:
```console
make check
diff --git a/labs/lab-08/tasks/rot13/solution/Makefile b/labs/lab-08/tasks/rot13/solution/Makefile
deleted file mode 100644
index 2bb7f2e86..000000000
--- a/labs/lab-08/tasks/rot13/solution/Makefile
+++ /dev/null
@@ -1,24 +0,0 @@
-AS = nasm
-CC = gcc
-
-UTILSDIR := ../utils/
-
-ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)"
-CFLAGS ?= -Wall
-LDFLAGS ?= -m32 -no-pie
-
-TARGET := rot13
-OBJS := main.o rot13.o
-
-all: $(TARGET)
-
-$(TARGET): $(OBJS)
- $(CC) $(LDFLAGS) -o $@ $^
-
-%.o: %.asm
- $(AS) $(ASFLAGS) $< -o $@
-
-.PHONY: clean
-
-clean:
- -rm -f *.o $(TARGET)
diff --git a/labs/lab-08/tasks/rot13/solution/Makefile b/labs/lab-08/tasks/rot13/solution/Makefile
new file mode 120000
index 000000000..a39be4f20
--- /dev/null
+++ b/labs/lab-08/tasks/rot13/solution/Makefile
@@ -0,0 +1 @@
+../support/Makefile
\ No newline at end of file
diff --git a/labs/lab-08/tasks/rot13/solution/main.asm b/labs/lab-08/tasks/rot13/solution/main.asm
index 850b121ec..b8d42e282 100644
--- a/labs/lab-08/tasks/rot13/solution/main.asm
+++ b/labs/lab-08/tasks/rot13/solution/main.asm
@@ -10,19 +10,21 @@ extern rot13
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- mov eax, [length]
- push eax
+ mov rax, [length]
+
+ sub rsp, 8 ; align the stack
push mystring
+ mov rdi, mystring
+ mov rsi, rax
call rot13
- add esp, 8
+ add rsp, 8
- push mystring
- push after_fmt
+ mov rdi, after_fmt
+ mov rsi, mystring
call printf
- add esp, 8
leave
ret
diff --git a/labs/lab-08/tasks/rot13/solution/rot13.asm b/labs/lab-08/tasks/rot13/solution/rot13.asm
index 831c19269..77a56de39 100644
--- a/labs/lab-08/tasks/rot13/solution/rot13.asm
+++ b/labs/lab-08/tasks/rot13/solution/rot13.asm
@@ -2,18 +2,17 @@ section .text
global rot13
rot13:
- push ebp
- mov ebp, esp
- push ebx ; preserve ebx as required by cdecl
+ push rbp
+ mov rbp, rsp
- mov esi, [ebp + 8] ; pointer to input string
- mov ecx, [ebp + 12] ; length of the buffer
+ mov rcx, rsi ; length of the buffer
+ mov rsi, rdi ; pointer to the input string
loop:
- cmp ecx, 0 ; Check if there are more characters to process
+ cmp rcx, 0 ; Check if there are more characters to process
je done ; If no, we are done
- mov al, [esi] ; Load the current byte into AL register
+ mov al, [rsi] ; Load the current byte into AL register
cmp al, 0 ; Check if it's the null terminator
je handle_null ; If it's a null terminator, handle it
@@ -30,7 +29,7 @@ loop:
lower_store:
add al, 'a' ; Convert back to ASCII
- mov [esi], al ; Store the transformed character back
+ mov [rsi], al ; Store the transformed character back
jmp next
check_upper:
@@ -47,25 +46,25 @@ check_upper:
upper_store:
add al, 'A' ; Convert back to ASCII
- mov [esi], al ; Store the transformed character back
+ mov [rsi], al ; Store the transformed character back
next:
- inc esi ; Move to the next byte in the string
- dec ecx ; Decrement the length counter
+ inc rsi ; Move to the next byte in the string
+ dec rcx ; Decrement the length counter
jmp loop ; Repeat the loop
handle_null:
; We are at a null terminator, check if it's the last null terminator
; If so, just leave it and terminate the string
- cmp byte [esi + 1], 0 ; Check if the next byte is also a null terminator
+ cmp byte [rsi + 1], 0 ; Check if the next byte is also a null terminator
je done ; If yes, don't replace with a space
; Otherwise, replace null terminator with space
- mov byte [esi], ' '
- inc esi ; Move to the next byte
+ mov byte [rsi], ' '
+ inc rsi ; Move to the next byte
jmp loop
done:
- pop ebx ; Restore the preserved register
+
leave ; Clean up the stack frame
ret ; Return from the function
diff --git a/labs/lab-08/tasks/rot13/support/Makefile b/labs/lab-08/tasks/rot13/support/Makefile
index 2bb7f2e86..668cefd87 100644
--- a/labs/lab-08/tasks/rot13/support/Makefile
+++ b/labs/lab-08/tasks/rot13/support/Makefile
@@ -3,9 +3,9 @@ CC = gcc
UTILSDIR := ../utils/
-ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)"
+ASFLAGS ?= -f elf64 -F dwarf -I "$(UTILSDIR)"
CFLAGS ?= -Wall
-LDFLAGS ?= -m32 -no-pie
+LDFLAGS ?= -fno-PIC -no-pie
TARGET := rot13
OBJS := main.o rot13.o
diff --git a/labs/lab-08/tasks/rot13/support/main.asm b/labs/lab-08/tasks/rot13/support/main.asm
index 850b121ec..b8d42e282 100644
--- a/labs/lab-08/tasks/rot13/support/main.asm
+++ b/labs/lab-08/tasks/rot13/support/main.asm
@@ -10,19 +10,21 @@ extern rot13
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- mov eax, [length]
- push eax
+ mov rax, [length]
+
+ sub rsp, 8 ; align the stack
push mystring
+ mov rdi, mystring
+ mov rsi, rax
call rot13
- add esp, 8
+ add rsp, 8
- push mystring
- push after_fmt
+ mov rdi, after_fmt
+ mov rsi, mystring
call printf
- add esp, 8
leave
ret
diff --git a/labs/lab-08/tasks/rot13/support/rot13.asm b/labs/lab-08/tasks/rot13/support/rot13.asm
index 59fcbb946..f9c9da8a3 100644
--- a/labs/lab-08/tasks/rot13/support/rot13.asm
+++ b/labs/lab-08/tasks/rot13/support/rot13.asm
@@ -2,12 +2,14 @@ section .text
global rot13
rot13:
- push ebp
- mov ebp, esp
- push ebx ; preserve ebx as required by cdecl
+ push rbp
+ mov rbp, rsp
+
+ ; TODO: save the used registers and align the stack, if needed
; TODO
- pop ebx
+ ; TODO: restore the used registers and the stack pointer, if altered
+
leave
ret
diff --git a/labs/lab-08/tasks/rot13/tests/.gitignore b/labs/lab-08/tasks/rot13/tests/.gitignore
new file mode 100644
index 000000000..34b8ce54b
--- /dev/null
+++ b/labs/lab-08/tasks/rot13/tests/.gitignore
@@ -0,0 +1,3 @@
+graded_test.o
+test_rot13.o
+test_rot13
diff --git a/labs/lab-08/tasks/rot13/tests/Makefile b/labs/lab-08/tasks/rot13/tests/Makefile
index 2cc5a4afb..a6d183d72 100644
--- a/labs/lab-08/tasks/rot13/tests/Makefile
+++ b/labs/lab-08/tasks/rot13/tests/Makefile
@@ -1,8 +1,8 @@
SRC_PATH ?= ../support
FULL_SRC_PATH = "$(realpath $(SRC_PATH))"
CPPFLAGS = -I. -I$(FULL_SRC_PATH) -I../utils
-CFLAGS = -Wall -Wextra -m32
-LDFLAGS = -m32
+CFLAGS = -Wall -Wextra -m64
+LDFLAGS = -m64 -no-pie
# Remove the line below to disable debugging support.
CFLAGS += -g -O0
diff --git a/labs/lab-08/tasks/string-print-len/.gitignore b/labs/lab-08/tasks/string-print-len/.gitignore
index 268b98689..a50b891a1 100644
--- a/labs/lab-08/tasks/string-print-len/.gitignore
+++ b/labs/lab-08/tasks/string-print-len/.gitignore
@@ -1 +1 @@
-print_string_len
+print_string_length
diff --git a/labs/lab-08/tasks/string-print-len/README.md b/labs/lab-08/tasks/string-print-len/README.md
index 681d6059e..e0f8708a3 100644
--- a/labs/lab-08/tasks/string-print-len/README.md
+++ b/labs/lab-08/tasks/string-print-len/README.md
@@ -1,5 +1,5 @@
---
-nav_order: 2
+nav_order: 3
parent: Lab 8 - Functions
---
@@ -7,12 +7,12 @@ parent: Lab 8 - Functions
Navigate to `tasks/string-print-len/support/`.
-The program `print_string_len.asm` displays the length of a string using the `PRINTF32` macro.
+The program `print_string_len.asm` displays the length of a string using the `PRINTF64` macro.
The calculation of the length of the `mystring` string occurs within the program (it is already implemented).
Implement the program to display the length of the string using the `printf` function.
-At the end, you will have the length of the string displayed twice: initially with the `PRINTF32` macro and then with the external function call `printf`.
+At the end, you will have the length of the string displayed twice: initially with the `PRINTF64` macro and then with the external function call `printf`.
> **NOTE:** Consider that the `printf` call is of the form `printf("String length is %u\n", len);`.
> You need to construct the stack for this call.
@@ -22,13 +22,25 @@ At the end, you will have the length of the string displayed twice: initially wi
> 1. Mark the symbol `printf` as external.
> 1. Define the format string `"String length is %u", 10, 0`.
> 1. Make the function call to `printf`, i.e.:
-> 1. Put the two arguments on the stack: the format string and the length.
+> 1. Put the two arguments into the corresponding registers (`rdi` and `rsi`, in this order)
> 1. Call `printf` using `call`.
-> 1. Restore the stack.
>
-> The length of the string is found in the `ecx` register.
+> The length of the string is found in the `rcx` register.
-To test the implementation, enter the `tests/` directory and run:
+After you consider your implementation complete, it is recommended to first run it `manually` in order to assess its correctness.
+In order to do so, enter the `support/` directory and run:
+
+```console
+make
+```
+
+If your code successfully compiled, you can then run the binary like so:
+
+```console
+./print_string_length
+```
+
+To fully test the implementation, enter the `tests/` directory and run:
```console
make check
diff --git a/labs/lab-08/tasks/string-print-len/solution/main.asm b/labs/lab-08/tasks/string-print-len/solution/main.asm
index ca31680db..219a3b59a 100644
--- a/labs/lab-08/tasks/string-print-len/solution/main.asm
+++ b/labs/lab-08/tasks/string-print-len/solution/main.asm
@@ -1,4 +1,4 @@
-%include "../utils/printf32.asm"
+%include "../utils/printf64.asm"
section .data
mystring db "This is my string", 0
@@ -10,25 +10,24 @@ extern print_string_length
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- mov eax, mystring
- xor ecx, ecx
+ mov rax, mystring
+ xor rcx, rcx
test_one_byte:
- mov bl, [eax]
+ mov bl, [rax]
test bl, bl
je out
- inc eax
- inc ecx
+ inc rax
+ inc rcx
jmp test_one_byte
out:
- PRINTF32 `[PRINTF32]: %d\n[printf]: \x0`, ecx
+ PRINTF64 `[PRINTF64]: %d\n[printf]: \x0`, rcx
- push ecx
+ mov rdi, rcx
call print_string_length
- add esp, 4
leave
ret
diff --git a/labs/lab-08/tasks/string-print-len/solution/print_string_length.asm b/labs/lab-08/tasks/string-print-len/solution/print_string_length.asm
index 3cb6b60fd..99920e6ee 100644
--- a/labs/lab-08/tasks/string-print-len/solution/print_string_length.asm
+++ b/labs/lab-08/tasks/string-print-len/solution/print_string_length.asm
@@ -7,17 +7,20 @@ extern printf
global print_string_length
print_string_length:
- push ebp
- mov ebp, esp
- push ebx ; preserve ebx as required by cdecl
+ push rbp
+ mov rbp, rsp
- mov ecx, [ebp + 8] ; get the string length from the stack
+ sub rsp, 8 ; align the stack
+ push rcx ; save the string length
- push ecx
- push print_format
+ mov rcx, rdi ; get the string length from the stack
+
+ mov rdi, print_format
+ mov rsi, rcx
call printf
- add esp, 8
- pop ebx
+ pop rcx ; restore the string length
+ add rsp, 8 ; restore the stack pointer
+
leave
ret
diff --git a/labs/lab-08/tasks/string-print-len/support/Makefile b/labs/lab-08/tasks/string-print-len/support/Makefile
index 1aee33b81..65fb97a78 100644
--- a/labs/lab-08/tasks/string-print-len/support/Makefile
+++ b/labs/lab-08/tasks/string-print-len/support/Makefile
@@ -3,9 +3,9 @@ CC = gcc
UTILSDIR := ../utils/
-ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)"
+ASFLAGS ?= -f elf64 -F dwarf -I "$(UTILSDIR)"
CFLAGS ?= -Wall
-LDFLAGS ?= -m32 -no-pie
+LDFLAGS ?= -fno-PIC -no-pie
TARGET := print_string_length
OBJS := main.o print_string_length.o
diff --git a/labs/lab-08/tasks/string-print-len/support/main.asm b/labs/lab-08/tasks/string-print-len/support/main.asm
index ca31680db..219a3b59a 100644
--- a/labs/lab-08/tasks/string-print-len/support/main.asm
+++ b/labs/lab-08/tasks/string-print-len/support/main.asm
@@ -1,4 +1,4 @@
-%include "../utils/printf32.asm"
+%include "../utils/printf64.asm"
section .data
mystring db "This is my string", 0
@@ -10,25 +10,24 @@ extern print_string_length
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- mov eax, mystring
- xor ecx, ecx
+ mov rax, mystring
+ xor rcx, rcx
test_one_byte:
- mov bl, [eax]
+ mov bl, [rax]
test bl, bl
je out
- inc eax
- inc ecx
+ inc rax
+ inc rcx
jmp test_one_byte
out:
- PRINTF32 `[PRINTF32]: %d\n[printf]: \x0`, ecx
+ PRINTF64 `[PRINTF64]: %d\n[printf]: \x0`, rcx
- push ecx
+ mov rdi, rcx
call print_string_length
- add esp, 4
leave
ret
diff --git a/labs/lab-08/tasks/string-print-len/support/print_string_length.asm b/labs/lab-08/tasks/string-print-len/support/print_string_length.asm
index dc666e6f2..9de1b3a21 100644
--- a/labs/lab-08/tasks/string-print-len/support/print_string_length.asm
+++ b/labs/lab-08/tasks/string-print-len/support/print_string_length.asm
@@ -7,12 +7,14 @@ extern printf
global print_string_length
print_string_length:
- push ebp
- mov ebp, esp
- push ebx ; preserve ebx as required by cdecl
+ push rbp
+ mov rbp, rsp
+
+ ; TODO: save the used registers and align the stack, if needed
; TODO: print the string length
- pop ebx
+ ; TODO: restore the used registers and the stack pointer, if altered
+
leave
ret
diff --git a/labs/lab-08/tasks/string-print-len/tests/.gitignore b/labs/lab-08/tasks/string-print-len/tests/.gitignore
new file mode 100644
index 000000000..fcf2f0f99
--- /dev/null
+++ b/labs/lab-08/tasks/string-print-len/tests/.gitignore
@@ -0,0 +1,3 @@
+graded_test.o
+test_print_string_length.o
+test_print_string_length
diff --git a/labs/lab-08/tasks/string-print-len/tests/Makefile b/labs/lab-08/tasks/string-print-len/tests/Makefile
index b0ceb6c8a..6f7c9973d 100644
--- a/labs/lab-08/tasks/string-print-len/tests/Makefile
+++ b/labs/lab-08/tasks/string-print-len/tests/Makefile
@@ -1,8 +1,8 @@
SRC_PATH ?= ../support
FULL_SRC_PATH = "$(realpath $(SRC_PATH))"
CPPFLAGS = -I. -I$(FULL_SRC_PATH) -I../utils
-CFLAGS = -Wall -Wextra -m32
-LDFLAGS = -m32
+CFLAGS = -Wall -Wextra -m64
+LDFLAGS = -m64 -no-pie
# Remove the line below to disable debugging support.
CFLAGS += -g -O0
diff --git a/labs/lab-08/tasks/string-print-len/utils/printf32.asm b/labs/lab-08/tasks/string-print-len/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-08/tasks/string-print-len/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-08/tasks/string-print-len/utils/printf64.asm b/labs/lab-08/tasks/string-print-len/utils/printf64.asm
new file mode 100644
index 000000000..e799a46e0
--- /dev/null
+++ b/labs/lab-08/tasks/string-print-len/utils/printf64.asm
@@ -0,0 +1,73 @@
+; SPDX-License-Identifier: BSD-3-Clause
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-08/tasks/string-print/README.md b/labs/lab-08/tasks/string-print/README.md
index 9423cc04b..3d7e18082 100644
--- a/labs/lab-08/tasks/string-print/README.md
+++ b/labs/lab-08/tasks/string-print/README.md
@@ -1,5 +1,5 @@
---
-nav_order: 1
+nav_order: 2
parent: Lab 8 - Functions
---
@@ -7,15 +7,28 @@ parent: Lab 8 - Functions
Navigate to `tasks/string-print/support/`.
-To display a string, we can use the internal macro `PRINTF32`.
+To display a string, we can use the internal macro `PRINTF64`.
Alternatively, we can use a function such as `puts()`.
-In the file `print_string.asm`, displaying a string using the `PRINTF32` macro is implemented.
+In the file `print_string.asm`, displaying a string using the `PRINTF64` macro is implemented.
Following the example of the `hello_world.asm` file, implement string display using `puts` as well.
If you're having difficulties solving this exercise, take a peek at [hello_world.asm](../../guides/hello_world/).
-To test the implementation, enter the `tests/` directory and run:
+After you consider your implementation complete, it is recommended to first run it `manually` in order to assess its correctness.
+In order to do so, enter the `support/` directory and run:
+
+```console
+make
+```
+
+If your code successfully compiled, you can then run the binary like so:
+
+```console
+./print_string
+```
+
+To fully test the implementation, enter the `tests/` directory and run:
```console
make check
diff --git a/labs/lab-08/tasks/string-print/solution/main.asm b/labs/lab-08/tasks/string-print/solution/main.asm
index 584b41af8..d104eb1f1 100644
--- a/labs/lab-08/tasks/string-print/solution/main.asm
+++ b/labs/lab-08/tasks/string-print/solution/main.asm
@@ -1,4 +1,4 @@
-%include "../utils/printf32.asm"
+%include "../utils/printf64.asm"
section .data
mystring db "This is my string", 0
@@ -9,14 +9,13 @@ extern printf
extern print_string
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- PRINTF32 `[PRINTF32]: %s\n[PUTS]: \x0`, mystring
+ PRINTF64 `[PRINTF64]: %s\n[PUTS]: \x0`, mystring
- push mystring
+ mov rdi, mystring
call print_string
- add esp, 4
leave
ret
diff --git a/labs/lab-08/tasks/string-print/solution/print_string.asm b/labs/lab-08/tasks/string-print/solution/print_string.asm
index 7dca8572a..b1e39d7b6 100644
--- a/labs/lab-08/tasks/string-print/solution/print_string.asm
+++ b/labs/lab-08/tasks/string-print/solution/print_string.asm
@@ -4,16 +4,12 @@ extern puts
global print_string
print_string:
- push ebp
- mov ebp, esp
- push ebx ; preserve ebx as required by cdecl
+ push rbp
+ mov rbp, rsp
- mov eax, [ebp + 8] ; get the address of the string
-
- push eax
+ ; call the puts function
+ ; as the argument is already placed in rdi by the caller
call puts
- add esp, 4
- pop ebx
leave
ret
diff --git a/labs/lab-08/tasks/string-print/support/Makefile b/labs/lab-08/tasks/string-print/support/Makefile
index 0b644bd20..0fffef7e9 100644
--- a/labs/lab-08/tasks/string-print/support/Makefile
+++ b/labs/lab-08/tasks/string-print/support/Makefile
@@ -3,9 +3,9 @@ CC = gcc
UTILSDIR := ../utils/
-ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)"
+ASFLAGS ?= -f elf64 -F dwarf -I "$(UTILSDIR)"
CFLAGS ?= -Wall
-LDFLAGS ?= -m32 -no-pie
+LDFLAGS ?= -fno-PIC -no-pie
TARGET := print_string
OBJS := main.o print_string.o
diff --git a/labs/lab-08/tasks/string-print/support/main.asm b/labs/lab-08/tasks/string-print/support/main.asm
index 584b41af8..d104eb1f1 100644
--- a/labs/lab-08/tasks/string-print/support/main.asm
+++ b/labs/lab-08/tasks/string-print/support/main.asm
@@ -1,4 +1,4 @@
-%include "../utils/printf32.asm"
+%include "../utils/printf64.asm"
section .data
mystring db "This is my string", 0
@@ -9,14 +9,13 @@ extern printf
extern print_string
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- PRINTF32 `[PRINTF32]: %s\n[PUTS]: \x0`, mystring
+ PRINTF64 `[PRINTF64]: %s\n[PUTS]: \x0`, mystring
- push mystring
+ mov rdi, mystring
call print_string
- add esp, 4
leave
ret
diff --git a/labs/lab-08/tasks/string-print/support/print_string.asm b/labs/lab-08/tasks/string-print/support/print_string.asm
index 232f98c51..6fcd3a322 100644
--- a/labs/lab-08/tasks/string-print/support/print_string.asm
+++ b/labs/lab-08/tasks/string-print/support/print_string.asm
@@ -4,12 +4,14 @@ extern puts
global print_string
print_string:
- push ebp
- mov ebp, esp
- push ebx ; preserve ebx as required by cdecl
+ push rbp
+ mov rbp, rsp
+
+ ; TODO: save the used registers and align the stack, if needed
; TODO: print the string
- pop ebx
+ ; TODO: restore the used registers and the stack pointer, if altered
+
leave
ret
diff --git a/labs/lab-08/tasks/string-print/tests/.gitignore b/labs/lab-08/tasks/string-print/tests/.gitignore
new file mode 100644
index 000000000..926637ce9
--- /dev/null
+++ b/labs/lab-08/tasks/string-print/tests/.gitignore
@@ -0,0 +1,3 @@
+graded_test.o
+test_print_string.o
+test_print_string
diff --git a/labs/lab-08/tasks/string-print/tests/Makefile b/labs/lab-08/tasks/string-print/tests/Makefile
index c6ec40cf7..5645b2f0a 100644
--- a/labs/lab-08/tasks/string-print/tests/Makefile
+++ b/labs/lab-08/tasks/string-print/tests/Makefile
@@ -1,8 +1,8 @@
SRC_PATH ?= ../support
FULL_SRC_PATH = "$(realpath $(SRC_PATH))"
CPPFLAGS = -I. -I$(FULL_SRC_PATH) -I../utils
-CFLAGS = -Wall -Wextra -m32
-LDFLAGS = -m32
+CFLAGS = -Wall -Wextra -m64
+LDFLAGS = -m64 -no-pie
# Remove the line below to disable debugging support.
CFLAGS += -g -O0
diff --git a/labs/lab-08/tasks/string-print/utils/printf32.asm b/labs/lab-08/tasks/string-print/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-08/tasks/string-print/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-08/tasks/string-print/utils/printf64.asm b/labs/lab-08/tasks/string-print/utils/printf64.asm
new file mode 100644
index 000000000..e799a46e0
--- /dev/null
+++ b/labs/lab-08/tasks/string-print/utils/printf64.asm
@@ -0,0 +1,73 @@
+; SPDX-License-Identifier: BSD-3-Clause
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-08/tasks/sum7/.gitignore b/labs/lab-08/tasks/sum7/.gitignore
new file mode 100644
index 000000000..b293f82d3
--- /dev/null
+++ b/labs/lab-08/tasks/sum7/.gitignore
@@ -0,0 +1 @@
+sum7
diff --git a/labs/lab-08/tasks/sum7/README.md b/labs/lab-08/tasks/sum7/README.md
new file mode 100644
index 000000000..c217517f2
--- /dev/null
+++ b/labs/lab-08/tasks/sum7/README.md
@@ -0,0 +1,47 @@
+---
+nav_order: 1
+parent: Lab 8 - Functions
+---
+
+# Task: Computing the sum of 7 numbers
+
+Navigate to `tasks/sum7/support/`.
+
+Similarly to what was described in the reading section of this lab, for this task, you will have to compute the sum of 7 numbers, all received as arguments to the `sum7` function.
+
+Be careful as not all of the arguments are stored in registers.
+
+The function's signature is the following: `long sum7(long a, long b, long c, long d, long e, long f, long g)`.
+
+After you consider your implementation complete, it is recommended to first run it `manually` in order to assess its correctness.
+In order to do so, enter the `support/` directory and run:
+
+```console
+make
+```
+
+If your code successfully compiled, you can then run the binary like so:
+
+```console
+./sum7
+```
+
+To fully test the implementation, enter the `tests/` directory and run:
+
+```console
+make check
+```
+
+In case of a correct solution, you will get an output such as:
+
+```text
+./run_all_tests.sh
+test_sum_byte ........................ passed ... 15
+test_sum_word ........................ passed ... 20
+test_sum_dword ........................ passed ... 30
+test_sum_qword ........................ passed ... 35
+
+Total: 100/100
+```
+
+If you're having trouble solving this exercise, go through [this](../../reading/functions.md) reading material.
diff --git a/labs/lab-08/tasks/sum7/solution/Makefile b/labs/lab-08/tasks/sum7/solution/Makefile
new file mode 120000
index 000000000..a39be4f20
--- /dev/null
+++ b/labs/lab-08/tasks/sum7/solution/Makefile
@@ -0,0 +1 @@
+../support/Makefile
\ No newline at end of file
diff --git a/labs/lab-08/tasks/sum7/solution/main.asm b/labs/lab-08/tasks/sum7/solution/main.asm
new file mode 100644
index 000000000..556918542
--- /dev/null
+++ b/labs/lab-08/tasks/sum7/solution/main.asm
@@ -0,0 +1,33 @@
+%include "../utils/printf64.asm"
+
+section .data
+ fmt db "sum = %d", 10, 0
+
+section .text
+
+extern printf
+extern sum7
+global main
+main:
+ push rbp
+ mov rbp, rsp
+
+ sub rsp, 8 ; align stack
+ mov rdi, 1
+ mov rsi, 2
+ mov rdx, 3
+ mov rcx, 4
+ mov r8, 5
+ mov r9, 6
+ mov r10, 7
+ push r10
+ call sum7
+ pop r10
+ add rsp, 8 ; restore stack
+
+ mov rdi, fmt
+ mov rsi, rax
+ call printf
+
+ leave
+ ret
diff --git a/labs/lab-08/tasks/sum7/solution/sum7.asm b/labs/lab-08/tasks/sum7/solution/sum7.asm
new file mode 100644
index 000000000..a6ce2639c
--- /dev/null
+++ b/labs/lab-08/tasks/sum7/solution/sum7.asm
@@ -0,0 +1,23 @@
+section .text
+
+global sum7
+
+sum7:
+ push rbp
+ mov rbp, rsp
+
+ ; clear rax
+ xor rax, rax
+
+ ; rdi, rsi, rdx, rcx, r8, r9 are the first 6 arguments
+ ; [rbp + 16] is the 7th argument
+ mov rax, [rbp + 16]
+ add rax, rdi
+ add rax, rsi
+ add rax, rdx
+ add rax, rcx
+ add rax, r8
+ add rax, r9
+
+ leave
+ ret
diff --git a/labs/lab-08/tasks/sum7/support/Makefile b/labs/lab-08/tasks/sum7/support/Makefile
new file mode 100644
index 000000000..04829dcbf
--- /dev/null
+++ b/labs/lab-08/tasks/sum7/support/Makefile
@@ -0,0 +1,24 @@
+AS = nasm
+CC = gcc
+
+UTILSDIR := ../utils/
+
+ASFLAGS ?= -f elf64 -F dwarf -I "$(UTILSDIR)"
+CFLAGS ?= -Wall
+LDFLAGS ?= -fno-PIC -no-pie
+
+TARGET := sum7
+OBJS := main.o sum7.o
+
+all: $(TARGET)
+
+$(TARGET): $(OBJS)
+ $(CC) $(LDFLAGS) -o $@ $^
+
+%.o: %.asm
+ $(AS) $(ASFLAGS) $< -o $@
+
+.PHONY: clean
+
+clean:
+ -rm -f *.o $(TARGET)
diff --git a/labs/lab-08/tasks/sum7/support/main.asm b/labs/lab-08/tasks/sum7/support/main.asm
new file mode 100644
index 000000000..556918542
--- /dev/null
+++ b/labs/lab-08/tasks/sum7/support/main.asm
@@ -0,0 +1,33 @@
+%include "../utils/printf64.asm"
+
+section .data
+ fmt db "sum = %d", 10, 0
+
+section .text
+
+extern printf
+extern sum7
+global main
+main:
+ push rbp
+ mov rbp, rsp
+
+ sub rsp, 8 ; align stack
+ mov rdi, 1
+ mov rsi, 2
+ mov rdx, 3
+ mov rcx, 4
+ mov r8, 5
+ mov r9, 6
+ mov r10, 7
+ push r10
+ call sum7
+ pop r10
+ add rsp, 8 ; restore stack
+
+ mov rdi, fmt
+ mov rsi, rax
+ call printf
+
+ leave
+ ret
diff --git a/labs/lab-08/tasks/sum7/support/sum7.asm b/labs/lab-08/tasks/sum7/support/sum7.asm
new file mode 100644
index 000000000..a6ce2639c
--- /dev/null
+++ b/labs/lab-08/tasks/sum7/support/sum7.asm
@@ -0,0 +1,23 @@
+section .text
+
+global sum7
+
+sum7:
+ push rbp
+ mov rbp, rsp
+
+ ; clear rax
+ xor rax, rax
+
+ ; rdi, rsi, rdx, rcx, r8, r9 are the first 6 arguments
+ ; [rbp + 16] is the 7th argument
+ mov rax, [rbp + 16]
+ add rax, rdi
+ add rax, rsi
+ add rax, rdx
+ add rax, rcx
+ add rax, r8
+ add rax, r9
+
+ leave
+ ret
diff --git a/labs/lab-08/tasks/sum7/tests/.gitignore b/labs/lab-08/tasks/sum7/tests/.gitignore
new file mode 100644
index 000000000..a2bcd9334
--- /dev/null
+++ b/labs/lab-08/tasks/sum7/tests/.gitignore
@@ -0,0 +1,3 @@
+graded_test.o
+test_sum7.o
+test_sum7
diff --git a/labs/lab-08/tasks/sum7/tests/Makefile b/labs/lab-08/tasks/sum7/tests/Makefile
new file mode 100644
index 000000000..376f5bd8a
--- /dev/null
+++ b/labs/lab-08/tasks/sum7/tests/Makefile
@@ -0,0 +1,43 @@
+SRC_PATH ?= ../support
+FULL_SRC_PATH = "$(realpath $(SRC_PATH))"
+CPPFLAGS = -I. -I$(FULL_SRC_PATH) -I../utils
+CFLAGS = -Wall -Wextra -m64
+LDFLAGS = -m64 -no-pie
+# Remove the line below to disable debugging support.
+CFLAGS += -g -O0
+
+SRCS = $(wildcard test*.c)
+OBJS = $(patsubst %.c,%.o,$(SRCS))
+EXECS = $(patsubst %.c,%,$(SRCS))
+
+
+.PHONY: all src check lint clean
+
+all: src $(EXECS)
+
+$(EXECS): %:%.o graded_test.o $(SRC_PATH)/sum7.o | src
+ $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
+
+$(OBJS): %.o:%.c graded_test.h
+
+graded_test.o: graded_test.c graded_test.h
+
+src:
+ make -C $(FULL_SRC_PATH)
+
+check:
+ make -C $(FULL_SRC_PATH) clean
+ make clean
+ make -i SRC_PATH=$(FULL_SRC_PATH)
+ ./run_all_tests.sh
+
+lint:
+ -cd .. && checkpatch.pl -f src/*.c tests/*.c tests/*/*.c
+ -cd .. && checkpatch.pl -f checker/*.sh tests/*.sh
+ -cd .. && cpplint --recursive src/ tests/ checker/
+ -cd .. && shellcheck checker/*.sh tests/*.sh
+
+clean:
+ -rm -f *~
+ -rm -f graded_test.o $(OBJS)
+ -rm -f $(EXECS)
diff --git a/labs/lab-08/tasks/sum7/tests/graded_test.c b/labs/lab-08/tasks/sum7/tests/graded_test.c
new file mode 100644
index 000000000..1eb03d100
--- /dev/null
+++ b/labs/lab-08/tasks/sum7/tests/graded_test.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include
+#include
+#include
+#include
+
+#include "./graded_test.h"
+
+static void my_itoa(size_t num, char *a)
+{
+ unsigned char digit3;
+ unsigned char digit2;
+ unsigned char digit1;
+
+ /* Print at most 3 decimal digits. */
+ if (num > 999)
+ num = 999;
+
+ digit1 = num % 10;
+ num /= 10;
+ digit2 = num % 10;
+ num /= 10;
+ digit3 = num % 10;
+
+ if (digit3 == 0)
+ a[0] = ' ';
+ else
+ a[0] = '0' + digit3;
+
+ if (digit2 == 0)
+ a[1] = ' ';
+ else
+ a[1] = '0' + digit2;
+
+ a[2] = '0' + digit1;
+}
+
+/*
+ * Print test result. Printed message should fit in 72 characters.
+ *
+ * Print format is:
+ *
+ * description ...................... passed ... NNN
+ * description ...................... failed ... NNN
+ * 32 chars 24 chars 6 3 3
+ */
+
+static void print_test(const char *description, int result, size_t points)
+{
+ /* Make these global linkage, so it's only allocated once. */
+ static char print_buffer[74];
+ static const char failed[] = "failed";
+ static const char passed[] = "passed";
+ size_t i;
+ size_t len;
+
+ /* Collect description in print_buffer. */
+ len = MIN(strlen(description), 32);
+ for (i = 0; i < len; i++)
+ print_buffer[i] = description[i];
+ for (i = len; i < 32; i++)
+ print_buffer[i] = ' ';
+ print_buffer[32] = ' ';
+
+ /* Collect dots in print_buffer. */
+ for (i = 0; i < 24; i++)
+ print_buffer[33+i] = '.';
+ print_buffer[57] = ' ';
+
+ /* Collect passed / failed. */
+ for (i = 0; i < 6; i++) {
+ if (result == 1)
+ print_buffer[58+i] = passed[i];
+ else
+ print_buffer[58+i] = failed[i];
+ }
+ print_buffer[64] = ' ';
+
+ /* Collect dots in print_buffer. */
+ for (i = 0; i < 3; i++)
+ print_buffer[65+i] = '.';
+ print_buffer[68] = ' ';
+
+ /* Collect number. */
+ if (result == 1) {
+ my_itoa(points, &print_buffer[69]);
+ } else {
+ print_buffer[69] = ' ';
+ print_buffer[70] = ' ';
+ print_buffer[71] = '0';
+ }
+
+ /* Collect newline. */
+ print_buffer[72] = '\n';
+
+ write(1, print_buffer, 73);
+}
+
+void run_test(struct graded_test *test)
+{
+ int res;
+
+ res = test->function();
+ print_test(test->description, res, test->points);
+#ifdef EXIT_IF_FAIL
+ exit(EXIT_FAILURE);
+#endif
+}
+
+void run_tests(struct graded_test *tests, size_t count)
+{
+ size_t i;
+
+ for (i = 0; i < count; i++)
+ run_test(&tests[i]);
+}
diff --git a/labs/lab-08/tasks/sum7/tests/graded_test.h b/labs/lab-08/tasks/sum7/tests/graded_test.h
new file mode 100644
index 000000000..f56f2e07c
--- /dev/null
+++ b/labs/lab-08/tasks/sum7/tests/graded_test.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+
+#ifndef GRADED_TEST_H_
+#define GRADED_TEST_H_ 1
+
+/* test function prototype */
+typedef int (*test_f)(void);
+
+struct graded_test {
+ test_f function; /* test/evaluation function */
+ char *description; /* test description */
+ size_t points; /* points for each test */
+};
+
+void run_test(struct graded_test *test);
+void run_tests(struct graded_test *tests, size_t count);
+
+#endif /* GRADED_TEST_H_ */
diff --git a/labs/lab-08/tasks/sum7/tests/run_all_tests.sh b/labs/lab-08/tasks/sum7/tests/run_all_tests.sh
new file mode 100755
index 000000000..79cb0daab
--- /dev/null
+++ b/labs/lab-08/tasks/sum7/tests/run_all_tests.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+# SPDX-License-Identifier: BSD-3-Clause
+
+./test_sum7 | tee results.txt
+
+total=$(grep '\( passed \| failed \)' results.txt | rev | cut -d ' ' -f 1 | rev | paste -s -d'+' | bc)
+echo ""
+echo -n "Total: "
+echo -n " "
+LC_ALL=C printf "%3d/100\n" "$total"
+
+rm results.txt
diff --git a/labs/lab-08/tasks/sum7/tests/test_sum7.c b/labs/lab-08/tasks/sum7/tests/test_sum7.c
new file mode 100644
index 000000000..2a14e51f5
--- /dev/null
+++ b/labs/lab-08/tasks/sum7/tests/test_sum7.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include
+#include
+#include
+#include "graded_test.h"
+
+extern long sum7(long a, long b, long c, long d, long e, long f, long g);
+
+#define OUTPUT_BUFFER_SIZE 1024
+
+/* reverse: reverse string s in place */
+void reverse(char s[])
+{
+ int i, j;
+ char c;
+
+ for (i = 0, j = strlen(s)-1; i < j; i++, j--) {
+ c = s[i];
+ s[i] = s[j];
+ s[j] = c;
+ }
+}
+
+void itoa(long n, char s[])
+{
+ long i, sign;
+
+ sign = n;
+
+ if (n < 0)
+ n = -n;
+ i = 0;
+ do {
+ s[i++] = n % 10 + '0';
+ } while ((n /= 10) > 0);
+ if (sign < 0)
+ s[i++] = '-';
+ s[i] = '\0';
+ reverse(s);
+}
+
+static int check_print_output(long a, long b, long c, long d, long e, long f, long g, char *res)
+{
+ char buffer[OUTPUT_BUFFER_SIZE] = {0};
+
+ long output = sum7(a, b, c, d, e, f, g);
+
+ // get the string representation of the output
+ itoa(output, buffer);
+
+ return strcmp(buffer, res) == 0;
+}
+
+static int test_sum_byte(void)
+{
+ return check_print_output(1, 2, 3, 4, 5, 6, 7, "28");
+}
+
+static int test_sum_word(void)
+{
+ return check_print_output(195, 196, 187, 198, 199, 200, 201, "1376");
+}
+
+static int test_sum_dword(void)
+{
+ return check_print_output(65536, 65537, 65538, 65539, 65540, 65541, 65542, "458773");
+}
+
+static int test_sum_qword(void)
+{
+ return check_print_output(4294967296, 4294967297, 4294967298, 4294967299, 4294967300, 4294967301, 4294967302,
+ "30064771093");
+}
+
+static struct graded_test all_tests[] = {
+ { test_sum_byte, "test_sum_byte", 15 },
+ { test_sum_word, "test_sum_word", 20 },
+ { test_sum_dword, "test_sum_dword", 30 },
+ { test_sum_qword, "test_sum_qword", 35 }
+};
+
+int main(void)
+{
+ run_tests(all_tests, sizeof(all_tests) / sizeof(all_tests[0]));
+ return 0;
+}
diff --git a/labs/lab-08/tasks/sum7/utils/printf64.asm b/labs/lab-08/tasks/sum7/utils/printf64.asm
new file mode 100644
index 000000000..e799a46e0
--- /dev/null
+++ b/labs/lab-08/tasks/sum7/utils/printf64.asm
@@ -0,0 +1,73 @@
+; SPDX-License-Identifier: BSD-3-Clause
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro
diff --git a/labs/lab-08/tasks/to-upper/.gitignore b/labs/lab-08/tasks/to-upper/.gitignore
index 91d366d5d..6ce843e64 100644
--- a/labs/lab-08/tasks/to-upper/.gitignore
+++ b/labs/lab-08/tasks/to-upper/.gitignore
@@ -1 +1 @@
-toupper
+to_upper
diff --git a/labs/lab-08/tasks/to-upper/README.md b/labs/lab-08/tasks/to-upper/README.md
index 987224b75..69fb6d0df 100644
--- a/labs/lab-08/tasks/to-upper/README.md
+++ b/labs/lab-08/tasks/to-upper/README.md
@@ -1,5 +1,5 @@
---
-nav_order: 4
+nav_order: 5
parent: Lab 8 - Functions
---
@@ -30,7 +30,20 @@ there is no need for another string.
Implement the `toupper()` function so that the transformation occurs only for lowercase characters, not uppercase letters or other types of characters.
-To test the implementation, enter the `tests/` directory and run:
+After you consider your implementation complete, it is recommended to first run it `manually` in order to assess its correctness.
+In order to do so, enter the `support/` directory and run:
+
+```console
+make
+```
+
+If your code successfully compiled, you can then run the binary like so:
+
+```console
+./to_upper
+```
+
+To fully test the implementation, enter the `tests/` directory and run:
```console
make check
diff --git a/labs/lab-08/tasks/to-upper/solution/main.asm b/labs/lab-08/tasks/to-upper/solution/main.asm
index 101cd2b05..68ccdf4c5 100644
--- a/labs/lab-08/tasks/to-upper/solution/main.asm
+++ b/labs/lab-08/tasks/to-upper/solution/main.asm
@@ -10,22 +10,19 @@ extern to_upper
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- push mystring
- push before_format
+ mov rdi, before_format
+ mov rsi, mystring
call printf
- add esp, 8
- push mystring
+ mov rdi, mystring
call to_upper
- add esp, 4
- push mystring
- push after_format
+ mov rdi, after_format
+ mov rsi, mystring
call printf
- add esp, 8
leave
ret
diff --git a/labs/lab-08/tasks/to-upper/solution/to_upper.asm b/labs/lab-08/tasks/to-upper/solution/to_upper.asm
index afef0f4d2..fdade5819 100644
--- a/labs/lab-08/tasks/to-upper/solution/to_upper.asm
+++ b/labs/lab-08/tasks/to-upper/solution/to_upper.asm
@@ -3,21 +3,25 @@ section .text
global to_upper
to_upper:
- push ebp
- mov ebp, esp
- push ebx ; preserve ebx as required by cdecl
+ push rbp
+ mov rbp, rsp
- mov eax, [ebp + 8]
+ sub rsp, 8 ; leave room in order to align the stack
+ push rbx ; preserve rbx as required by the System V AMD64 ABI
+
+ mov rax, rdi
check_one_byte:
- mov bl, [eax]
+ mov bl, [rax]
test bl, bl
je out
sub bl, 0x20
- mov [eax], bl
- inc eax
+ mov [rax], bl
+ inc rax
jmp check_one_byte
out:
- pop ebx
+ pop rbx ; restore rbx
+ add rsp, 8
+
leave
ret
diff --git a/labs/lab-08/tasks/to-upper/support/Makefile b/labs/lab-08/tasks/to-upper/support/Makefile
index 8b23c8bc7..78337ff3f 100644
--- a/labs/lab-08/tasks/to-upper/support/Makefile
+++ b/labs/lab-08/tasks/to-upper/support/Makefile
@@ -3,9 +3,9 @@ CC = gcc
UTILSDIR := ../utils/
-ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)"
+ASFLAGS ?= -f elf64 -F dwarf -I "$(UTILSDIR)"
CFLAGS ?= -Wall
-LDFLAGS ?= -m32 -no-pie
+LDFLAGS ?= -fno-PIC -no-pie
TARGET := to_upper
OBJS := main.o to_upper.o
diff --git a/labs/lab-08/tasks/to-upper/support/main.asm b/labs/lab-08/tasks/to-upper/support/main.asm
index 101cd2b05..68ccdf4c5 100644
--- a/labs/lab-08/tasks/to-upper/support/main.asm
+++ b/labs/lab-08/tasks/to-upper/support/main.asm
@@ -10,22 +10,19 @@ extern to_upper
global main
main:
- push ebp
- mov ebp, esp
+ push rbp
+ mov rbp, rsp
- push mystring
- push before_format
+ mov rdi, before_format
+ mov rsi, mystring
call printf
- add esp, 8
- push mystring
+ mov rdi, mystring
call to_upper
- add esp, 4
- push mystring
- push after_format
+ mov rdi, after_format
+ mov rsi, mystring
call printf
- add esp, 8
leave
ret
diff --git a/labs/lab-08/tasks/to-upper/support/to_upper.asm b/labs/lab-08/tasks/to-upper/support/to_upper.asm
index be2328552..c2c62e111 100644
--- a/labs/lab-08/tasks/to-upper/support/to_upper.asm
+++ b/labs/lab-08/tasks/to-upper/support/to_upper.asm
@@ -3,12 +3,14 @@ section .text
global to_upper
to_upper:
- push ebp
- mov ebp, esp
- push ebx ; preserve ebx as required by cdecl
+ push rbp
+ mov rbp, rsp
+
+ ; TODO: save the used registers and align the stack, if needed
; TODO
- pop ebx
+ ; TODO: restore the used registers and the stack pointer, if altered
+
leave
ret
diff --git a/labs/lab-08/tasks/to-upper/tests/.gitignore b/labs/lab-08/tasks/to-upper/tests/.gitignore
new file mode 100644
index 000000000..9a3294024
--- /dev/null
+++ b/labs/lab-08/tasks/to-upper/tests/.gitignore
@@ -0,0 +1,3 @@
+graded_test.o
+test_to_upper.o
+test_to_upper
diff --git a/labs/lab-08/tasks/to-upper/tests/Makefile b/labs/lab-08/tasks/to-upper/tests/Makefile
index e56989788..ff7a403d5 100644
--- a/labs/lab-08/tasks/to-upper/tests/Makefile
+++ b/labs/lab-08/tasks/to-upper/tests/Makefile
@@ -1,8 +1,8 @@
SRC_PATH ?= ../support
FULL_SRC_PATH = "$(realpath $(SRC_PATH))"
CPPFLAGS = -I. -I$(FULL_SRC_PATH) -I../utils
-CFLAGS = -Wall -Wextra -m32
-LDFLAGS = -m32
+CFLAGS = -Wall -Wextra -m64
+LDFLAGS = -m64 -no-pie
# Remove the line below to disable debugging support.
CFLAGS += -g -O0
diff --git a/labs/lab-08/tasks/to-upper/utils/printf32.asm b/labs/lab-08/tasks/to-upper/utils/printf32.asm
deleted file mode 100644
index 0617f3d8d..000000000
--- a/labs/lab-08/tasks/to-upper/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-08/tasks/to-upper/utils/printf64.asm b/labs/lab-08/tasks/to-upper/utils/printf64.asm
new file mode 100644
index 000000000..e799a46e0
--- /dev/null
+++ b/labs/lab-08/tasks/to-upper/utils/printf64.asm
@@ -0,0 +1,73 @@
+; SPDX-License-Identifier: BSD-3-Clause
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 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:
+ 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
+%endmacro