FASM
FASM 通过 FASM 本身附带的特制宏来支持局部变量。
include 'win32ax.inc'
.code
start:
mov ax, 1
call foo
proc foo
;Local variables
locals
var1 dd ?
var2 dw ?
endl
;Use them as expected
mov eax, [var1]
lea ebx, [var2]
ret
endp
即编译1成
:00401000 66B80100 mov ax, 0001
:00401004 E800000000 call 00401009
:00401009 55 push ebp
:0040100A 89E5 mov ebp, esp
:0040100C 83EC08 sub esp, 00000008
:0040100F 8B45F8 mov eax, dword ptr [ebp-08]
:00401012 8D5DFC lea ebx, dword ptr [ebp-04]
:00401015 C9 leave
:00401016 C3 ret
NASM
NASM 也支持使用 %local 指令的局部变量。
引用手册:
silly_swap:
%push mycontext ; save the current context
%stacksize small ; tell NASM to use bp
%assign %$localsize 0 ; see text for explanation
%local old_ax:word, old_dx:word
enter %$localsize,0 ; see text for explanation
mov [old_ax],ax ; swap ax & bx
mov [old_dx],dx ; and swap dx & cx
mov ax,bx
mov dx,cx
mov bx,[old_ax]
mov cx,[old_dx]
leave ; restore old bp
ret ;
%pop ; restore original context
%$localsize 变量由 %local 指令在内部使用,并且必须在当前上下文中定义,然后才能使用 %local 指令。
其他草率的方法
可以
%define SUPER_VAR ebp-4
%define MEGA_VAR ebp-8
mov DWORD [SUPER_VAR], 0xf
mov DWORD [MEGA_VAR], 0xff
但是,这隐藏了变量在堆栈中并假定正确设置的帧指针的事实。
稍微好一点的方法:
%define SUPER_VAR 4
%define MEGA_VAR 8
mov DWORD [ebp-SUPER_VAR], 0xf
mov DWORD [ebp-MEGA_VAR], 0xff
汇编程序员方式
真正的汇编程序员使用 cmets[citation needed] 来说明他们代码的意图。
并且只在vi 中编写代码。还是emacs?
mov DWORD [ebp-4], 0xf ;SUPER_VAR
mov DWORD [ebp-8], 0xff ;MEGA_VAR
汇编语言的主要优势在于其简单的语法和完整的信息方法(没有什么是隐藏的,程序员控制着一切)。
虽然使用高级宏没有任何问题2,但混合使用高级和低级方法会导致源文件更难被专家解析。
此外,从本体论的角度来看,这毫无意义:如果您想使用高级功能,那么像 C 这样的语言更适合,并且必须重新考虑汇编的使用。相反,如果你想学习如何进行低级编程,那么这样的宏是学习过程的障碍。
最后,宏不是魔法。虽然非常灵活,但程序员迟早会遇到极限。
例如,我没有深入研究 FASM 和 NASM 对 aligned 局部变量的支持。
1 现在这不再是汇编了...
2 高级宏让您可以轻松地重构代码,这一点非常重要。不过,人们应该暂停片刻,质疑自己在预期/需要重要重构时使用汇编的选择。