汇编中的 for + if

本文通过一个简单的目标介绍使用汇编语言实现循环和分支语句相结合进行编程的方法。

对于汇编初学者来说,在高级语言中信手拈来的循环与分支语句结合的形式可能会成为一个有些许困惑的障碍,本文将尝试以较为简明的方式来说明,以便初学者快速上手。

目标

目标等效 C 语言如下(注意并非等价):

int a = 0;
int b = 0;
for(int i = 0; i < 10; i++) {
	if(i < 5) {
		a += i;
	}
	else {
		b += i;
	}
}

x86 Assembly

在 x86 Assembly 中有内建指令 loop 来完成指定次数的循环。loop 将使用 eax 寄存器中的数值,将其作为循环次数,当 loop 被执行时,将跳转到 loop 后的标签,并将 eax 减去 1,如果 eax 为 0,则不再循环并继续其后的代码。

mov eax, 9
L1:
	<LOOP BODY>
	loop L1
;此代码将执行 10 次循环体内的代码

对于循环体内的分支语句,我们可以通过 jz/jnz/je/jne 等条件跳转语句结合标签完成。jz 与 je 效果相同,若 ZF 为 1 则跳转;jnz 与 jne 效果相同,若 ZF 为 0 则跳转。

对于其中一个分支,我们可以将其留到判断语句之后执行,对于另外一个分支,则跳转到其他位置。

对于上述我们的目标,在下面的示例中,第二个分支(i < 5 时)被保留在判断之后,第二个分支(i >= 5 时)跳转到 loop 之后。

方案一:在迭代过程中遇到关键特殊值转换到另一个循环(对我而言比较符合直觉)

mov al, 0 ;a
mov bl, 0 ;b
mov ecx, 9 ;i
L1:
	cmp ecx, 4
	jz L2
	add al, ecx
	loop L1
L2:
	add bl, ecx
	loop L2
E1:
	;Do something after loop

方案二:进行大小比较(按照 C 语言的思路)

这里需要用到 jc/jnc。jc 会在 CF 为 1 时跳转;jnc 会在 CF 为 0 时跳转。

mov al, 0 ;a
mov bl, 0 ;b
mov ecx, 9 ;i
L1:
	cmp ecx, 5
	jnc B1
	add al, ecx
Repeat:
	loop L1
B1:
	add bl, ecx
	jmp Repeat
E1:
	;Do something after loop

注意这里跳转到循环体外部语句后要往回跳转,否则会直接执行后面的代码而跳过循环。

ARM Assembly

ARM 中需要手动进行循环,实际上同理 x86 中也可以使用以下的方法。这里可以利用 ARM 提供的条件语句简化代码而无需进行过多的跳转。

mov r0, #0 @a
mov r1, #0 @b
mov r2, #0 @i
loop:
	cmp r2, #10
	bge E1
	cmp r2, #5
	addlt r0, r2
	cmp r2, #5
	addge r1, r2
	add r2, #1
	b loop
E1:
	@Do something after loop

留下评论

您的电子邮箱地址不会被公开。 必填项已用*标注