From 19427394db75e95271eb2f34400e1e24a493a1e3 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 2 Jan 2022 13:41:04 +0100 Subject: [PATCH] add itoa and build "system" --- .gitignore | 3 ++ build.sh | 30 +++++++++++++ src/itoa.asm | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+) create mode 100644 .gitignore create mode 100644 build.sh create mode 100644 src/itoa.asm diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..612c5bc --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +target +.idea +*.iml diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..a18814f --- /dev/null +++ b/build.sh @@ -0,0 +1,30 @@ +build () { + FILE="$1" + PROGRAM_NAME=$(basename "$FILE" ".asm") + + if [ ! -f "$FILE" ]; then + echo "$PROGRAM_NAME not found" + return + fi + + echo "Building $PROGRAM_NAME" + nasm -g -F dwarf -f elf64 "$FILE" -o "./target/$PROGRAM_NAME.o" && ld.lld "./target/$PROGRAM_NAME.o" -o "./target/$PROGRAM_NAME" +} + + +if [ "$1" = "--clean" ]; then + rm -r target + exit +fi + +if [ ! -d ./target ]; then + mkdir ./target +fi + +if [ "$#" -eq 0 ]; then + for FILE in ./src/*.asm ; do + build "$FILE" + done +else + build "src/$1.asm" +fi diff --git a/src/itoa.asm b/src/itoa.asm new file mode 100644 index 0000000..ef31e93 --- /dev/null +++ b/src/itoa.asm @@ -0,0 +1,120 @@ + global _start + +NUMBER EQU 0 + + section .data +buffer: times 8 db 0 + + + section .text +_start: + mov rax, NUMBER + mov rbx, buffer + call itoa + cmp rax, 0 + jnz error + +write_buffer: + mov rax, 1 ; write + mov rdi, 1 ; stdout + mov rsi, buffer + mov rdx, rbx ; the length + syscall + +graceful_exit: + xor rdi, rdi + jmp exit + +error: + mov rdi, 1 +exit: + mov rax, 60 + syscall + + + +; itoa - converts an unsigned integer into its ascii representation +; inputs: +; rax - the number +; rbx - the pointer to the buffer +; outputs: +; rax - 0: success, 1: error +; rbx - the length + +MAX_SIZE EQU 100000 +START_DIVISOR EQU MAX_SIZE / 10 +ASCII_NUM EQU 48 + +itoa: +; r12: whether we are in the leading zeroes (bool) +; r11: buffer start +; r10: number +; r9: divisor +; r8: current buffer pointer + mov r12, 1 + mov r10, rax + + cmp r10, MAX_SIZE + jge number_too_big + + mov r9, START_DIVISOR + mov r11, rbx + mov r8, rbx + + cmp rax, 0 + jz write_zero_return +div_loop: + ; first division for getting the mod of the number + xor rdx, rdx + mov rax, r10 + mov rcx, r9 + div rcx + ; if rax is non-zero or we are not in the leading zeroes, write into the buffer + cmp rax, 0 + jne write_ascii_into_buffer + cmp r12, 0 + jz write_ascii_into_buffer + ; else, skip the write + jmp take_remainder_of_number + +write_ascii_into_buffer: + ; write the ascii number into the buffer + add rax, ASCII_NUM + mov byte [r8], al + inc r8 + xor r12, r12 ; we are past the leading zeroes, set it to false + +take_remainder_of_number: + ; if the divisor is one, we are done here + cmp r9, 1 + je return_success + + ; now take the remainder of the number for the next loop + xor rdx, rdx + mov rax, r10 + mov rcx, r9 + div rcx + mov r10, rdx ; nom = num % div + + ; divide the divisor by ten + xor rdx, rdx + mov rax, r9 + mov rcx, 10 + div rcx + mov r9, rax + + jmp div_loop + +write_zero_return: + mov byte [r8], '0' + inc r8 +return_success: + ; calculate the length into r8 + sub r8, r11 + mov rax, 0 ; return the success code 0 + mov rbx, r8 ; return the length + ret +number_too_big: + mov rax, 1 ; return error code 1 + mov rbx, 0 ; we've written nothing + ret \ No newline at end of file