汇编语言 宏

编写宏是确保用汇编语言进行模块化编程的另一种方法。

  • 宏是一系列指令,由名称指定,可以在程序中的任何位置使用。

  • NASM 中,宏是用 %macro%endmacro 指令定义的。

  • 宏以 %macro 指令开始,以 %endmacro 指令结束。

宏的语法如下:

  1. %macro macro_name number_of_params
  2. <macro body>
  3. %endmacro

其中,number_of_params 指定数字参数,macro_name 指定宏的名称。

通过使用宏名称和必要的参数来调用宏。当您需要在程序中多次使用某个指令序列时,可以将这些指令放在宏中并使用它,而不是一直编写指令。

例如,程序的一个常见需求是在屏幕上写入字符串。要显示字符串,您需要以下指令序列:

  1. movedx,len ;message length
  2. movecx,msg ;message to write
  3. movebx,1 ;file descriptor (stdout)
  4. moveax,4 ;system call number (sys_write)
  5. int0x80 ;call kernel

在上面显示字符串的实例中,INT 80H 函数调用使用了寄存器 EAXEBXECXEDX。因此,每次需要在屏幕上显示时,都需要将这些寄存器保存在堆栈上,调用 INT 80H,然后从堆栈中恢复寄存器的原始值。因此,编写两个宏来保存和恢复数据可能很有用。

我们注意到,一些指令,如 IMULIDIVINT 等,需要将一些信息存储在某些特定寄存器中,甚至在某些特定的寄存器中返回值。如果程序已经使用这些寄存器来保存重要数据,那么这些寄存器中的现有数据应该保存在堆栈中,并在指令执行后恢复。


实例

下面的实例显示了如何定义和使用宏:

  1. ; 具有两个参数的宏
  2. ; 实现写入系统调用
  3. %macro write_string 2
  4. mov eax, 4
  5. mov ebx, 1
  6. mov ecx, %1
  7. mov edx, %2
  8. int 80h
  9. %endmacro
  10. section .text
  11. global _start ;必须声明才能使用 gcc
  12. _start: ;告诉链接器入口点
  13. write_string msg1, len1
  14. write_string msg2, len2
  15. write_string msg3, len3
  16. mov eax,1 ;系统调用号 (sys_exit)
  17. int 0x80 ;调用内核
  18. section .data
  19. msg1 db 'Hello, programmers!',0xA,0xD
  20. len1 equ $ - msg1
  21. msg2 db 'Welcome to cankaoshouce.com,', 0xA,0xD
  22. len2 equ $- msg2
  23. msg3 db 'Learn assembly programming! '
  24. len3 equ $- msg3

结果如下:

  1. Hello, programmers!
  2. Welcome cankaoshouce.com,
  3. Learn assembly programming!