NASM 中如何在函数结束时批量取消 %define 定义?
数据阿明
可以用 NASM 的 context stack 管理由一个宏定义的一批临时变量:在函数对应的源码区域开始处执行 %push,将变量定义为 %$var1 这样的上下文局部宏,再在源码区域结束处用一次 %pop 清理整个上下文。
这需要调整变量的定义和引用方式。普通的 %define var1 ... 不会在函数结束或执行 %pop 时自动消失。
为什么原来的 clear_vars 不生效?
NASM 在调用多行宏之前,会先展开调用行中的单行宏。例如:
%define var1 10
clear_vars var1
传给 clear_vars 的参数已经变成了 10,宏体里的 %undef %1 无法再取得原始名称 var1。即使增加 %rep 或调整 %rotate,也无法恢复原始名称。这个顺序可参见 NASM 预处理展开规则。
加引号可以保留字符串内容,但 %undef 需要宏标识符。直接传入 "var1" 不会自动将字符串转换为标识符。
用上下文局部宏统一清理
如果可以修改负责定义变量的宏,可以这样组织:
bits 64
section .text
%macro define_vars 0
%define %$var1 10
%define %$var2 20
%define %$var3 30
%endmacro
%push function_vars
example_function:
define_vars
mov eax, %$var1
add eax, %$var2
add eax, %$var3
ret
%pop
%push 创建上下文,define_vars 在当前上下文中定义三个单行宏,%pop 则销毁这个上下文及其局部定义。这样就不必维护清理名称列表或逐项编写 %undef。NASM context stack 文档说明了 %push、%pop 和 %$ 的用法。
使用时需要注意什么?
- 定义和引用都要使用
%$var1。只在普通%define var1 ...外面加%push、%pop,不会使它变成局部定义。 %push和%pop必须配对。存在嵌套上下文时,%$var1指向栈顶上下文,访问上一层需要使用%$$var1。- 这是预处理阶段的源码范围管理。
ret不会触发清理,清理发生在预处理器读到%pop时。 - 如果必须保留现有的全局宏名称,直接写出相应的
%undef仍是明确可控的方案。不要用不带参数的%clear代替局部清理,它会清除其他宏定义,包括 NASM 的预定义宏。
备注:内容仅供参考。
