【问题标题】:How to efficiently conditional check multiple values in Assembly如何在Assembly中有效地条件检查多个值
【发布时间】:2018-07-01 07:21:55
【问题描述】:

想知道你是如何在汇编中完成这种事情的(nasm x86 或任何东西)。

if (a && (b || !c) && (d || e)) {
  something()
}

我才刚刚开始学习汇编,所以想看看您将如何处理这种“多变量”情况。你不能这样做(从here 获取jnz):

cmp eax, a && (b || !c) && (d || e)
jnz something

所以看来你必须以某种方式积累价值。

【问题讨论】:

  • 您可以手动使用Shunting-yard算法将这些表达式求解为一些rpn,可以很容易地写成指令。但请记住算术和逻辑and/or/xor/等之间的区别。 (见 Peter Cordes 的回答)。

标签: assembly


【解决方案1】:

源代码中的每条 asm 指令都映射到 1 条机器指令1。你的汇编器不是编译器。

一条指令能做什么完全取决于机器码能做什么; asm 源码语法可以表达一切。 x86 cmp instruction 只能读取 2 个输入操作数和写入标志,所以它当然不能基于 6 个输入设置标志。


有时您可以有效地将 C 源布尔表达式转换为一个 asm 分支,例如逻辑|| 可以使用按位或,根据结果非零设置 ZF。所以if(a || b || c) 可以编译成

    or eax, ebx
    or eax, ecx
    jnz  .not_if

      ; if body
.not_if:

但更典型的是,最好分别对条件的每个部分进行实际比较和分支。例如if (a && b) 可能编译为:

    test   eax,eax
    jz   .not_if
    test   ebx,ebx
    jz   .not_if

         ; if body    
.not_if:

您不能 test eax,ebx,因为例如,在 EAX=1 和 EBX=2 的情况下,按位与可以为 0。

另一种可以将内容合并到一个 cmp/jcc 中的情况是范围检查:double condition checking in assemblysub 将范围的一端带到0,然后是cmp / ja(无符号比较)。如果 sub 包装成一个大的无符号值,或者该值超出范围上限,则跳转。

更一般地说,看看编译器在编译 C 时做了什么。如果您不希望编译器能够打开 @987654338,那么将赋值给 volatile 变量是很方便的事情@ 进入无分支 CMOV 或其他东西。 有关查看编译器输出和构建有用的编译器输入的更多信息,请参阅How to remove "noise" from GCC/clang assembly output?。尤其是 Matt Godbolt 的 CppCon 演讲


实际上在整数寄存器中创建布尔值并将它们与运算/或运算一起在 MIPS 上工作(它没有 FLAGS 寄存器,因此您可以分支或比较到整数寄存器)。

或者在POWER / PowerPC上有多个条件代码字段,您可以比较到CR0,比较到CR1,然后使用条件寄存器指令组合条件。

如果您忘记标记 x86,或者您试图询问有关不同汇编语言的通用问题,请使用 IDK。


脚注 1:许多 RISC 架构都有“伪指令”,可以扩展为 2 或 3 条实际机器指令,例如 MIPS 上的 li $t0, 0x1234567 -> lui 设置 32 位常量的上半部分,以及ori $t0, $t0, 0x4567 设置低半部分。固定指令宽度架构无法像 x86 那样将任意 32 位常量放入一条指令中。

x86 不使用“伪指令”。它们已经足够复杂了。 :P

【讨论】:

    猜你喜欢
    • 2017-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-18
    • 1970-01-01
    相关资源
    最近更新 更多