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{|}
...
...