想知道如何在组装中完成这种事情(nasm x86或其他)。
if (a && (b || !c) && (d || e)) {
something()
}
我才刚刚开始学习汇编,所以想看看您将如何处理这种“多变量”情况。您无法做(从here获得jnz
)
cmp eax, a && (b || !c) && (d || e)
jnz something
因此,您似乎必须以某种方式累积值。
答案 0 :(得分:2)
您源代码中的每条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
,因为例如按位AND可以在EAX = 1和EBX = 2时为0。
另一种可以将内容组合为一个cmp / jcc的方法是范围检查:double condition checking in assembly。 sub
将范围的一端带到0
,然后是cmp
/ ja
(无符号比较)。如果sub
包装为一个较大的无符号值,或者该值超出上限,则跳转。
更一般地,请看一下编译C时编译器的工作。如果您不希望编译器能够将volatile
变量赋值到if()
主体中,则很方便。将if
变成无分支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