x86 程序集中宏和 Procedures/methods 之间的区别
Difference betwee Macros and Procedures/methods in x86 Assembly
谁能解释一下 x86 汇编中宏和 procedures/methods 的区别?我完全迷路了。谢谢。
宏在最终编译步骤之前内联扩展,而过程将在最终可执行文件中通过 'call' 和 'ret' 操作实现。
基本上,宏是语法糖,可以让您的源代码更漂亮或让您更快地输入它。要使用下面 link 中的宏示例(逐字复制):
; A macro with two parameters
; Implements the write system call
%macro write_string 2
mov eax, 4
mov ebx, 1
mov ecx, %1
mov edx, %2
int 80h
%endmacro
section .text
global _start ;must be declared for using gcc
_start: ;tell linker entry point
write_string msg1, len1
write_string msg2, len2
write_string msg3, len3
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
msg1 db 'Hello, programmers!',0xA,0xD
len1 equ $ - msg1
msg2 db 'Welcome to the world of,', 0xA,0xD
len2 equ $- msg2
msg3 db 'Linux assembly programming! '
len3 equ $- msg3
这相当于:
section .text
global _start ;must be declared for using gcc
_start: ;tell linker entry point
mov eax, 4
mov ebx, 1
mov ecx, msg1
mov edx, len1
int 80h
mov eax, 4
mov ebx, 1
mov ecx, msg2
mov edx, len2
int 80h
mov eax, 4
mov ebx, 1
mov ecx, msg3
mov edx, len3
int 80h
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
msg1 db 'Hello, programmers!',0xA,0xD
len1 equ $ - msg1
msg2 db 'Welcome to the world of,', 0xA,0xD
len2 equ $- msg2
msg3 db 'Linux assembly programming! '
len3 equ $- msg3
可以看到前面使用宏的代码更加简洁易读。第二种形式本质上是最终编译的形式,在编译器扩展对宏的每个引用之后。
过程不会以这种方式重复,它们被编译一次,'call' 操作码用于进入过程,'ret' 操作码离开它。
将重要的函数作为过程来实现可能会产生更小的可执行文件,因为不会为每次调用复制代码。但是,使用过程意味着您必须通过寄存器处理传递任何必需的参数,并且 'call' 和 'ret' 本身具有非零执行时间。因此,如果函数足够大并且在代码中的足够多的地方被调用,它可以成为大小与性能的权衡。
https://www.tutorialspoint.com/assembly_programming/assembly_macros.htm
https://www.tutorialspoint.com/assembly_programming/assembly_procedures.htm
谁能解释一下 x86 汇编中宏和 procedures/methods 的区别?我完全迷路了。谢谢。
宏在最终编译步骤之前内联扩展,而过程将在最终可执行文件中通过 'call' 和 'ret' 操作实现。
基本上,宏是语法糖,可以让您的源代码更漂亮或让您更快地输入它。要使用下面 link 中的宏示例(逐字复制):
; A macro with two parameters
; Implements the write system call
%macro write_string 2
mov eax, 4
mov ebx, 1
mov ecx, %1
mov edx, %2
int 80h
%endmacro
section .text
global _start ;must be declared for using gcc
_start: ;tell linker entry point
write_string msg1, len1
write_string msg2, len2
write_string msg3, len3
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
msg1 db 'Hello, programmers!',0xA,0xD
len1 equ $ - msg1
msg2 db 'Welcome to the world of,', 0xA,0xD
len2 equ $- msg2
msg3 db 'Linux assembly programming! '
len3 equ $- msg3
这相当于:
section .text
global _start ;must be declared for using gcc
_start: ;tell linker entry point
mov eax, 4
mov ebx, 1
mov ecx, msg1
mov edx, len1
int 80h
mov eax, 4
mov ebx, 1
mov ecx, msg2
mov edx, len2
int 80h
mov eax, 4
mov ebx, 1
mov ecx, msg3
mov edx, len3
int 80h
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
msg1 db 'Hello, programmers!',0xA,0xD
len1 equ $ - msg1
msg2 db 'Welcome to the world of,', 0xA,0xD
len2 equ $- msg2
msg3 db 'Linux assembly programming! '
len3 equ $- msg3
可以看到前面使用宏的代码更加简洁易读。第二种形式本质上是最终编译的形式,在编译器扩展对宏的每个引用之后。
过程不会以这种方式重复,它们被编译一次,'call' 操作码用于进入过程,'ret' 操作码离开它。
将重要的函数作为过程来实现可能会产生更小的可执行文件,因为不会为每次调用复制代码。但是,使用过程意味着您必须通过寄存器处理传递任何必需的参数,并且 'call' 和 'ret' 本身具有非零执行时间。因此,如果函数足够大并且在代码中的足够多的地方被调用,它可以成为大小与性能的权衡。
https://www.tutorialspoint.com/assembly_programming/assembly_macros.htm
https://www.tutorialspoint.com/assembly_programming/assembly_procedures.htm