├── .gitignore ├── README.md └── Sources ├── hello-world ├── Makefile └── hello.asm ├── hi_and_low_rax ├── Makefile ├── demo_rax.asm └── print_rax.asm ├── http-server ├── Makefile ├── http-server.asm └── mime-type.asm ├── multi-thread ├── Makefile └── threads.asm ├── pointers ├── Makefile └── pointers.asm ├── snake-game ├── Makefile └── snake.asm ├── solve_linear_simd ├── Makefile ├── inputs.txt └── solve_linear_simd.asm └── sorting ├── Makefile ├── int-utils.asm ├── io-utils.asm └── main.asm /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daohainam/lets-learn-assembly-language/559e1919e90d9d158849722041500b2aca3f7a1b/.gitignore -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Let's learn Assembly Language 2 | Đây là nội dung khóa học ngôn ngữ Assembly x86_64 trên Linux. 3 | 4 | Xem các video bài giảng tại đây: https://www.youtube.com/playlist?list=PLRLJQuuRRcFndxbUxCtbYt2EOcscuNLoR 5 | 6 | ## Yêu cầu đầu vào: 7 | - Biết Linux và terminal cơ bản 8 | - Có ý thích tìm hiểu về kiến trúc máy tính 9 | - Không yêu cầu kiến thức Assembly trước đó 10 | 11 | ## Mục tiêu 12 | Học viên sau khi học xong sẽ nắm được kiến thức về các phần sau: 13 | 14 | - Kiến trúc cơ bản của trong máy tính 15 | - Tổ chức bộ nhớ 16 | - Thanh ghi và phân loại thanh ghi 17 | - Các lệnh assembly cơ bản 18 | - Tổ chức mã nguồn, include và link 19 | - Cách chương trình được thực thi 20 | - Giao tiếp với hệ điều hành Linux thông qua syscall 21 | - Hiểu cách gọi ngắt, hàm, stack và quy ước System V AMD64 ABI 22 | - Sử dụng lệnh nhảy và lặp 23 | - Quản lý bộ nhớ 24 | - Debugging với gdb 25 | - Sử dụng các hàm libc từ Assembly 26 | 27 | ## Danh sách bài học 28 | - [Giới thiệu](https://youtu.be/ISZwMjDWJl4) 29 | - [Cài đặt môi trường](https://youtu.be/bFLv9VVrFSc) 30 | - [Viết và biên dịch chương trình Hello World](https://youtu.be/uaDyCNSw7p8) 31 | - [Các thành phần trong một chương trình Assembly](https://youtu.be/nqaedSHwAZY) 32 | - Transistor, các phép toán logic và cổng (gates) 33 | - Bit, biểu diễn số và các hệ cơ số 34 | - Làm quen với gdb 35 | - Section (segment) 36 | - Tổ chức bộ nhớ của một chương trình 37 | - Code segment 38 | - Data segment 39 | - Stack segment 40 | - Heap 41 | - Thanh ghi (giới thiệu, hi/lo) 42 | - Các thanh ghi dữ liệu 43 | - Các thanh ghi dấu chấm động 44 | - Các thanh ghi địa chỉ/con trỏ 45 | - Các thanh ghi index 46 | - Các thanh ghi segment (segment trong các chế độ 16/32/64 bit) 47 | - Thanh ghi cờ 48 | - Gọi các lệnh hệ thống Linux (syscall/int 80h) 49 | - Kernel/User mode 50 | - Các chế độ địa chỉ 51 | - Khai báo biến/const và các kiểu dữ liệu 52 | - Array 53 | - Bảng mã ASCII 54 | - Các lệnh cơ bản 55 | - Lệnh gán và các lệnh số học 56 | - Lệnh logic và dịch bit 57 | - Lệnh rẽ nhánh (có và không có điều kiện) 58 | - Vòng lặp 59 | - Khai báo và gọi thủ tục (call/ret) 60 | - System V AMD64 ABI 61 | - Tổ chức mã nguồn với include và link 62 | - Macro 63 | - Quản lý bộ nhớ 64 | - Làm việc với hệ thống file 65 | 66 | # Tài liệu tham khảo 67 | - [Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 1: Basic Architecture](https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html) 68 | - [NASM manual](https://www.nasm.us/xdoc/2.16.03/html/nasmdoc0.html) 69 | - [Linux System Call Table - Chromium OS](https://www.chromium.org/chromium-os/developer-library/reference/linux-constants/syscalls/) 70 | - [Assembly Programming Tutorial - tutorialspoint](https://www.tutorialspoint.com/assembly_programming/index.htm) 71 | - [Debugging with gdb](https://www.eecs.umich.edu/courses/eecs373/readings/Debugger.pdf) 72 | - [gdb (and ddd) Guide](https://www.cs.swarthmore.edu/~newhall/unixhelp/howto_gdb.php) 73 | - [System V Application Binary Interface AMD64 Architecture Processor Supplement](https://cs61.seas.harvard.edu/site/2022/pdf/x86-64-abi-20210928.pdf) 74 | - [System V ABI - OSDev](https://wiki.osdev.org/System_V_ABI) 75 | -------------------------------------------------------------------------------- /Sources/hello-world/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | nasm -f elf64 -g -F dwarf hello.asm -o hello.o 3 | ld hello.o -o hello 4 | 5 | clean: 6 | rm -f *.o hello -------------------------------------------------------------------------------- /Sources/hello-world/hello.asm: -------------------------------------------------------------------------------- 1 | section .text 2 | global _start 3 | 4 | _start: 5 | mov rax, 1 6 | mov rdi, 1 7 | mov rsi, hello_msg 8 | mov rdx, hello_msg_len 9 | syscall 10 | 11 | mov rax, 60 12 | mov rdi, 0 13 | syscall 14 | 15 | section .rodata 16 | hello_msg db 'Hello world!', 0x0A 17 | hello_msg_len equ $ - hello_msg 18 | 19 | -------------------------------------------------------------------------------- /Sources/hi_and_low_rax/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | nasm -f elf64 -g -F dwarf demo_rax.asm -o demo_rax.o 3 | ld demo_rax.o -o demo_rax 4 | 5 | clean: 6 | rm -f *.o demo_rax -------------------------------------------------------------------------------- /Sources/hi_and_low_rax/demo_rax.asm: -------------------------------------------------------------------------------- 1 | section .text 2 | global _start 3 | 4 | %macro print 2 5 | mov rsi, %1 6 | mov rdx, %2 7 | call print_string 8 | %endmacro 9 | 10 | _start: 11 | xor rax, rax 12 | call print_rax 13 | 14 | mov al, 0xEF 15 | print al_msg, al_msg_len 16 | call print_rax 17 | 18 | mov ah, 0xCD 19 | print ah_msg, ah_msg_len 20 | call print_rax 21 | 22 | or eax, 0x89AB0000 23 | print eax_msg, eax_msg_len 24 | call print_rax 25 | 26 | mov rbx, 0x0123456700000000 27 | or rax, rbx 28 | print rax_or_msg, rax_or_msg_len 29 | call print_rax 30 | 31 | mov rbx, 0xF0F0F0F0F0F0F0F0 32 | and rax, rbx 33 | print rax_and_msg, rax_and_msg_len 34 | call print_rax 35 | 36 | mov rax, 60 37 | xor rdi, rdi 38 | syscall 39 | 40 | print_rax: 41 | push rax 42 | mov rax, 1 ; write 43 | mov rdi, 1 ; stdout 44 | mov rsi, rax_content 45 | mov rdx, rax_content_len 46 | syscall 47 | pop rax 48 | 49 | call print_rax_hex 50 | 51 | push rax 52 | mov rax, 1 ; write 53 | mov rdi, 1 ; stdout 54 | mov rsi, newline 55 | mov rdx, newline_len 56 | syscall 57 | pop rax 58 | 59 | ret 60 | 61 | print_string: 62 | push rax 63 | mov rax, 1 ; write 64 | mov rdi, 1 ; stdout 65 | syscall 66 | pop rax 67 | 68 | ret 69 | 70 | %include "print_rax.asm" 71 | 72 | section .rodata 73 | rax_content db 'RAX: ' 74 | rax_content_len equ $ - rax_content 75 | 76 | newline db 10, 13 77 | newline_len equ 2 78 | 79 | hex_prefix db "0x" 80 | hex_prefix_len equ $ - hex_prefix 81 | 82 | al_msg db 'AL = 0xEF', 10, 13 83 | al_msg_len equ $ - al_msg 84 | 85 | ah_msg db 'AH = 0xCD', 10, 13 86 | ah_msg_len equ $ - ah_msg 87 | 88 | eax_msg db 'EAX = EAX or 0x89AB0000', 10, 13 89 | eax_msg_len equ $ - eax_msg 90 | 91 | rax_or_msg db 'RAX = RAX or 0x0123456700000000', 10, 13 92 | rax_or_msg_len equ $ - rax_or_msg 93 | 94 | rax_and_msg db 'RAX = RAX and 0xF0F0F0F0F0F0F0F0', 10, 13 95 | rax_and_msg_len equ $ - rax_and_msg 96 | 97 | 98 | section .bss 99 | hex_buffer resb 16 -------------------------------------------------------------------------------- /Sources/hi_and_low_rax/print_rax.asm: -------------------------------------------------------------------------------- 1 | print_rax_hex: 2 | push rax 3 | push rbx ; save rbx (callee-saved) 4 | 5 | mov rbx, rax ; sao chép giá trị RAX sang RBX để xử lý 6 | 7 | ; in tiền tố "0x" 8 | mov rax, 1 ; syscall write 9 | mov rdi, 1 ; stdout 10 | mov rsi, hex_prefix 11 | mov rdx, hex_prefix_len 12 | syscall 13 | 14 | ; chuyển số trong RBX sang hex chuỗi 15 | mov rcx, 16 ; 16 chữ số hex cho 64-bit 16 | lea rdi, [hex_buffer + 15] ; con trỏ tới cuối buffer 17 | 18 | convert_loop: 19 | mov rax, rbx 20 | and rax, 0xF ; lấy 4 bit cuối 21 | cmp rax, 9 22 | jbe to_digit 23 | add rax, 'A' - 10 24 | jmp store 25 | 26 | to_digit: 27 | add rax, '0' 28 | 29 | store: 30 | mov [rdi], al 31 | dec rdi 32 | shr rbx, 4 33 | loop convert_loop 34 | 35 | ; in chuỗi hex 36 | mov rax, 1 ; syscall write 37 | mov rdi, 1 ; stdout 38 | lea rsi, [hex_buffer] 39 | mov rdx, 16 40 | syscall 41 | 42 | ; in dấu xuống dòng 43 | mov rax, 1 44 | mov rdi, 1 45 | mov rsi, newline 46 | mov rdx, newline_len 47 | syscall 48 | 49 | pop rbx 50 | pop rax 51 | ret -------------------------------------------------------------------------------- /Sources/http-server/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | nasm -f elf64 http-server.asm -o http-server.o 3 | nasm -f elf64 mime-type.asm -o mimi-type.o 4 | ld http-server.o mimi-type.o -o http-server 5 | 6 | clean: 7 | rm -f *.o http-server -------------------------------------------------------------------------------- /Sources/http-server/http-server.asm: -------------------------------------------------------------------------------- 1 | extern get_mime_type 2 | 3 | %define SYS_SOCKET 41 4 | %define SYS_BIND 49 5 | %define SYS_LISTEN 50 6 | %define SYS_ACCEPT 43 7 | %define SYS_READ 0 8 | %define SYS_WRITE 1 9 | %define SYS_OPEN 2 10 | %define SYS_CLOSE 3 11 | %define SYS_EXIT 60 12 | %define SYS_FORK 57 13 | 14 | section .data 15 | sockaddr: 16 | dw 2 ; AF_INET 17 | dw 0x5000 ; Port 80 18 | dd 0 ; INADDR_ANY 19 | times 8 db 0 ; Padding 20 | 21 | http_404 db "HTTP/1.1 404 Not Found", 13,10, \ 22 | "Content-Type: text/plain", 13,10, \ 23 | "Connection: close", 13,10,13,10, \ 24 | "404 Not Found", 10 25 | http_404_len equ $ - http_404 26 | 27 | ; MIME table: [ext, mimetype] 28 | mime_table: 29 | db ".html",0,"text/html",0 30 | db ".css",0,"text/css",0 31 | db ".js",0,"application/javascript",0 32 | db ".png",0,"image/png",0 33 | db ".jpg",0,"image/jpeg",0 34 | db ".jpeg",0,"image/jpeg",0 35 | db ".txt",0,"text/plain",0 36 | db 0 37 | 38 | section .bss 39 | sockfd resq 1 40 | clientfd resq 1 41 | buffer resb 4096 42 | filepath resb 256 43 | filebuf resb 8192 44 | mimebuf resb 64 45 | headerbuf resb 512 46 | 47 | section .text 48 | global _start 49 | 50 | _start: 51 | ; socket 52 | mov rax, SYS_SOCKET 53 | mov rdi, 2 54 | mov rsi, 1 55 | xor rdx, rdx 56 | syscall 57 | mov [sockfd], rax 58 | 59 | ; bind 60 | mov rax, SYS_BIND 61 | mov rdi, [sockfd] 62 | lea rsi, [sockaddr] 63 | mov edx, 16 64 | syscall 65 | 66 | ; listen 67 | mov rax, SYS_LISTEN 68 | mov rdi, [sockfd] 69 | mov rsi, 10 70 | syscall 71 | 72 | accept_loop: 73 | ; accept 74 | mov rax, SYS_ACCEPT 75 | mov rdi, [sockfd] 76 | xor rsi, rsi 77 | xor rdx, rdx 78 | syscall 79 | mov [clientfd], rax 80 | 81 | ; fork 82 | mov rax, SYS_FORK 83 | syscall 84 | test rax, rax 85 | jnz .parent 86 | 87 | ; child: handle client 88 | mov rdi, [clientfd] 89 | call handle_client 90 | 91 | ; close + exit 92 | mov rax, SYS_CLOSE 93 | mov rdi, [clientfd] 94 | syscall 95 | 96 | mov rax, SYS_EXIT 97 | xor rdi, rdi 98 | syscall 99 | 100 | .parent: 101 | ; parent: close client socket 102 | mov rax, SYS_CLOSE 103 | mov rdi, [clientfd] 104 | syscall 105 | jmp accept_loop 106 | 107 | handle_client: 108 | ; read request 109 | mov rax, SYS_READ 110 | mov rdi, rdi 111 | lea rsi, [buffer] 112 | mov rdx, 4096 113 | syscall 114 | 115 | ; parse GET path 116 | lea rsi, [buffer] 117 | lea rdi, [filepath] 118 | call parse_get_path 119 | 120 | ; open file 121 | mov rax, SYS_OPEN 122 | lea rdi, [filepath] 123 | xor rsi, rsi 124 | syscall 125 | cmp rax, 0 126 | js .send_404 127 | mov rbx, rax ; fd 128 | 129 | ; read file 130 | mov rax, SYS_READ 131 | mov rdi, rbx 132 | lea rsi, [filebuf] 133 | mov rdx, 8192 134 | syscall 135 | mov rcx, rax ; file size 136 | 137 | ; get mime type 138 | lea rdi, [filepath] 139 | lea rsi, [mimebuf] 140 | call get_mime_type 141 | 142 | ; build header 143 | lea rdi, [mimebuf] 144 | lea rsi, [headerbuf] 145 | call build_http_header 146 | 147 | ; send header 148 | mov rax, SYS_WRITE 149 | mov rdi, [clientfd] 150 | lea rsi, [headerbuf] 151 | mov rdx, rax ; header length trả về từ build_http_header trong rax 152 | syscall 153 | 154 | ; send file content 155 | mov rax, SYS_WRITE 156 | mov rdi, [clientfd] 157 | lea rsi, [filebuf] 158 | mov rdx, rcx 159 | syscall 160 | 161 | ret 162 | 163 | .send_404: 164 | mov rax, SYS_WRITE 165 | mov rdi, [clientfd] 166 | lea rsi, [http_404] 167 | mov rdx, http_404_len 168 | syscall 169 | ret 170 | 171 | parse_get_path: 172 | push rcx 173 | push rdx 174 | xor rcx, rcx 175 | .skip: 176 | cmp byte [rsi + rcx], ' ' 177 | je .found 178 | inc rcx 179 | cmp rcx, 10 180 | jne .skip 181 | jmp .done 182 | .found: 183 | inc rcx ; skip space 184 | xor rbx, rbx 185 | .copy: 186 | mov al, [rsi + rcx] 187 | cmp al, ' ' 188 | je .done 189 | cmp al, '/' 190 | je .skip_slash 191 | mov [rdi + rbx], al 192 | inc rbx 193 | .skip_slash: 194 | inc rcx 195 | cmp rbx, 255 196 | jl .copy 197 | .done: 198 | mov byte [rdi + rbx], 0 199 | pop rdx 200 | pop rcx 201 | ret 202 | 203 | build_http_header: 204 | ; rdi: mimebuf, rsi: headerbuf 205 | mov rcx, 0 206 | ; copy status 207 | mov rbx, header_1 208 | .copy1: 209 | mov al, [rbx + rcx] 210 | mov [rsi + rcx], al 211 | cmp al, 0 212 | je .copy_mime 213 | inc rcx 214 | jmp .copy1 215 | .copy_mime: 216 | dec rcx 217 | mov rbx, rdi 218 | .copy2: 219 | mov al, [rbx] 220 | mov [rsi + rcx], al 221 | cmp al, 0 222 | je .copy3 223 | inc rbx 224 | inc rcx 225 | jmp .copy2 226 | .copy3: 227 | mov rbx, header_2 228 | mov rdx, 0 229 | .copy4: 230 | mov al, [rbx + rdx] 231 | mov [rsi + rcx], al 232 | inc rcx 233 | inc rdx 234 | cmp byte [rbx + rdx -1], 0 235 | jne .copy4 236 | .done: 237 | mov rax, rcx ; return header length 238 | ret 239 | 240 | header_1 db "HTTP/1.1 200 OK", 13,10,"Content-Type: ",0 241 | header_2 db 13,10,"Connection: close",13,10,13,10,0 242 | 243 | -------------------------------------------------------------------------------- /Sources/http-server/mime-type.asm: -------------------------------------------------------------------------------- 1 | global get_mime_type 2 | 3 | section .rodata 4 | ; MIME table: [ext, mimetype] 5 | mime_table: 6 | db ".html",0,"text/html",0 7 | db ".css",0,"text/css",0 8 | db ".js",0,"application/javascript",0 9 | db ".png",0,"image/png",0 10 | db ".jpg",0,"image/jpeg",0 11 | db ".jpeg",0,"image/jpeg",0 12 | db ".txt",0,"text/plain",0 13 | db 0 14 | plain db "text/plain", 0 15 | 16 | section .text 17 | 18 | get_mime_type: 19 | ; rdi: filepath, rsi: mimebuf 20 | push rdi 21 | push rsi 22 | ; find last dot 23 | mov rbx, rdi 24 | .find_dot: 25 | cmp byte [rbx], 0 26 | je .noext 27 | cmp byte [rbx], '.' 28 | je .found 29 | inc rbx 30 | jmp .find_dot 31 | .found: 32 | ; rbx = .ext 33 | lea rdx, [mime_table] 34 | .next: 35 | cmp byte [rdx], 0 36 | je .noext 37 | ; compare ext 38 | mov rdi, rbx 39 | mov rsi, rdx 40 | call strcmp 41 | cmp rax, 0 42 | jne .skip 43 | ; match: copy mime type 44 | .cpy: 45 | ; skip ext 46 | .skip0: 47 | cmp byte [rdx], 0 48 | je .start_cpy 49 | inc rdx 50 | jmp .skip0 51 | .start_cpy: 52 | inc rdx 53 | mov rcx, 0 54 | .copy_loop: 55 | mov al, [rdx + rcx] 56 | mov [rsi + rcx], al 57 | cmp al, 0 58 | je .done 59 | inc rcx 60 | jmp .copy_loop 61 | .skip: 62 | ; skip ext and mime 63 | .sk: 64 | cmp byte [rdx], 0 65 | je .sk2 66 | inc rdx 67 | jmp .sk 68 | .sk2: 69 | inc rdx 70 | cmp byte [rdx], 0 71 | je .next 72 | jmp .next 73 | .noext: 74 | ; default: text/plain 75 | mov rax, 0 76 | mov rbx, rsi 77 | mov rdi, plain 78 | .cp: 79 | mov al, [rdi + rax] 80 | mov [rbx + rax], al 81 | cmp al, 0 82 | je .done 83 | inc rax 84 | jmp .cp 85 | .done: 86 | pop rsi 87 | pop rdi 88 | ret 89 | 90 | strcmp: 91 | xor rax, rax 92 | .loop: 93 | mov al, [rdi] 94 | mov bl, [rsi] 95 | cmp al, bl 96 | jne .diff 97 | test al, al 98 | je .same 99 | inc rdi 100 | inc rsi 101 | jmp .loop 102 | .same: 103 | xor rax, rax 104 | ret 105 | .diff: 106 | mov rax, 1 107 | ret 108 | -------------------------------------------------------------------------------- /Sources/multi-thread/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | nasm -f elf64 threads.asm -o threads.o 3 | gcc -no-pie -nostartfiles threads.o -o threads -lc 4 | clean: 5 | rm -f *.o threads -------------------------------------------------------------------------------- /Sources/multi-thread/threads.asm: -------------------------------------------------------------------------------- 1 | %define SYS_folk 57 2 | %define SYS_exit 60 3 | %define SYS_nanosleep 35 4 | %define num_threads 10 5 | 6 | section .data 7 | fmt_msg db "[Thread %d] Sleeping %d sec...", 10, 0 8 | thread_start_msg db "Thread %d started", 10, 0 9 | start_msg db "Multi-thread demo", 10, 0 10 | stop_msg db "Press Ctrl-C to stop...", 10, 0 11 | 12 | section .bss 13 | thread_ids resq num_threads 14 | 15 | section .text 16 | extern printf 17 | extern srand 18 | extern rand 19 | global _start 20 | 21 | ; ----------------------------- 22 | _start: 23 | mov rdi, start_msg 24 | call printf 25 | 26 | ; seed rand 27 | mov rdi, 0x_cafe_babe 28 | call srand 29 | 30 | mov rbx, 0 31 | .next_thread: 32 | cmp rbx, num_threads 33 | jge wait_exit 34 | 35 | mov rax, SYS_folk 36 | syscall 37 | 38 | test rax, rax 39 | jz .child ; child thread will go to thread_func 40 | 41 | ; parent, save child id 42 | mov [thread_ids + rbx*8], rax 43 | inc rbx 44 | jmp .next_thread 45 | 46 | .child: 47 | ; child thread jumps directly to function 48 | jmp thread_func 49 | 50 | ; ----------------------------- 51 | thread_func: 52 | mov rdi, thread_start_msg 53 | mov rsi, rbx ; rbx = thread number (0..n) 54 | call printf 55 | 56 | .loop: 57 | 58 | ; sleep random 1–10 seconds, rax is now containing a random value 59 | call rand 60 | xor rdx, rdx 61 | mov rcx, 10 62 | div rcx ; rax = rand() / 0, rdx = rand() % 10 63 | inc rdx ; rdx = remainer + 1 64 | add rdx, rbx 65 | 66 | mov r12, rdx 67 | 68 | mov rdi, fmt_msg 69 | mov rsi, rbx 70 | call printf 71 | 72 | ; build timespec 73 | sub rsp, 16 74 | mov qword [rsp], r12 ; tv_sec 75 | mov qword [rsp+8], 0 ; tv_nsec 76 | mov rdi, rsp 77 | xor rsi, rsi 78 | mov rax, SYS_nanosleep 79 | syscall 80 | add rsp, 16 81 | 82 | jmp .loop 83 | 84 | mov rax, SYS_exit 85 | xor rdi, rdi 86 | syscall 87 | 88 | ; ----------------------------- 89 | wait_exit: 90 | ; parent waits until user kills it or all threads done (basic version ends here) 91 | ; in real case should use futex or pthread join 92 | 93 | mov rdi, stop_msg 94 | call printf 95 | 96 | .wait: 97 | jmp .wait 98 | -------------------------------------------------------------------------------- /Sources/pointers/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | nasm -f elf64 -g -F dwarf pointers.asm -o pointers.o 3 | ld pointers.o -o pointers 4 | 5 | clean: 6 | rm -f *.o pointers -------------------------------------------------------------------------------- /Sources/pointers/pointers.asm: -------------------------------------------------------------------------------- 1 | %macro linefeed 0 2 | mov rax, 1 3 | mov rdi, 1 4 | mov rsi, linefeed_msg 5 | mov rdx, 2 6 | syscall 7 | %endmacro 8 | 9 | %macro print_string 2 10 | mov rax, 1 11 | mov rdi, 1 12 | mov rsi, %1 13 | mov rdx, %2 14 | syscall 15 | %endmacro 16 | 17 | section .text 18 | global _start 19 | 20 | _start: 21 | ; in địa chỉ của x 22 | print_string address_x_msg, address_x_msg_len 23 | mov rdi, x 24 | call print_hex 25 | linefeed 26 | 27 | ; in giá trị của x 28 | print_string value_x_msg, value_x_msg_len 29 | mov rdi, [x] 30 | call print_hex 31 | linefeed 32 | 33 | ; in địa chỉ của p 34 | print_string address_p_msg, address_p_msg_len 35 | mov rdi, p 36 | call print_hex 37 | linefeed 38 | 39 | ; in giá trị của p 40 | print_string value_p_msg, value_p_msg_len 41 | mov rdi, [p] 42 | call print_hex 43 | linefeed 44 | 45 | print_string p_points_to_x_msg, p_points_to_x_msg_len 46 | linefeed 47 | 48 | ; p = &x; 49 | mov rdi, x 50 | mov [p], rdi 51 | 52 | ; in giá trị của p 53 | print_string value_p_msg, value_p_msg_len 54 | mov rdi, [p] 55 | call print_hex 56 | linefeed 57 | 58 | print_string change_x_value_msg, change_x_value_msg_len 59 | linefeed 60 | 61 | ; thay đổi giá trị của x: x = 0x_0000_CAFEBABE_0000 62 | mov rax, 0x_0000_CAFEBABE_0000 63 | mov [x], rax 64 | 65 | ; in ra giá trị tại *p 66 | print_string value_p_dest_msg, value_p_dest_msg_len 67 | mov rdi, [p] 68 | mov rdi, [rdi] 69 | call print_hex 70 | 71 | linefeed 72 | 73 | mov rax, 60 74 | mov rdi, 0 75 | syscall 76 | 77 | print_hex: 78 | push rsi 79 | push rdx 80 | push rcx 81 | push rax 82 | 83 | mov rcx, 16 ; Số chữ số hex cần in 84 | lea rsi, [hex_buffer + 16] ; Con trỏ đến cuối buffer 85 | .hex_loop: 86 | dec rsi ; Lùi về 1 byte để ghi ký tự 87 | mov rax, rdi 88 | and rax, 0xF ; Lấy 4 bit thấp 89 | cmp rax, 10 90 | jl .digit 91 | add al, 'a' - 10 92 | jmp .store 93 | .digit: 94 | add al, '0' 95 | .store: 96 | mov [rsi], al 97 | shr rdi, 4 ; Dịch sang phải 4 bit (1 hex digit) 98 | loop .hex_loop 99 | 100 | ; Ghi ra stdout (sys_write) 101 | mov rax, 1 ; syscall: write 102 | mov rdi, 1 ; fd: stdout 103 | mov rdx, 16 ; số byte cần ghi 104 | syscall 105 | 106 | pop rax 107 | pop rcx 108 | pop rdx 109 | pop rsi 110 | ret 111 | 112 | 113 | section .data 114 | address_x_msg db 'Address of x: ' 115 | address_x_msg_len equ $ - address_x_msg 116 | value_x_msg db 'Value of x: ' 117 | value_x_msg_len equ $ - value_x_msg 118 | address_p_msg db 'Address of p: ' 119 | address_p_msg_len equ $ - address_p_msg 120 | value_p_msg db 'Value of p: ' 121 | value_p_msg_len equ $ - value_p_msg 122 | value_p_dest_msg db 'Value of *p: ' 123 | value_p_dest_msg_len equ $ - value_p_dest_msg 124 | p_points_to_x_msg db 10, 13, 'SET: p = &x;', 10, 13 125 | p_points_to_x_msg_len equ $ - p_points_to_x_msg 126 | change_x_value_msg db 10, 13, 'SET: x = 0x_0000_CAFEBABE_0000;', 10, 13 127 | change_x_value_msg_len equ $ - change_x_value_msg 128 | linefeed_msg db 10, 13 129 | x dq 0x_CAFEBABE_CAFEBABE ; biến x (unsigned long long x = 0x_CAFEBABE_CAFEBABE;) 130 | 131 | section .bss 132 | p resq 1 ; con trỏ p (int *p;) 133 | hex_buffer resb 16 134 | 135 | -------------------------------------------------------------------------------- /Sources/snake-game/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | nasm -f elf64 snake.asm -o snake.o 3 | ld snake.o -o snake 4 | clean: 5 | rm -f *.o snake 6 | -------------------------------------------------------------------------------- /Sources/snake-game/snake.asm: -------------------------------------------------------------------------------- 1 | ; Build with: 2 | ; nasm -f elf64 snake.asm -o snake.o 3 | ; ld snake.o -o snake 4 | ; Run in terminal (Linux) with stty raw -echo; ./snake 5 | 6 | BITS 64 7 | DEFAULT REL 8 | 9 | section .data 10 | clear_screen db 27, '[2J', 0 11 | cursor_home db 27, '[H', 0 12 | game_over_msg db 27, '[H', 'Game Over! Press Enter to restart.', 0 13 | snake_char db 'o' 14 | food_char db 'x' 15 | snake_init_len equ 3 16 | max_snake_len equ 2000 17 | width equ 80 18 | height equ 25 19 | 20 | section .bss 21 | snake_x resb max_snake_len 22 | snake_y resb max_snake_len 23 | snake_len resb 1 24 | food_x resb 1 25 | food_y resb 1 26 | dir resb 1 ; 0=left,1=right,2=up,3=down 27 | char resb 1 28 | 29 | section .text 30 | global _start 31 | 32 | _start: 33 | call init_game 34 | main_loop: 35 | call read_key 36 | call move_snake 37 | call check_collision 38 | call draw 39 | jmp main_loop 40 | 41 | ; ================================ 42 | ; initialize game 43 | ; ================================ 44 | init_game: 45 | mov rsi, clear_screen 46 | call print_string 47 | mov rsi, cursor_home 48 | call print_string 49 | ; Set initial direction = right 50 | mov byte [dir], 1 51 | ; Set initial snake length 52 | mov byte [snake_len], snake_init_len 53 | ; Init snake positions 54 | mov rcx, snake_init_len 55 | mov rbx, 40 ; mid X 56 | mov rdx, 12 ; mid Y 57 | .init_loop: 58 | mov [snake_x + rcx - 1], bl 59 | mov [snake_y + rcx - 1], dl 60 | dec bl 61 | loop .init_loop 62 | ; Place food 63 | call place_food 64 | ret 65 | 66 | ; ================================ 67 | ; read key 68 | ; ================================ 69 | read_key: 70 | mov eax, 0 ; syscall: read 71 | mov edi, 0 ; stdin 72 | mov rsi, char 73 | mov edx, 3 ; read up to 3 bytes 74 | syscall 75 | cmp byte [char], 27 ; ESC? 76 | jne .check_arrows 77 | mov eax, 60 ; exit 78 | xor edi, edi 79 | syscall 80 | 81 | .check_arrows: 82 | cmp byte [char+1], 91 83 | jne .done 84 | mov al, [char+2] 85 | cmp al, 'A' 86 | je .up 87 | cmp al, 'B' 88 | je .down 89 | cmp al, 'C' 90 | je .right 91 | cmp al, 'D' 92 | je .left 93 | jmp .done 94 | 95 | .up: 96 | cmp byte [dir], 3 97 | je .done 98 | mov byte [dir], 2 99 | jmp .done 100 | .down: 101 | cmp byte [dir], 2 102 | je .done 103 | mov byte [dir], 3 104 | jmp .done 105 | .left: 106 | cmp byte [dir], 1 107 | je .done 108 | mov byte [dir], 0 109 | jmp .done 110 | .right: 111 | cmp byte [dir], 0 112 | je .done 113 | mov byte [dir], 1 114 | .done: 115 | ret 116 | 117 | ; ================================ 118 | ; move snake 119 | ; ================================ 120 | move_snake: 121 | ; Shift body 122 | mov cl, [snake_len] 123 | dec cl 124 | .rev: 125 | mov al, [snake_x + rcx] 126 | mov [snake_x + rcx + 1], al 127 | mov al, [snake_y + rcx] 128 | mov [snake_y + rcx + 1], al 129 | loop .rev 130 | 131 | ; Move head 132 | mov al, [snake_x] 133 | mov bl, [snake_y] 134 | mov dl, [dir] 135 | cmp dl, 0 136 | jne .not_left 137 | dec al 138 | jmp .set 139 | .not_left: 140 | cmp dl, 1 141 | jne .not_right 142 | inc al 143 | jmp .set 144 | .not_right: 145 | cmp dl, 2 146 | jne .not_up 147 | dec bl 148 | jmp .set 149 | .not_up: 150 | inc bl 151 | .set: 152 | mov [snake_x], al 153 | mov [snake_y], bl 154 | 155 | ; Check if food eaten 156 | cmp al, [food_x] 157 | jne .no_eat 158 | cmp bl, [food_y] 159 | jne .no_eat 160 | inc byte [snake_len] 161 | call place_food 162 | .no_eat: 163 | ret 164 | 165 | ; ================================ 166 | ; draw screen 167 | ; ================================ 168 | draw: 169 | mov rsi, clear_screen 170 | call print_string 171 | mov rcx, [snake_len] 172 | xor rbx, rbx 173 | .draw_loop: 174 | mov al, [snake_x + rbx] 175 | mov bl, [snake_y + rbx] 176 | call draw_char_at 177 | inc rbx 178 | loop .draw_loop 179 | 180 | ; draw food 181 | mov al, [food_x] 182 | mov bl, [food_y] 183 | mov sil, byte [food_char] 184 | call draw_at 185 | ret 186 | 187 | ; ================================ 188 | ; check collision 189 | ; ================================ 190 | check_collision: 191 | mov al, [snake_x] 192 | mov bl, [snake_y] 193 | mov rcx, [snake_len] 194 | cmp cl, 3 195 | jl .ok 196 | mov rsi, 1 197 | .loop: 198 | mov dl, [snake_x + rsi] 199 | cmp al, dl 200 | jne .next 201 | mov dl, [snake_y + rsi] 202 | cmp bl, dl 203 | je .dead 204 | .next: 205 | inc rsi 206 | loop .loop 207 | .ok: 208 | ret 209 | .dead: 210 | mov rsi, game_over_msg 211 | call print_string 212 | .wait_key: 213 | mov eax, 0 214 | mov edi, 0 215 | mov rsi, char 216 | mov edx, 1 217 | syscall 218 | cmp byte [char], 10 219 | jne .wait_key 220 | call init_game 221 | ret 222 | 223 | ; ================================ 224 | ; place food (simple rand using time) 225 | ; ================================ 226 | place_food: 227 | mov eax, 201 ; syscall: time 228 | xor edi, edi 229 | syscall 230 | ; use rax for x and y 231 | mov bl, al 232 | and bl, 79 233 | add bl, 1 234 | mov [food_x], bl 235 | shr al, 1 236 | and al, 23 237 | add al, 1 238 | mov [food_y], al 239 | ret 240 | 241 | ; ================================ 242 | ; draw_char_at: al = x, bl = y, draw 'o' 243 | ; ================================ 244 | draw_char_at: 245 | push rsi 246 | mov sil, [snake_char] 247 | call draw_at 248 | pop rsi 249 | ret 250 | 251 | ; ================================ 252 | ; draw_at: al = x, bl = y, sil = char 253 | ; ================================ 254 | draw_at: 255 | push rdi 256 | mov rdi, 1 257 | mov edx, 1 258 | mov ah, 0 259 | mov rsi, rsp 260 | mov [rsp-1], sil 261 | sub rsp, 1 262 | ; ANSI cursor move 263 | mov rax, 1 264 | call set_cursor 265 | mov eax, 1 266 | syscall 267 | add rsp, 1 268 | pop rdi 269 | ret 270 | 271 | ; ================================ 272 | ; set_cursor: al = x, bl = y 273 | ; ================================ 274 | set_cursor: 275 | ; builds ANSI "\033[%d;%dH" 276 | push rbx 277 | push rax 278 | mov rsi, cursor_home 279 | call print_string 280 | pop rax 281 | pop rbx 282 | ret 283 | 284 | ; ================================ 285 | ; print_string: rsi = zero-term string 286 | ; ================================ 287 | print_string: 288 | mov rdi, rsi 289 | xor rcx, rcx 290 | .find_len: 291 | cmp byte [rdi + rcx], 0 292 | je .done_len 293 | inc rcx 294 | jmp .find_len 295 | .done_len: 296 | mov eax, 1 297 | mov edi, 1 298 | mov edx, ecx 299 | syscall 300 | ret 301 | -------------------------------------------------------------------------------- /Sources/solve_linear_simd/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | nasm -f elf64 solve_linear_simd.asm 3 | gcc -no-pie -nostartfiles -mavx -o solve_linear_simd solve_linear_simd.o 4 | clean: 5 | rm -f *.o solve_linear_simd -------------------------------------------------------------------------------- /Sources/solve_linear_simd/inputs.txt: -------------------------------------------------------------------------------- 1 | 1000.0 20.0 2 | 15.0 1500.0 3 | 0.5 2 4 | 111111.1111 999999.9999 5 | -------------------------------------------------------------------------------- /Sources/solve_linear_simd/solve_linear_simd.asm: -------------------------------------------------------------------------------- 1 | extern printf 2 | extern scanf 3 | 4 | section .rodata 5 | read_format db "%lf %lf", 0 6 | result_msg db "[%d] %lfx + %lf = 0 => x = %lf", 10, 0 7 | step_msg db "Step!", 10, 0 8 | align 32 9 | neg_mask: dq 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000 10 | 11 | section .bss 12 | align 32 13 | a_values resq 4 ; 4 x double = 32 bytes 14 | align 32 15 | b_values resq 4 16 | align 32 17 | x_values resq 4 18 | 19 | section .text 20 | global _start 21 | 22 | _start: 23 | ; Read 4 pairs (a[i], b[i]) 24 | xor r12, r12 25 | .read_loop: 26 | ; scanf("%lf %lf", &a[i], &b[i]) 27 | mov rdi, read_format 28 | lea rsi, [a_values+ r12*8] 29 | lea rdx, [b_values + r12*8] 30 | xor rax, rax 31 | call scanf 32 | 33 | inc r12 34 | cmp r12, 4 35 | jl .read_loop 36 | 37 | ; Load 4 a’s and b’s to ymm registers 38 | vmovapd ymm0, [a_values] ; ymm0 = a[0..3] 39 | vmovapd ymm1, [b_values] ; ymm1 = b[0..3] 40 | 41 | ; Load negate mask 42 | vmovapd ymm2, [neg_mask] 43 | vxorpd ymm1, ymm1, ymm2 ; ymm1 = -b 44 | 45 | ; Compute x = -b / a 46 | vdivpd ymm3, ymm1, ymm0 ; ymm3 = x[0..3] 47 | 48 | ; Store results 49 | vmovapd [x_values], ymm3 50 | 51 | ; Print results 52 | xor r12, r12 53 | .print_loop: 54 | ; Load double x[i] to xmm0 (lower 64-bit of ymm3) 55 | movsd xmm0, [a_values + r12*8] 56 | movsd xmm1, [b_values + r12*8] 57 | movsd xmm2, [x_values + r12*8] 58 | mov rdi, result_msg 59 | mov rsi, r12 60 | inc rsi 61 | mov eax, 3 62 | call printf 63 | 64 | inc r12 65 | cmp r12, 4 66 | jl .print_loop 67 | 68 | ; Exit 69 | mov rax, 60 70 | xor rdi, rdi 71 | syscall -------------------------------------------------------------------------------- /Sources/sorting/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | nasm -f elf64 -g -F dwarf main.asm -o bubblesort.o 3 | nasm -f elf64 -g -F dwarf int-utils.asm -o int-utils.o 4 | nasm -f elf64 -g -F dwarf io-utils.asm -o io-utils.o 5 | ld bubblesort.o int-utils.o io-utils.o -o bubblesort 6 | 7 | clean: 8 | rm -f *.o bubblesort -------------------------------------------------------------------------------- /Sources/sorting/int-utils.asm: -------------------------------------------------------------------------------- 1 | global print_str 2 | global int_to_str 3 | global str_to_int 4 | 5 | extern input_buf 6 | 7 | ;----------------------- 8 | ; Hàm str_to_int: chuỗi -> số 9 | ; Input: RSI = địa chỉ chuỗi 10 | ; Output: RAX = số nguyên (64-bit) 11 | ;----------------------- 12 | str_to_int: 13 | xor rax, rax 14 | xor rbx, rbx 15 | .next_digit: 16 | mov bl, byte [rsi] 17 | cmp bl, 10 18 | je .done 19 | cmp bl, 13 20 | je .done 21 | cmp bl, 0 22 | je .done 23 | sub bl, '0' 24 | imul rax, rax, 10 25 | add rax, rbx 26 | inc rsi 27 | jmp .next_digit 28 | .done: 29 | ret 30 | 31 | ;----------------------- 32 | ; Hàm int_to_str 33 | ; Input: RAX = số nguyên 34 | ; Output: input_buf = chuỗi kết quả (kết thúc bằng newline) 35 | ;----------------------- 36 | int_to_str: 37 | mov rsi, input_buf 38 | add rsi, 31 39 | mov byte [rsi], 10 ; newline 40 | dec rsi 41 | xor rcx, rcx 42 | 43 | .convert: 44 | xor rdx, rdx 45 | mov rbx, 10 46 | div rbx 47 | add dl, '0' 48 | mov [rsi], dl 49 | dec rsi 50 | inc rcx 51 | test rax, rax 52 | jnz .convert 53 | 54 | inc rsi 55 | mov rdi, rsi 56 | mov rdx, rcx 57 | inc rdx ; để in cả newline 58 | ret 59 | 60 | -------------------------------------------------------------------------------- /Sources/sorting/io-utils.asm: -------------------------------------------------------------------------------- 1 | global print_str 2 | 3 | ;----------------------- 4 | ; print_str 5 | ; Input: RDI = địa chỉ chuỗi, RDX = độ dài 6 | ;----------------------- 7 | print_str: 8 | mov rax, 1 ; write 9 | mov rdi, 1 ; stdout 10 | syscall 11 | ret -------------------------------------------------------------------------------- /Sources/sorting/main.asm: -------------------------------------------------------------------------------- 1 | extern print_str 2 | extern str_to_int 3 | extern int_to_str 4 | 5 | global input_buf 6 | 7 | section .text 8 | global _start 9 | 10 | _start: 11 | mov rsi, prompt 12 | mov rdx, prompt_len 13 | call print_str 14 | 15 | xor r12, r12 ; chỉ số i = 0 16 | 17 | read_loop: 18 | cmp r12, 10 19 | je bubble_sort 20 | 21 | ; đọc một dòng từ stdin 22 | mov rax, 0 ; syscall read 23 | mov rdi, 0 ; stdin 24 | mov rsi, input_buf 25 | mov rdx, 32 26 | syscall 27 | 28 | ; chuyển chuỗi sang số nguyên 29 | mov rsi, input_buf 30 | call str_to_int 31 | 32 | mov [numbers + r12*8], rax ; lưu giá trị vào mảng 33 | 34 | inc r12 35 | jmp read_loop 36 | 37 | ;----------------------- 38 | ; Bubble Sort 39 | ;----------------------- 40 | bubble_sort: 41 | mov rsi, sorting_prompt 42 | mov rdx, sorting_prompt_len 43 | call print_str 44 | 45 | mov rcx, 10 46 | outer_loop: 47 | dec rcx 48 | mov rbx, 0 49 | inner_loop: 50 | mov r8, [numbers + rbx*8] 51 | mov r9, [numbers + rbx*8 + 8] 52 | cmp r8, r9 53 | jle no_swap 54 | 55 | ; hoán đổi 56 | mov [numbers + rbx*8], r9 57 | mov [numbers + rbx*8 + 8], r8 58 | 59 | no_swap: 60 | inc rbx 61 | cmp rbx, rcx 62 | jl inner_loop 63 | cmp rcx, 1 64 | jg outer_loop 65 | 66 | ;----------------------- 67 | ; In kết quả ra màn hình 68 | ;----------------------- 69 | mov rsi, result_prompt 70 | mov rdx, result_prompt_len 71 | call print_str 72 | 73 | xor r12, r12 74 | print_loop: 75 | cmp r12, 10 76 | je exit 77 | 78 | mov rax, [numbers + r12*8] 79 | call int_to_str ; chuyển số thành chuỗi, kết quả ở input_buf 80 | call print_str ; in chuỗi ra màn hình 81 | 82 | inc r12 83 | jmp print_loop 84 | 85 | ;----------------------- 86 | ; Thoát chương trình 87 | ;----------------------- 88 | exit: 89 | mov rax, 60 90 | xor rdi, rdi 91 | syscall 92 | 93 | ; %include "int-utils.asm" 94 | ; %include "io-utils.asm" 95 | 96 | section .rodata 97 | prompt db 'Enter 10 int64 values:', 0x0A, 0x0D 98 | prompt_len equ $ - prompt 99 | sorting_prompt db 'Start sorting...', 0x0A, 0x0D 100 | sorting_prompt_len equ $ - sorting_prompt 101 | result_prompt db 'Result:', 0x0A, 0x0D 102 | result_prompt_len equ $ - result_prompt 103 | 104 | section .bss 105 | numbers resq 10 ; mảng chứa 10 số nguyên 64-bit 106 | input_buf resb 32 ; buffer để đọc chuỗi nhập vào 107 | 108 | 109 | --------------------------------------------------------------------------------