# BÁO CÁO LẦN 1 # I. Tìm hiểu về ASM ## 1.Tổng quan * Theo em qua tìm hiểu thì Assembly là một ngôn ngữ lập trình gần với ngôn ngữ máy, được sử dụng để viết chương trình cho các vi xử lý thông qua các hướng dẫn (instruction) cơ bản mà vi xử lý hiểu được * Khi viết code trong một ngôn ngữ lập trình bậc cao như C, C++, Java, hoặc Python, code sẽ được compile từ ngôn ngữ bậc cao này sang ngôn ngữ bậc thấp hơn để máy tính có thể hiểu được. Ví dụ nếu code một chương trình bằng Python thì source sẽ được compile như sau Python ---> C++ ---> C ---> ASM ---> Binary. * Có nhiều dạng ngôn ngữ assembly, mỗi loại phụ thuộc vào kiến trúc của bộ vi xử lý mà nó hướng đến như : MASM32, NASM, MISP, ARM. * ASM sẽ k dùng các biến như các ngôn ngữ bậc cao khác mà dữ liệu sẽ được lưu trữ tạm thời ở các thanh ghi. Có nhiều loại thanh ghi nhưng NASM sẽ chỉ tương tác đa phần ở các thanh ghi 32bit ![image](https://hackmd.io/_uploads/Hyu-cUpda.png) đây là tổng quan về các thanh ghi 32bit ## 2.Thanh Ghi ### a.Thanh ghi Đa Năng Có 8 thanh ghi đa năng khác nhau: * EAX : Thanh ghi chính được sử dụng trong tính toán số học chứa kết quả của các phép tính số học và giá trị trả về của hàm. * EBX : Thanh ghi cơ sở được sử dụng để lưu trữ địa chỉ cơ sở của chương trình. * ECX : Thanh ghi bộ đếm thường được sử dụng để giữ giá trị biểu thị số lần một quá trình được lặp lại. Được sử dụng cho các hoạt động vòng lặp và chuỗi. * EDX : được dùng tương tự như EAX ngoài ra sẽ mở rộng EAX lên 64-bit. * ESI : Thanh ghi chỉ mục nguồn được sử dụng làm địa chỉ nguồn cho các phép toán với xâu.' * EDI được sử dụng làm địa chỉ đích cho các phép toán với xâu. * EBP : Con trỏ cơ sở trỏ đến cuối khung ngăn xếp hiện tại. Nó được sử dụng để tham chiếu các biến cục bộ. * ESP : Con trỏ ngăn xếp . Nó trỏ đến đầu khung ngăn xếp hiện tại. Nó được sử dụng để tham chiếu các biến cục bộ. ### b.Thanh ghi đoạn * CS : Thanh ghi đoạn mã lưu trữ vị trí cơ sở của phần mã (section .text) được sử dụng để truy cập dữ liệu. * DS : Thanh ghi phân đoạn dữ liệu lưu trữ vị trí mặc định cho các biến (phần .data) được sử dụng để truy cập dữ liệu. * SS: chứa dữ liệu và địa chỉ trả về của các chương trình con. * ES : Thanh ghi phân đoạn bổ sung được sử dụng trong các hoạt động chuỗi. * FS : Thanh ghi phân đoạn bổ sung. * GS : Thanh ghi phân đoạn bổ sung. ### c.Thanh ghi điều khiển Thanh ghi con trỏ lệnh 32 bit và thanh ghi cờ 32 bit (Flags Register) kết hợp với nhau được coi là thanh ghi điều khiển.Có các thanh ghi cờ như sau: * CF : Mang cờ * PF : Cờ chẵn lẻ * AF : Cờ điều chỉnh * ZF : Cờ không * SF : Cờ hiệu * OF : Cờ tràn ## Cấu trúc chương trình NASM ### Section bss * Dùng để khai báo các `dynamic variable` ### Section data * Dùng để khai báo các hằng số và các `static variable` ### Section text * Dùng để ghi code, bắt đầu với `global _start` được coi như là nhãn để đánh dấu bắt đầu chương trình. ``` Section .text global _start _start: ``` ### Một số command thường được dùng * `mov` : Dùng để gán giá trị * `add, sub` : Tính tổng, hiệu * `cmp` : So sánh hai giá trị với nha * `push` : Đẩy giá trị * `pop` : Lấy giá trị ra * `ret` : Trả về từ hàm (quay lại địa chỉ được lưu trước đó trên stack) * `inc` : Tăng giá trị lên 1 * `dec ` : giảm giá trị đi 1 ## Cách compile và link file asm * Đầu tiên cần tạo file một file có đuôi là `.asm` ở đây ví dụ là `deadline.asm` và push code asm vào file ![Screenshot from 2024-01-13 02-07-56](https://hackmd.io/_uploads/rkg8z61Kp.png) * Tiếp đó là gõ `nasm -f elf32 -0 deadline.o deadline.asm` để compiled file và tạo ra file object ![Screenshot from 2024-01-13 02-08-50](https://hackmd.io/_uploads/Hyc2GaJY6.png) * Để liên kết file object và tạo file execute thì gõ `ld -m elf_i386 -o deadline deadline.o` ![Screenshot from 2024-01-13 03-01-14](https://hackmd.io/_uploads/ryTd7pJKp.png) # Code Chương Trình NASM ## In ra dòng chữ `Hello KCSC!!` ``` section .data msg db 'Hello KCSC!!', 0xa len equ $ - msg section .text global _start _start: mov edx, len mov ecx, msg mov ebx, 1 mov eax, 4 int 0x80 mov ebx, 0 mov eax, 1 int 0x80 ``` ### **Giải thích Code:** * Ở phần `Section .data` khai báo biến `msg` với kiểu dữ liệu là byte `db` và `0xa` là kí tự xuống dòng. `len equ $ - msg` định nghĩa biến len là địa chỉ hiện tại và trừ đi địa chỉ của biến `msg` để lấy độ dài của biến `msg` * Ở phần `Section .text` nhãn `_start` để báo cho kernel nơi bắt đầu chương trình. Gán địa chỉ biến len vào thanh ghi `edx` vầ gán địa chỉ của biến msg vào ecx. Gán file descriptor của STDOUT vào thanh ghi ebx. Gán mã hệ thống bằng 4 (SYS_Write) vào thanh ghi eax và gọi hàm ngắt để in chuỗi ra màn hình. Gàn ebx = 0, eax = 1 (SYS_Exit) và gọi hàm ngắt để tránh lỗi `Segmentation fault` ![Screenshot from 2024-01-15 03-29-48](https://hackmd.io/_uploads/rkqSaPMKT.png) ## Nhập và in chuỗi `Minh Triet AT20` ``` section .data msg: db "Nhap chuoi: ",0xa len equ $ - msg str: times 256 db 0 section .text global _start _start: mov edx, len mov ecx, msg mov ebx, 1 mov eax, 4 int 0x80 mov edx, len mov ecx, str mov ebx, 0 mov eax, 3 int 0x80 mov edx, len mov ecx, str mov ebx, 1 mov eax, 4 int 0x80 mov eax, 1 int 0x80 ``` * Từ section .data đến in chuỗi ra màn hình giống như bài đầu. ``` mov edx, len mov ecx, str mov ebx, 0 mov eax, 3 int 0x80 ``` * gán len vào edx và str vào ecx. gán ebx = 0 và eax = 3 (SYS_read) gọi hệ thống nhận chuỗi nhập vào từ user và gọi hàm ngắt. ``` mov edx, len mov ecx, str mov ebx, 1 mov eax, 4 int 0x80 ``` * In chuỗi user vừa nhập và màn hình và gọi hàm ngắt ``` mov eax, 1 int 0x80 ``` * Gọi SYS_exit và kết thúc chương trình ![Screenshot from 2024-01-15 05-48-39](https://hackmd.io/_uploads/S1XsWcGtT.png) ## TÌM HIỂU VỀ ASM P2 ### I. Các câu lệnh điều kiện (Conditional Command) #### 1. Lệnh CMP * Lệnh CMP so sánh hai toán hạng thường được sử dụng trong thực thi có điều kiện. Lệnh này về cơ bản trừ một toán hạng với toán hạng kia để so sánh xem các toán hạng có bằng nhau hay không. * CMP so sánh hai trường dữ liệu số. Toán hạng đích có thể nằm trong thanh ghi hoặc trong bộ nhớ. Toán hạng nguồn có thể là dữ liệu, thanh ghi hoặc bộ nhớ không đổi (tức thời). **Ví dụ :** ``` CMP DX, 00 ; So sánh DX với giá trị 00 JE Equal ; Nếu bằng thì jump tới Equal ``` #### 2. Lệnh nhảy vô điều kiện (Unconditional Jump) * Được thực hiện bởi lệnh `JMP`. Thực thi có điều kiện thường liên quan đến việc chuyển quyền điều khiển đến địa chỉ của lệnh không tuân theo lệnh hiện đang thực thi. Việc chuyển giao quyền điều khiển có thể tiến tới để thực hiện một tập lệnh mới hoặc lùi lại để thực hiện lại các bước tương tự. #### 3. Lệnh nhảy có điều kiện (Conditional Jump) * Nếu một số điều kiện xác định được thỏa mãn trong bước nhảy có điều kiện, luồng điều khiển sẽ được chuyển sang lệnh đích. Có rất nhiều lệnh nhảy có điều kiện tùy thuộc vào điều kiện và dữ liệu. Sau đây là các lệnh nhảy có điều kiện được sử dụng trên dữ liệu đã ký được sử dụng cho các phép tính số học ![Screenshot 2024-01-19 151602](https://hackmd.io/_uploads/H1Lke2wF6.png) 1. JE/JZ : Nhảy bằng hoặc nhảy bằng 0 2. JNE/JNZ : Nhảy ko bằng hoặc nhảy khác 0 3. JG/JNLE : Nhảy lớn hơn hoặc nhảy không ít hơn/bằng 4. JGE/JNL : Nhảy lớn hơn/bằng hoặc nhảy không ít hơn 5. JL/JNGE : Nhảy ít hơn hoặc nhảy không lớn hơn/bằng 6. JLE/JNG : Nhảy ít hơn/bằng hoặc nhảy không lớn hơn Còn bảng này sẽ là các lệnh nhảy có điều kiện sử dụng đặc biệt và kiểm tra giá trị của cờ ![Screenshot 2024-01-19 152619](https://hackmd.io/_uploads/rJSrfhDFa.png) * JXCZ : Nhảy nếu CX bằng 0 * JC : Nhảy nếu cờ CF được set * JNC : Nhảy nếu cờ CF không được set * JO : Nhảy nếu tràn * JNO : Nhảy nếu không tràn * JP/JPE : Nhảy nếu chẵn * JNP/JPO : Nhảy nếu không chẵn hoặc nhảy nếu lẻ * JS : Nhảy nếu có dấu(Giá trị âm) * JNS : Nhảy không dấu(Giá trị dương) ### II. Vòng lặp * Các lệnh jump có thể được sử dụng để thực hiện vòng lặp như jmp, je, jne, jl, jg, jle, jge, và các cấu trúc điều khiển khác để tạo vòng lặp. Chương trình dưới đây là lệnh in chuỗi 'Nguyen Minh Triet' 10 lần ``` section .data msg db 'Nguyen Minh Triet', 0xa len equ $ - msg section .text global _start: _start: mov edi, 10 L1: mov eax, 4 mov ebx, 1 mov ecx, msg mov edx, len int 0x80 DEC edi JNZ L1 mov eax, 1 int 0x80 ``` ### III. Array * Mảng là một tập hợp các giá trị được lưu trữ liên tiếp trong bộ nhớ. Mảng thường được sử dụng để lưu trữ và xử lý nhiều dữ liệu cùng loại. * Để khai báo một mảng trong NASM, sử dụng các instruction db (define byte) hoặc dw (define word) để xác định kích thước của mỗi phần tử trong mảng. * Ví dụ, đoạn mã sau khai báo một mảng có 5 phần tử kiểu word (2 byte) và khởi tạo giá trị ban đầu là 1, 2, 3, 4, 5: ``` array dw 1, 2, 3, 4, 5 ``` ### SYSCALL * Trong NASM, syscall là một lệnh được sử dụng để gọi các hệ thống gọi (system call) trong hệ điều hành. Lệnh syscall cho phép chương trình ASM tương tác với các dịch vụ hệ thống như đọc/ghi tệp, nhập/xuất trên màn hình, cấp phát bộ nhớ, và nhiều hoạt động hệ thống khác. * Trước khi thực hiện lệnh syscall, các tham số của hệ thống gọi được truyền vào các thanh ghi chứa các giá trị thích hợp. Sau khi lệnh syscall được gọi, kết quả của hệ thống gọi có thể được trả về qua các thanh ghi khác, chẳng hạn như thanh ghi eax Đây là bảng 4 syscall thường được dùng nhất khi lập trình NASM ![Screenshot 2024-01-23 200817](https://hackmd.io/_uploads/SkRIcN6Fa.png) 1. exit: Lệnh này được sử dụng để thoát khỏi chương trình và trả về giá trị thoát. Tham số truyền vào thông qua thanh ghi ebx để chỉ định mã thoát. 2. write: Lệnh này được sử dụng để ghi dữ liệu từ một bộ đệm (buffer) lên một file hoặc STDOUT (màn hình). Tham số truyền vào thông qua các thanh ghi ebx, ecx, edx để chỉ định file descriptor, địa chỉ bộ đệm và số lượng byte cần ghi. 3. read: Lệnh này được sử dụng để đọc dữ liệu từ một file hoặc STDIN (bàn phím) vào một bộ đệm. Tham số truyền vào thông qua các thanh ghi ebx, ecx, edx để chỉ định file descriptor, địa chỉ bộ đệm và số lượng byte cần đọc. 4. open: Lệnh này được sử dụng để mở một file và trả về file descriptor tương ứng. Tham số truyền vào thông qua các thanh ghi ebx, ecx, edx để chỉ định đường dẫn file, flags và mode. 5. close: Lệnh này được sử dụng để đóng một file descriptor đã mở trước đó. Tham số truyền vào thông qua thanh ghi ebx để chỉ định file descriptor cần đóng. ## CODING ### Code Selection Sort ``` section .text global _start _start: mov eax, 0x4 mov ebx, 0x1 mov ecx, msg1 mov edx, len1 int 0x80 mov eax, 0x3 mov ebx, 0 mov ecx, quant mov edx, 0xa int 0x80 dec eax mov ebx, ecx mov ecx, eax call _converstring mov dword [Numberscount], eax mov ecx, eax xor edi, edi call _ArrayIn call _selectionSort mov eax, 0x4 mov ebx, 0x1 mov ecx, msg4 mov edx, len4 int 0x80 mov ecx, dword [Numberscount] call _ArrayOut mov eax, 0x1 int 0x80 _selectionSort: xor eax, eax xor ebx, ebx xor ecx, ecx xor edx, edx xor edi, edi xor esi, esi ForI: mov edx, esi mov edi, esi ForJ: mov eax, dword [arr + 4 * edx] mov ecx, dword [arr + 4 * edi] cmp eax, ecx jl continue mov edx, edi continue: inc edi cmp edi, [Numberscount] jne ForJ mov eax, dword [arr + 4 * edx] mov ecx, dword [arr + 4 * esi] mov dword [arr + 4 * edx], ecx mov dword [arr + 4 * esi], eax inc esi cmp esi, [Numberscount] jne ForI ret _converstring: xor edx, edx xor eax, eax xor esi, esi stringToNum: mov edx, 10 mul edx mov dl, [ebx + esi] sub edx, 0x30 add eax, edx inc esi loop stringToNum ret _convertnum: mov ecx, 0 mov [F], ecx cmp eax, 2147483648 jna c0nt1nu3 inc ecx mov edx, 0x1 mov [F], edx mov edx, 0xffffffff sub edx, eax mov eax, edx c0nt1nu3: execute: xor edx, edx mov ebx, 10 div ebx add edx, 0x30 push edx inc ecx cmp eax, 0 jne execute mov edx, 0x1 cmp [F], edx jne Cont1nue push edx Cont1nue: mov ebp, 0 L00P: pop edx mov [num + ebp], edx inc ebp loop L00P ret _ArrayIn: mov [counti], ecx loop: xor eax, eax mov eax, edi call _convertnum mov eax, 0x3 mov ebx, 0x0 mov ecx, A mov edx, 0xa int 0x80 dec eax mov ebx, ecx mov ecx, eax call _converstring mov dword [arr + 4 * edi], eax inc edi cmp edi, [Numberscount] jne loop ret _ArrayOut: mov esi, 0 outloop: mov eax, dword [arr + 4 * esi] call _convertnum mov eax, 0x4 mov ebx, 0x1 mov ecx, num mov edx, ebp int 0x80 mov eax, 0x4 mov ebx, 0x1 mov ecx, 0x20 mov edx, 0x1 int 0x80 inc esi cmp esi, [Numberscount] jne outloop mov eax, 0x4 mov ebx, 0x1 mov ecx, 0xa mov edx, 0x1 int 0x80 ret section .data msg1 db 'Enter the number of the array ' len1 equ $-msg1 msg4 db 'The array after sorting is: ' len4 equ $-msg4 num times 35 db '' numLen equ $ - num quant db '0' arr times 512 dd 0 A times 20 db 0 counti dd 0 Numberscount dd 0 F db 0 ``` 1. Label `_ArrayIn`: Đây là một subroutine để đọc mảng từ đầu vào. Nó được gọi từ `_start` để đọc các phần tử của mảng từ người dùng. 2. Label `_selectionSort`: Đây là một subroutine để triển khai thuật toán sắp xếp chọn trên mảng. Nó được gọi từ `_start` để sắp xếp các phần tử của mảng. 3. Label `_ArrayOut`: Đây là một subroutine để in ra mảng đã được sắp xếp. Nó được gọi từ `_start` để in ra màn hình các phần tử của mảng. 4. Label `_convertNum`: Chuyển đổi số thành chuỗi. 5. Label `_convertString`: chuyển đổi chuỗi thành số ![Screenshot from 2024-01-23 08-16-41](https://hackmd.io/_uploads/S1hY3VpK6.png) ### Code Fibonacci ``` section .text global _start _start: mov eax, 0x4 mov ebx, 0x1 mov ecx, msg mov edx, msgLen int 0x80 mov eax, 0x3 mov ebx, 0x0 mov ecx, num1 mov edx, 0xe int 0x80 dec eax mov ecx, eax mov ebx, num1 call _convertString mov ecx, eax call _Fibo call _convertNum mov eax, 0x4 mov ebx, 0x1 mov ecx, msg2 mov edx, msg2len int 0x80 mov eax, 0x4 mov ebx, 0x1 mov ecx, num2 mov edx, ebp int 0x80 mov eax, 0x1 int 0x80 _Fibo: mov eax, 0x1 mov ebx, 0x0 xor esi, esi cmp ecx, 0x2 jg Fib ret Fib: mov esi, eax add eax, ebx mov ebx, esi loop Fib mov eax, ebx ret _convertNum: mov ecx, 0 running: xor edx, edx mov ebx, 10 div ebx add edx, 0x30 push edx inc ecx cmp eax, 0 jne running mov ebp, 0 LOOP: pop edx mov [num2 + ebp], edx inc ebp loop LOOP ret _convertString: xor edx, edx xor eax, eax xor esi, esi stringToNum: mov edx, 10 mul edx mov dl, [ebx + esi] sub edx, 0x30 add eax, edx inc esi loop stringToNum ret section .data msg db 'Nhap n: ' msgLen equ $ - msg msg2 db 'So Fibo la: ' msg2len equ $ - msg2 num1 times 100 db 0 num2 times 100 db '' len db 0 ``` * **Phần .data:** 1. msg là chuỗi "Nhap n: " để hiển thị thông báo nhập số n. 2. msgLen là kích thước của chuỗi msg. 3. msg2 là chuỗi "So Fibo la: " để hiển thị thông báo kết quả. 4. msg2len là kích thước của chuỗi msg2. 5. num1 là mảng 35 byte để lưu giá trị của số n nhập vào. 6. num2 là mảng 35 byte để lưu giá trị của số Fibonacci tính được. 7. len là biến 1 byte để lưu độ dài của số n nhập vào. * **Phần .text:** 1. Gọi hàm hệ thống để hiển thị thông báo "Nhap n: ": 2. Đọc số n từ người dùng: 3. Chuyển đổi số n từ dạng chuỗi sang dạng số nguyên: 4. Tính số Fibonacci thứ n: - Chương trình gọi hàm _Fibo để tính số Fibonacci thứ n. - Đầu tiên, chương trình đặt giá trị 0 vào thanh ghi ebx và giá trị 1 vào thanh ghi eax. - Bằng cách sử dụng vòng lặp loop, chương trình tính số Fibonacci bằng cách cộng giá trị của eax và ebx. 5. Chuyển đổi số Fibonacci từ dạng số nguyên sang dạng chuỗi: - Sau khi tính được số Fibonacci, chương trình gọi hàm _convertNum để chuyển đổi giá trị số Fibonacci từ dạng số nguyên sang dạng chuỗi và lưu vào mảng num2. ![Screenshot from 2024-01-24 03-18-36](https://hackmd.io/_uploads/ryuzdB0ta.png)