考虑一个nasm宏,用于在调用它时注入一些程序集,在这种情况下测试传递的参数是否等于42:
%macro special_handler_if_42 1
cmp 42, %1
jne %%skip
; some additional assembly to handle the %1 == 42 case
push %1
push 42
call some_func
%%skip:
%endmacro
如果 相等,我们会执行一些额外的操作,否则我们只需继续宏后面的代码。到目前为止,非常好。
现在我想以功能相同的方式编写宏,除了&#34;等于42&#34;情况,恰好是非常罕见的,被移动&#34;脱离&#34;,以便直通(无跳转)情况是默认情况,类似于(现在不以宏形式显示):< / p>
cmp 42, rax
je equals_42
jump_back:
; the rest of the code that follows the macro
ret
; somewhere outside the current function
equals_42:
push rax
push 42
call some_func
jmp jump_back
这在执行时更有效,也可能节省i-cache空间。我不确定如何编写具有非局部效果的宏。欢迎提示。
答案 0 :(得分:3)
如果您不介意将宏拆分为两个宏,一个执行测试,一个处理断言,那么您可以使用NASM's context stack。
我想象了一个assert_XXX
形式的宏系统,它们都非常相似并且执行特定的测试。
超出函数末尾的单个assertions_handler
将生成所需的任何处理程序。
由于此系统使用上下文堆栈,因此您应该能够多次使用它来执行不同的功能
基本上,每个assert_XXX
函数都会在堆栈上推送一个上下文,assertions_handler
将全部消耗它们。
assert_XXX
还将定义上下文本地宏argX
以将其参数传递给处理程序,因此无需对任何内容进行硬编码。
BITS 64
%macro assert_not_equal 2
;Create and push a new context (The name is optional but goodpractice)
%push assert_equal_ctx
%define %$arg1 %1
%define %$arg2 %2
cmp %1, %2
je %$handler
%$jump_back:
%endmacro
%macro assert_greater 2
%push assert_greater_ctx
%define %$arg1 %1
%define %$arg2 %2
cmp %1, %2
jbe %$handler
%$jump_back:
%endmacro
%macro assertions_handler 0
%rep 1000
%ifctx assert_equal_ctx
%$handler:
push %$arg1
push %$arg2
call somefunc
jmp %$jump_back
%pop assert_equal_ctx
%elifctx assert_greater_ctx
%$handler:
push %$arg1
push %$arg2
call somefunc2
%pop assert_greater_ctx
%else
%exitrep
%endif
%endrep
%endmacro
;
;TEST TEST TEST TEST TEST TEST TEST TEST
;
assert_not_equal rax, 5
nop
nop
nop
assert_greater rax, 8
nop
nop
nop
ret
assertions_handler
;
; Handler functions
;
somefunc:
ret
somefunc2:
ret
每个函数的最大断言数设置为1000,您可以将其增加到2 62 。