【发布时间】:2018-05-25 03:02:24
【问题描述】:
考虑一个 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
在它是相等的情况下,我们执行一些额外的操作,否则我们就继续执行宏后面的代码。到目前为止,一切顺利。
现在我想以一种功能相同的方式编写宏,除了碰巧非常罕见的“等于 42”的情况被移出“不符合规定”,因此跌落(没有跳转) case 是默认的,类似于(现在未以宏形式显示):
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 空间。我不确定如何编写具有这样的非本地效果的宏。欢迎提出想法。
【问题讨论】:
-
链接器部分?但是,对于内联部分,这意味着短函数底部的 6 字节
jcc rel32而不是 2 字节jcc rel8。外线部分可能必须非常罕见才能比函数的底部更好。 (通常在同一页面/TLB 条目中)。但也许更好地打包使用它的其他函数意味着在您的其余代码中更多的 TLB 和 I-cache 命中。 -
是的,我考虑过说
.text.unlikely。在我的用例中,不太可能的情况是“从不”或多或少地使用(它表示断言失败并终止程序)。所以这种情况下的性能权重为零(但jcc的 2 个额外字节可能也会损害正常情况)。 -
你(作为断言案例)难道不能做
cmove eax,[42](可能[ss:42]有不同的故障代码),并处理抛出异常的失败吗? (我从未编写过异常处理程序,但我想有一种方法可以找出哪个地址失败,所以你可以在那里捕捉“42”,eax是 eax .. 也许你可以捕捉到指令代码,应该是足以在 90% 的情况下将其与真正的失败区分开来)......哦,这是 8B 长的操作码...... :-o -
@Ped7g:
cmov无条件加载内存源操作数。您不能使用它来获得其他微指令的谓词执行;它只是一个简单的 ALU uop,需要在执行之前准备好所有 3 个输入。 (标志 + 2 个整数)。如果您只是想出错,您可以在文件末尾使用一次org 0xdeadbeef/bad_condition:,然后在宏中使用jcc。 (或者可以确保它可以通过 64 位代码中的 rel32 访问。) -
NASM 支持上下文和上下文标签。我有一个原型,它使用
assert_not_equal宏在测试站点使用,assertions_handler在函数之后使用。支持多个assert_xxx宏。但是我仍在研究如何将assert_xxx宏参数传递给assertions_handler。和现在一样,我对它们进行了硬编码
标签: performance assembly optimization x86 nasm