汇编语言 宏
编写宏是确保用汇编语言进行模块化编程的另一种方法。
宏是一系列指令,由名称指定,可以在程序中的任何位置使用。
在 NASM 中,宏是用
%macro
和%endmacro
指令定义的。宏以
%macro
指令开始,以%endmacro
指令结束。
宏的语法如下:
%macro macro_name number_of_params
<macro body>
%endmacro
其中,number_of_params 指定数字参数,macro_name 指定宏的名称。
通过使用宏名称和必要的参数来调用宏。当您需要在程序中多次使用某个指令序列时,可以将这些指令放在宏中并使用它,而不是一直编写指令。
例如,程序的一个常见需求是在屏幕上写入字符串。要显示字符串,您需要以下指令序列:
movedx,len ;message length
movecx,msg ;message to write
movebx,1 ;file descriptor (stdout)
moveax,4 ;system call number (sys_write)
int0x80 ;call kernel
在上面显示字符串的实例中,INT 80H
函数调用使用了寄存器 EAX、EBX、ECX 和 EDX。因此,每次需要在屏幕上显示时,都需要将这些寄存器保存在堆栈上,调用 INT 80H
,然后从堆栈中恢复寄存器的原始值。因此,编写两个宏来保存和恢复数据可能很有用。
我们注意到,一些指令,如 IMUL、IDIV、INT 等,需要将一些信息存储在某些特定寄存器中,甚至在某些特定的寄存器中返回值。如果程序已经使用这些寄存器来保存重要数据,那么这些寄存器中的现有数据应该保存在堆栈中,并在指令执行后恢复。
实例
下面的实例显示了如何定义和使用宏:
; 具有两个参数的宏
; 实现写入系统调用
%macro write_string 2
mov eax, 4
mov ebx, 1
mov ecx, %1
mov edx, %2
int 80h
%endmacro
section .text
global _start ;必须声明才能使用 gcc
_start: ;告诉链接器入口点
write_string msg1, len1
write_string msg2, len2
write_string msg3, len3
mov eax,1 ;系统调用号 (sys_exit)
int 0x80 ;调用内核
section .data
msg1 db 'Hello, programmers!',0xA,0xD
len1 equ $ - msg1
msg2 db 'Welcome to cankaoshouce.com,', 0xA,0xD
len2 equ $- msg2
msg3 db 'Learn assembly programming! '
len3 equ $- msg3
结果如下:
Hello, programmers!
Welcome cankaoshouce.com,
Learn assembly programming!