跳转指令是汇编语言中最常用的指令之一。C语言中的条件语句,循环语句,经过汇编后都含有跳转指令。
一、跳转指令
指令执行过程中遇到跳转指令会跳转到一个全新的位置。跳转指令分为无条件跳转与有条件跳转两种。无条件跳转又分为直接跳转(跳转目标在指令中)和间接跳转(跳转目标的值存在寄存器或存储器中)两种,是指无需做任何判断就跳转到目标位置。有条件跳转指令需要根据条件码的值决定是否跳转。CPU最常见的四个条件码是:
CF:进位标志,最近操作在最高位产生进位;
ZF:零标志,最近操作的结果为零;
SF:符号标志,最近操作的结果为负数;
OF:溢出标志,最近操作导致补码溢出。
IA32指令集中的跳转指令如下图所示:
表中前两个是无条件跳转,剩下所有的都是有条件跳转。在c语言中, a − b < 0 a-b<0 a−b<0,并不意味着 a < b a<b a<b,因为 a − b a-b a−b的值有可能溢出,导致相反的结果,即 a − b < 0 a-b<0 a−b<0,意味着 a > b a>b a>b。因此,我们在表中可以看到大于或小于的跳转指令需要同时判断溢出标志和符号标志。举例如下:
假设数据用4bits有符号数表示,采用补码编码方式
− 7 = 1001 -7=1001 −7=1001
4 = 0100 4=0100 4=0100
已知 − 7 < 4 -7<4 −7<4
然而 − 7 − 4 = − 7 + ( − 4 ) = 1001 + 1100 = ( 1 ) 0101 = 5 > 0 -7-4=-7+(-4)=1001+1100=(1)0101=5>0 −7−4=−7+(−4)=1001+1100=(1)0101=5>0
产生这种现象的原因是计算结果产生进位,而我们只有四位有效数字,因此,最高位1溢出,得到的结果为0101大于0。
二、跟踪跳转指令的执行
以je指令为例,看一看处理器如何处理跳转指令。假设je指令代码为73(实际上不一定是73)位于位置0x01e处,处理器最近的操作为非零,即跳转指令条件不满足,不跳转。
阶段 | j xx DEST | je 0x28 |
---|---|---|
取指令 | icode = M[PC] valC=M[PC+1] valP=PC+5 |
Icode=M[0x01e]=73 valC=M[0x01f]=0x28 valP=0x01e+5=0x023 |
译码 | – | – |
执行 | Cnd=cond(标志位,icode) | Cnd=cond(0,0,0,73)=0 |
访存 | – | – |
写回 | – | – |
更新PC | PC=Cnd? valC:valP | PC=0?0x28:0x23=0x23 |
三、C语言条件分支语句转跳转指令
C语言中的条件分支语句通用形式如下所示:
if (test statement)
then statement
else
else statement
翻译成goto语句如下所示:
if (test statement)
goto True;
else statement
goto Done;
True:
then statement
Done:
以如下C语言代码为例,展示汇编语言跳转指令使用方式:
int absdiff(int x, int y){
if (x<y)
return y-x;
else
return x-y ;
}
汇编语言形式如下:
// x at %ebp+8, y at %ebp+12
movl 8(%ebp) %edx //get x
movl 12(%ebp) %eax //get y
cmpl %eax %edx //compare x:y
jge .L2
subl %eax %edx //result=x-y
jmp .L3
.L2:
subl %edx %eax //result=y-x
.L3:
四、C语言do-while循环语句
C语言do-while语句通用形式如下:
do
body statement
while(test statement)
转成goto语句:
loop:
body statement
if (test statement)
goto loop;
示例:
// c语句
int fact_do(int n){
int result=1;
do {
result *= n;
n --;
}while(n>1);
return result;
}
//汇编代码语句
//assuming n at %ebp+8
movl 8(%ebp) %edx //get n
movl $1 %eax //set result =1
.L2:
imull %edx %eax //result*=n
subl $1 %edx //n--
cmpl $1 %edx //compare n>1
jg .L2
五、C语言while循环语句
C语言的while循环语句通用形式如下所示:
// while语句
while (test statement)
body statemen
//转成do-while语句
if(! test statement)
goto done;
do {
bodystatement}
while(test statement)
// 转成goto语句
if (!test statement)
goto done;
loop:
body statement
if (test statement)
goto loop
done:
示例如下:
//C代码
int fact_while(int n){
int result =1;
while (n>1){
result *= n;
n--;}
return result
}
//goto 代码
int fact_while(int n){
int result =1;
if (n<=1)
goto done;
loop:
result *= n;
n--;
if(n>1)
goto loop;
done:
return result;
}
//汇编代码
//assuming n at %ebp+8
movl 8(%ebp) %edx //get n
movl $1 %eax //set reuslt=1
cmpl $1 %edx //compare n: 1
jle .L7 // if <= go to done
.L10:
imull %edx %eax //result *=n
subl $1 %edx //n--
cmpl $1 %edx //compre n:1
jg .L10 //if > goto loop
.L7:
//return result
六、C语言for循环语句
先看通用代码:
//for 语句
for(init statement, test statement, update statement)
body statement
//翻译成while语句
init statement
while (test statement)
body statement
updata statement
//翻译成do while 语句
init statement
if (!test statement)
goto done;
do {
body statement
update statement
}while(test statement)
done;
//翻译成 go to语句
init statement
if(!test statement)
goto done
loop:
body statement
update statement
if(test statement)
goto loop
done:
再看个示例:
// C语言代码
int fact_for(int n){
int i;
int result =1;
for (i=2;i<n;i++){
result *= i;}
return result;
}
//汇编语言代码
//assuming n at %ebp+8
movl 8(%ebp) %edx //get n
movl $2 %eax //set i=2
movl $1 %ecx // set result =1
cmpl $2 %edx //compare n:i
jle .L14 //if n<=i goto done
.L17:
imull %eax %ecx //result *= i
addl $1 %eax //i++
cmpl %eax %edx //compare n:i
jge .L17 // if n>i
.L14:
done
理解汇编语言的跳转指令非常重要,这是理解处理器分支预测策略的基础。