การประกอบ - ขั้นตอน

โพรซีเดอร์หรือรูทีนย่อยมีความสำคัญมากในภาษาแอสเซมบลีเนื่องจากโปรแกรมภาษาแอสเซมบลีมักจะมีขนาดใหญ่ ขั้นตอนถูกระบุโดยชื่อ ตามชื่อนี้จะมีการอธิบายเนื้อหาของโพรซีเดอร์ซึ่งทำงานได้ดี สิ้นสุดขั้นตอนจะระบุโดยคำสั่งส่งคืน

ไวยากรณ์

ต่อไปนี้เป็นไวยากรณ์เพื่อกำหนดขั้นตอน -

proc_name:
   procedure body
   ...
   ret

โพรซีเดอร์ถูกเรียกใช้จากฟังก์ชันอื่นโดยใช้คำสั่ง CALL คำสั่ง CALL ควรมีชื่อของขั้นตอนที่เรียกว่าเป็นอาร์กิวเมนต์ดังที่แสดงด้านล่าง -

CALL proc_name

ขั้นตอนที่เรียกว่าจะส่งคืนการควบคุมไปยังขั้นตอนการเรียกโดยใช้คำสั่ง RET

ตัวอย่าง

ให้เราเขียนขั้นตอนง่ายๆที่ชื่อsumที่เพิ่มตัวแปรที่เก็บไว้ในทะเบียน ECX และ EDX และส่งกลับผลรวมในทะเบียน 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

เมื่อโค้ดด้านบนถูกคอมไพล์และเรียกใช้งานโค้ดจะได้ผลลัพธ์ดังนี้ -

The sum is:
9

โครงสร้างข้อมูลกองซ้อน

สแต็กคือโครงสร้างข้อมูลที่เหมือนอาร์เรย์ในหน่วยความจำซึ่งข้อมูลสามารถจัดเก็บและลบออกจากตำแหน่งที่เรียกว่า 'ด้านบน' ของสแต็ก ข้อมูลที่ต้องจัดเก็บจะถูก 'ผลัก' เข้าไปในสแต็กและข้อมูลที่จะดึงออกมาจะถูก 'ดึง' ออกจากสแต็ก Stack เป็นโครงสร้างข้อมูลแบบ LIFO กล่าวคือข้อมูลที่เก็บไว้ก่อนจะถูกดึงมาล่าสุด

ภาษาแอสเซมบลีมีคำสั่งสองคำสั่งสำหรับการดำเนินการสแต็ก: PUSH และ POP คำแนะนำเหล่านี้มีไวยากรณ์เช่น -

PUSH    operand
POP     address/register

พื้นที่หน่วยความจำที่สงวนไว้ในส่วนของสแต็กใช้สำหรับการนำสแตกไปใช้งาน รีจิสเตอร์ SS และ ESP (หรือ SP) ใช้สำหรับการนำสแตกไปใช้งาน ด้านบนสุดของสแต็กซึ่งชี้ไปยังรายการข้อมูลสุดท้ายที่แทรกลงในสแต็กจะถูกชี้ไปที่ทะเบียน SS: ESP โดยที่ทะเบียน SS ชี้ไปที่จุดเริ่มต้นของส่วนสแต็กและ SP (หรือ ESP) จะให้ค่าชดเชยเป็น ส่วนสแต็ก

การใช้งานสแต็กมีลักษณะดังต่อไปนี้ -

  • เท่านั้น words หรือ doublewords สามารถบันทึกลงในสแต็กไม่ใช่ไบต์

  • สแต็กเติบโตในทิศทางย้อนกลับกล่าวคือไปยังที่อยู่หน่วยความจำส่วนล่าง

  • ด้านบนของสแต็กชี้ไปที่รายการสุดท้ายที่แทรกในสแต็ก ชี้ไปที่ไบต์ล่างของคำสุดท้ายที่แทรก

ดังที่เราได้กล่าวถึงการจัดเก็บค่าของรีจิสเตอร์ในสแต็กก่อนนำไปใช้ สามารถทำได้ด้วยวิธีต่อไปนี้ -

; 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

ตัวอย่าง

โปรแกรมต่อไปนี้แสดงชุดอักขระ ASCII ทั้งหมด โปรแกรมหลักเรียกขั้นตอนที่ชื่อว่าdisplayซึ่งแสดงชุดอักขระ 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'

เมื่อโค้ดด้านบนถูกคอมไพล์และเรียกใช้งานโค้ดจะได้ผลลัพธ์ดังนี้ -

0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}
...
...