【发布时间】:2017-01-26 00:25:28
【问题描述】:
我有时会使用这种模式来迭代一些东西的数组:
mov [rsp+.r12], r12 ; Choose a register that calls inside the loop won't modify
mov r12, -1
.i:
inc r12
cmp r12, [rbp-.array_size]
je .end_i
; ... program logic ...
jmp .i
.end_i:
mov r12, [rsp+.r12]
我知道测试相等就足够了,但不应该“安全地”测试“大于或等于”(防止不会发生的情况)。
在这种情况下应该使用 je 还是 jge?
我在询问可以减少引入错误的可能性的具体技巧。
【问题讨论】:
-
我一直有点喜欢测试一个范围而不是仅仅测试相等性的想法,以防万一发生意外翻转或其他情况。但在 x86 asm 中,请记住
cmp/jge不能在 Core2 上进行宏融合(在 32 位模式下),但cmp/je可以。我认为这会更相关,直到我检查并发现只有 Core2 而不是 Nehalem 无法融合它,因为宏融合在 Core2 上的 64 位模式下根本不起作用。 (后来的微架构没有这个限制,可以宏融合越来越多的组合。) -
为什么你要显示一些奇怪的 r12 溢出/重新加载以释放它用作临时计数器?这完全无关紧要(而且看起来不像有效的代码)。肯定有一些寄存器已经死了,你可以不用保存就可以使用。
-
@Peter,应该怎么写?我认为 r12 是一个不错的选择,因为像 printf 这样的循环内的函数调用不会修改调用保存的 r12 寄存器,而且我们不需要手动保存和恢复调用周围的计数器。如有错误请指正。
-
哦,那是什么意思?当然,r12 是一个不错的选择,但如果您不需要 64 位计数器(无 REX 前缀),ebx 或 ebp 可能是更好的选择。最主要的是,在堆栈框架中有一个名为
.r12的命名点很奇怪。通常,如果您要命名某物,则使用具有语义含义的标签。因此,如果r12之前持有some_value,您将存储它。在循环之后,也许将 r12 用于其他用途。 -
不,这与我所说的相反。更新了我的答案,感谢您让我知道您迷失了短的 cmets,因此我可以扩展它,而不是浪费我们的时间 :)
标签: assembly x86 idioms loop-counter