Assembly - Thủ tục
Các thủ tục hoặc chương trình con rất quan trọng trong hợp ngữ, vì các chương trình hợp ngữ có xu hướng có kích thước lớn. Các thủ tục được xác định bằng một cái tên. Theo sau tên này, phần thân của thủ tục được mô tả thực hiện một công việc được xác định rõ ràng. Kết thúc thủ tục được chỉ ra bởi một câu lệnh trả về.
Cú pháp
Sau đây là cú pháp để xác định một thủ tục:
proc_name:
procedure body
...
ret
Thủ tục được gọi từ một hàm khác bằng cách sử dụng lệnh CALL. Lệnh CALL phải có tên của thủ tục được gọi làm đối số như hình dưới đây:
CALL proc_name
Thủ tục được gọi trả lại điều khiển cho thủ tục gọi bằng cách sử dụng lệnh RET.
Thí dụ
Hãy để chúng tôi viết một thủ tục rất đơn giản có tên là sum để thêm các biến được lưu trữ trong thanh ghi ECX và EDX và trả về tổng trong thanh ghi EAX -
section .text
global _start ;must be declared for using gcc
_start: ;tell linker entry point
mov ecx,'4'
sub ecx, '0'
mov edx, '5'
sub edx, '0'
call sum ;call sum procedure
mov [res], eax
mov ecx, msg
mov edx, len
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
mov ecx, res
mov edx, 1
mov ebx, 1 ;file descriptor (stdout)
mov eax, 4 ;system call number (sys_write)
int 0x80 ;call kernel
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
sum:
mov eax, ecx
add eax, edx
add eax, '0'
ret
section .data
msg db "The sum is:", 0xA,0xD
len equ $- msg
segment .bss
res resb 1
Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:
The sum is:
9
Cấu trúc dữ liệu ngăn xếp
Ngăn xếp là một cấu trúc dữ liệu giống như mảng trong bộ nhớ trong đó dữ liệu có thể được lưu trữ và xóa khỏi vị trí được gọi là 'đỉnh' của ngăn xếp. Dữ liệu cần lưu trữ được 'đẩy' vào ngăn xếp và dữ liệu cần truy xuất được 'bật ra' từ ngăn xếp. Stack là một cấu trúc dữ liệu LIFO, tức là, dữ liệu được lưu trữ trước sẽ được truy xuất sau cùng.
Hợp ngữ cung cấp hai hướng dẫn cho các hoạt động ngăn xếp: PUSH và POP. Các hướng dẫn này có các cú pháp như -
PUSH operand
POP address/register
Không gian bộ nhớ dành riêng trong phân đoạn ngăn xếp được sử dụng để thực hiện ngăn xếp. Các thanh ghi SS và ESP (hoặc SP) được sử dụng để triển khai ngăn xếp. Phần trên cùng của ngăn xếp, trỏ đến mục dữ liệu cuối cùng được chèn vào ngăn xếp được chỉ đến bởi thanh ghi SS: ESP, trong đó thanh ghi SS trỏ đến phần đầu của phân đoạn ngăn xếp và SP (hoặc ESP) đưa ra giá trị bù vào phân đoạn ngăn xếp.
Việc triển khai ngăn xếp có các đặc điểm sau:
Chỉ có words hoặc là doublewords có thể được lưu vào ngăn xếp, không phải một byte.
Ngăn xếp phát triển theo hướng ngược lại, tức là về phía địa chỉ bộ nhớ thấp hơn
Đỉnh của ngăn xếp trỏ đến mục cuối cùng được chèn trong ngăn xếp; nó trỏ đến byte thấp hơn của từ cuối cùng được chèn vào.
Như chúng ta đã thảo luận về việc lưu trữ các giá trị của các thanh ghi trong ngăn xếp trước khi sử dụng chúng để sử dụng; nó có thể được thực hiện theo cách sau -
; Save the AX and BX registers in the stack
PUSH AX
PUSH BX
; Use the registers for other purpose
MOV AX, VALUE1
MOV BX, VALUE2
...
MOV VALUE1, AX
MOV VALUE2, BX
; Restore the original values
POP BX
POP AX
Thí dụ
Chương trình sau đây hiển thị toàn bộ bộ ký tự ASCII. Chương trình chính gọi một thủ tục có tên là display , nó sẽ hiển thị bộ ký tự ASCII.
section .text
global _start ;must be declared for using gcc
_start: ;tell linker entry point
call display
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
display:
mov ecx, 256
next:
push ecx
mov eax, 4
mov ebx, 1
mov ecx, achar
mov edx, 1
int 80h
pop ecx
mov dx, [achar]
cmp byte [achar], 0dh
inc byte [achar]
loop next
ret
section .data
achar db '0'
Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:
0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}
...
...