源代码中的每条 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 assembly。 sub 将范围的一端带到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