If else OR statement in Assembly?

If else OR statement in Assembly?

对在 Assembly 中使用分支命令感到困惑,主要是 BNEBEQ。 所以我要为伪代码写一个汇编代码:

X = 5, Y = 10, Z = 15

if X != 4 && Y == 10 || Z = 20 

A = X + Y - 2

else   R = Z - 5 + X

我在 Keil uVision5 中为 ARM Cortex M0 Plus(不知道是否需要此信息)在其低位寄存器中编码,对于这个特定的板来说是 R0-R7 .

我知道如何编写 if else 语句本身,但我主要想问的是如何处理代码的 OR 部分。很明显 X!=4 为真, Y==10 为真,然后检查 Z = 20 是否为假,所以我会先检查 X!=4 ,使用 [=12 跳转=] 标签来检查 Y,使用 BEQ 来检查 Z,这是错误的,但由于等式已经正确,我会跳到 BNE endif 语句 A=X+Y-2?

然后在前面没有标签的情况下,如果第一个 BNE 标签不知何故是错误的,我会编写 else 语句供汇编器使用..?

A EQU 0x2000000
R EQU 0x2000004
X EQU 0x2000008
Y EQU 0x200000C
Z EQU 0x2000010

 LDR R7, =X
 LDR R0, [R7]
 ADD R0, #5  ; X = 5 in R0
 CMP R0, #4  ; Compare X != 4
 BNE jumpToY

jumpToY
 LDR R7, =Y
 LDR R1, [R7]   ; Y = 10 in R1
 CMP R1, #10    ; Compare Y == 10
 BEQ jumpToZ

jumpToZ
 etc...

想想你是如何评估头脑中的逻辑条件的。如果你想要A或B而你得到了A那么你就不需要考虑B。如果你想要A和B而你没有A那么计算B就没有意义了。

有些纯粹主义者认为您应该评估这两个条件,然后对结果进行逻辑比较: 计算一个 计算 B AND/OR结果一起

幸运的是,工程方法胜出:

对于 A 和 B(假设 BEQ 是 "true"):

Calculate A
BNE fail
Calculate B
BNE fail
success:
   ...
   RET/JMP somewhere  ; Don't drop through into fail
fail:
   ...

对于 A OR B(同样,假设 BEQ 是 "true"):

Calculate A
BEQ success
Calculate B
BNE fail
success:
   ...
   RET/JMP somewhere  ; Don't drop through into fail
fail:
   ...
A EQU 0x2000000
R EQU 0x2000004
X EQU 0x2000008
Y EQU 0x200000C
Z EQU 0x2000010

在这里,您可以看到防止额外跳转的条件指令。我们首先检查 And 的前 2 种情况,然后默认为 Or 情况。另请注意,我们必须跳到 else 代码之外以防止两者都执行。另请注意,我们进入了 else 案例,也是为了防止额外的跳转。

 ; These could be loaded with a singl LDM instruction instead.
 LDR R7, =X
 LDR R0, [R7]
 LDR R7, =Y
 LDR R0, [R7]
 LDR R7, =Z
 LDR R2, [R7]

 CMP R0,#5
 CMPEQ R1,#10
 BEQ FirstCase

 CMP R2,#5
 BEQ FirstCase
 ;... Fall Through

ElseCase:
   ...
   j RestOfCode
FirstCase:
   ...

RestOfCode:

请注意我是盲目编码的,这对任何语言来说都是危险的事情,ASM 更是如此。它应该演示如何处理您想要查看的 And/Or 个案例。

您还可以将代码放入 C 编译器并检查输出,因为它也会显示工作代码。

对于使用由一条指令设置的标志,然后是条件指令分支或跳转的处理器,asm 通常如何工作。在 branch/jump 条件之前的某个时刻,您设置了标志,例如比较在这种情况下会这样做。条件分支指令的工作方式是,如果条件为真,它会分支到该地址,这与 goto 在 C 中的工作方式完全相同。如果条件不为真,则不会。

if(x!=4) goto label0;
label2:
if(z==20) goto label1;
R = Z - 5 + X;
goto done;
label0:
if(y!=10) goto label2:
...
done:

所以从顶部开始,如果 x 不是 4,那么我们分支到 label0 并执行那里的操作,如果它是 4,那么我们继续执行 if z==20 然后重新关注 z==20 如果 z==20 则转到 label1 否则继续进行计算。

在汇编中类似于

ldr r0,=X
ldr r0,[r0]
cmp r0,#4
bne label0

ldr r2,=Z
ldr r2,[r2]
cmp r2,#20
beq label1

sub r2,#5
add r0,r2
ldr r2,=X
str r0,[r2]
b done

label0:
ldr r1,=Y
ldr r1,[r1]
cmp r1,#10
bne label2:

...

done:

我没有特别的原因在分支后面加了空格。在第一个 bne label0 上,如果确实发生了,那么我们接下来执行标签 0 之后的内容,如果设置了相等标志,则加载 y 地址,然后我们不分支,我们继续执行 Z 地址的加载。

就覆盖逻辑路径而言,可能会使你自己成为一个真理 table X!=4 Y==10 和 Z==20 中的每一个都是真或假,结果要么是 R=或 A=,然后您可以在最坏的情况下从字面上执行真相 table(8 组比较)或缩小范围……并继续优化直到您满意为止。

最终你希望 A= 代码在某个地方有一个分支到函数的末尾,而 R= 代码在某个地方也有一个分支到函数的末尾,然后根据你的真相 table 和实现您创建路径以获取 A= 或 R= 代码,但您必须点击其中一个。

编辑:

注意你的前三行看起来不对

 LDR R7, =X
 LDR R0, [R7]
 ADD R0, #5  ; X = 5 in R0

这不是将 X 设置为 5,因为您的评论暗示它会将 5 添加到 X,因此无论 X 是什么,您都添加了 5。

如果你想实现这个 X = 5, Y = 10, Z = 15

ldr r1,=X
mov r0,#5
str r0,[r1]
ldr r1,=Y
mov r0,#10
str r0,[r1]
ldr r1,=Z
mov r0,#15
str r0,[r1]

然后获取 x 并进行比较

LDR R7, =X
LDR R0, [R7]
CMP R0, #4  ; Compare X != 4