# DEADLINE 2: DUE DATE 29/1/2024 > Tìm hiểu về ngôn ngữ assembly, viết báo cáo chi tiết hết về những gì mà bản thân tìm hiểu được.(Ít nhất phải đủ để code được 2 chương trình bên dưới, thiếu có thể bổ sung tiếp trong task sau) Có thể tham khảo nguồn dưới đâu hoặc bất kì nguồn nào khác tìm được Tài liệu: https://www.tutorialspoint.com/assembly_programming/assembly_tutorial.pdf Code 2 chương trình sau: -Fibonacci -Selection Sort Vẽ graph mô tả code asm của 2 bài, comment giải thích những đoạn chính Deadline: 11:59 24/1/2024 ## 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)