使用汇编语言实现IF语句


IF 结构包含一个布尔表达式,其后有两个语句列表:一个是当表达式为真时执行,另一个是当表达式为假时执行:

if( boolean-expression )
    statement-list-1
else
    statement-list-2

结构中的 else 部分是可选的。在汇编语言中,则是用多个步骤来实现这种结构的。首先,对布尔表达式求值,这样一来某个 CPU 状态标志位会受到影响。然后,根据相关 CPU 状态标志位的值,构建一系列跳转把控制传递给两个语句列表。

【示例 1】下面的 C++ 代码中,如果 op1 等于 op2,则执行两条赋值语句:
if( op1 = op2 )
{
    X = 1;
    Y = 2;
}
在汇编语言中,这种 IF 语句转换为条件跳转和 CMP 指令。由于 op1 和 op2 都是内存操作数(变量),因此,在执行 CMP 之前,要将其中的一个操作数送入寄存器。

下面实现 IF 语句的程序是高效的,当逻辑表达式为真时,它允许代码“通过”直达两条期望被执行的 MOV 指令:
        mov eax, op1
        cmp eax,op2                  ; op1 == op2?
        jne L1                       ; 否:跳过后续指令
        mov X, 1                     ; 是:X, Y 赋值
        mov Y, 2
L1:
如果用 JE 来实现 == 运算符,生成的代码就没有那么紧凑了(6 条指令,而非 5 条指令):
        mov    eax, op1
        cmp    eax,op2              ; op1 == op2?
        je    L1                    ; 是:跳转到 L1
        jmp    L2                   ; 否:跳过赋值语句
LI:    mov X, 1                    ; X, Y 赋值
        mov    Y, 2
L2 :
从上面的例子可以看出,相同的条件结构在汇编语言中有多种实现方法。上面给出 的编译代码示例只代表一种假想的编译器可能产生的结果。

【示例 2】NTFS 文件存储系统中,磁盘簇的大小取决于磁盘卷的总容量。如下面的伪代码所示,如果卷大小(用变量 terrabytes 存放)不超过 16TB,则簇大小设置为 4096。否则, 簇大小设置为 8192:

clusterSize = 8192;
if terrabytes < 16
    clusterSize = 4096;

用汇编语言实现该伪代码:
        mov clusterSize, 8192                ;假设较大的磁盘簇
        cmp terrabytes, 16                   ;小于 16TB?
        jae next
        mov clusterSize, 4096                ;切换到较小的磁盘簇
next:
【示例 3】下面的伪代码有两个分支:

if op1 > op2
    call Routine1
else
    call Routine2
end if

用汇编语言翻译这段伪代码,设 op1 和 op2 是有符号双字变量。对这两个变量比较时,其中一个必须送入寄存器:
        mov eax, op1                    ; opl送入寄存器
        cmp    eax, op2                 ; opl > op2?
        jg    A1                        ; 是:调用 Routine1
        call    Routine2                ; 否:调用 Routine2
        jmp    A2    ;退出工F语句
A1:     call Routine1
A2:

白盒测试

复杂条件语句可能有多个执行路径,这使得它们难以进行调试检查(查看代码)。程序员经常使用的技术称为白盒测试,用来验证子程序的输入和相应的输出。

白盒测试需要源代码,并对输入变量进行不同的赋值。对每个输入组合,要手动跟踪源代码,验证其执行路径和子程序产生的输出。下面,通过嵌套 IF 语句的汇编程序来看看这个测试过程:
if op1 == op2
    if X > Y
        call Routine1
    else
        call Routine2
    end if
else
    call Routine3
end if
下面是可能的汇编语言翻译,加上了参考行号。程序改变了初始条件(op1 == op2),并立即跳转到 ELSE 部分。剩下要翻译的内容是内层 IF-ELSE 语句:
        mov    eax, op1
        cmp eax, op2                             ;op1 == op2?
        jne    L2                                ;否:调用 Routine3

; 处理内层 IF-ELSE 语句。
        mov    eax, X
        cmp    eax, Y                             ; X > Y?
        jg    L1                                  ; 是:调用 Routine1
        call    Routine2                          ; 否:调用 Routine2
        jmp    L3                                 ; 退出
L1:     call Routine1                             ; 调用 Routine1
        jmp    L3                                 ; 退出
L2:     call    Routine3
L3:
下表给出了示例代码的白盒测试结果。前四列对 op1、op2、X 和 Y 进行测试赋值。第 5 列和第 6 列对生成的执行路径进行了验证。

op1 op2 X Y 执行行序列 调用
10 20 30 40 1, 2, 3, 11, 12 Rountine3
10  20 40 30 1, 2, 3, 11, 12 Rountine3
10 10 30 40 1, 2, 3, 4, 5, 6, 7, 8, 12 Rountine2
10 10 40 30 1, 2, 3, 4, 5, 6, 9, 10, 12 Rountine1