计算机系统基础 7 分支程序的实现

简单条件转移指令

        根据单个标志位的值(CF, SF,OF,PF,ZF)来确定是否转移, 如果条件成立,则(EIP) + 位移量 ➡ EIP,否则什么也不做。

        注意,这里的EIP在执行本条指令时就已经变成当前指令的下一条指令的地址了,如下例, 0096827D是jnz l1的下一条指令地址,加上机器码75 07中表示偏移量的07就是l1所在处00968284

   mov  eax, x
00968270   A1 11 90 9D 00       mov   eax,dword ptr [x (09D9011h)]  
   cmp  eax, y
00968275  3B 05 15 90 9D 00    cmp  eax,dword ptr [y (09D9015h)]  
   jnz  l1
0096827B  75 07                       jne   l1 (0968284h)  
   mov  ecx,1
0096827D   B9 01 00 00 00        mov    ecx,1  
   jmp  l2
00968282   EB 05                      jmp    l1+5h (0968289h)  
l1: mov  ecx,0
00968284  B9 00 00 00 00          mov         ecx,0  
l2:
00968289   ……

JZ / JE       ZF=1时,转移

JNZ / JNE     ZF=0时,转移

JS            SF=1时,转移

JNS           SF=0时,转移

JO            OF=1时,转移

JNO           OF=0时,转移

JC            CF=1时,转移

JNC           CF=0时,转移

JP / JPE      PF=1时,转移

JNP / JPO     PF=0时,转移

无符号条件转移指令  

JA / JNBE   标号   ( CF=0 且 ZF=0,转移)

JAE / JNB   标号   ( CF=0 或 ZF=1,转移)

JB / JNAE   标号   ( CF=1 且 ZF=0,转移)

JBE / JNA   标号   ( CF=1 或 ZF=1,转移)

有符号条件转移指令 

JG / JNLE   标号:当 SF=OF 且 ZF=0时,转移

JGE / JNL   标号:当 SF=OF 或者 ZF=1时,转移

JL / JNGE   标号:当 SF≠OF 且 ZF=0时,转移

JLE / JNG   标号:当 SF≠OF 或者 ZF=1时,转移

 两种JMP格式

        间接转移方式中,除了立即数寻址方式外,其它方式均可以使用。

 功能等价的转移指令:

1. JMP L1

2. JMP BUF

3. LEA EBX,BUF

    JMP DWORD PTR [EBX]

4. MOV EBX,BUF

    JMP EBX

指令地址列表 

         如果要根据不同的输入跳转执行不同的程序片段,如果要JMP来写会非常麻烦。采用的方法是构造指令地址列表

        比如,

        FUNCTAB  DD  LP1, LP2, LP3

        JMP  FUNCTAB[EBX*4]

        (EBX)=0;跳转到 LP1

        (EBX)=1;跳转到 LP2

         又如,

void arraysubtract_colsfirst( )  {……}

void arraysubtract_rowsfirst( )  {……}

void arraysubtract_onedim ( )  {……}

int main()

{

    int   i;

    void (*funcp[3])() = { arraysubtract_colsfirst ,

                                    arraysubtract_rowsfirst,

                                    arraysubtract_onedim };

    funcp[i]();   // i=0,1,2 会执行不同的函数

    …….

}

这样也做到了从多分支到无分支的转化,比如下面例子

6.3.1 多分支向无分支的转化

例:当x==1时,显示‘HelloOne’

    x==2时,显示‘Two’

    x==3时,显示‘Welcome,Three’,……,

    x为不同的值,显示不同的串。

void myprint()
{   int  x;
    char msg1[] = "Hello,One";
    char msg2[] = "Two";
    char msg3[] = "Welcome, Three";
    char *p[3] = { msg1,msg2,msg3 };
    printf("please input 0,1,2 \n");
    scanf("%d", &x);
    printf("%s\n", p[x]);
}

编译优化上的利用

编译层面上可以利用这种转化实现优化:

比如对下面这个子函数的优化:

​​​​​​​int absdiff(int x, int y)

{

    int result;

    if (x < y)

        result = y - x;

    else

        result = x - y;

    return result;

}

无分支的写法:

int absdiff(int x, int y)

; _x$ = ecx

; _y$ = edx

push  esi

mov   esi, ecx

mov   eax, edx

sub   esi, edx

sub   eax, ecx

cmp   ecx, edx

cmovge eax, esi

pop   esi

ret   0

这样,先分别计算出x - y 和 y - x, 然后通过cmp、cmovge来实现选择。

Switch语句 

         Switch语句就是采用这种方式,如下例

        

#include <stdio.h>
int main(int argc, char* argv[])
{	int  x = 3, y = -1,  z;
	char c;
	c = getch();
	switch (c) {
	case '+':
	case 'a': // 用 字符’a’来表示‘+’
		z = x + y;
		break;
	case '-':
	case 's': // 用 字符’s’来表示‘-’
		z = x - y;
		break;
	default: z = 0;
	}
	printf(" %d %c %d = %d \n", x,c,y,z);
	return 0;
}

可以看出,是通过几种选择的值与其中最小值的差作为偏移量从内存中取数,取出的数作为在一个数组取数的下标,取出的数就是跳转到的地址,实际上就是用指令地址列表来实现的。

与转移指令功能类似的指令 

        带条件的数据传输指令

                上一篇详细写过。

语句格式:cmov***  r32,r32/m32

功    能:在条件“***”成立时,

          传送数据,即(r32/m32)→r32。

          cmov 是Conditional MOVe的缩写。

要    求:

   ① r32 表示一个32位的寄存器;

   ② m32位表示一个内存地址;

      m32对应直接、间接、变址、基址加变址寻址;

      m32对应的单元的数据类型是双字,即32位。

        字节指令 

语句格式:set***  opd

功    能:在条件“***”成立时,(opd)⬅ 1,否则 (opd)⬅ 0 。

      opd 一般为 一个字节寄存器

如:

    cmp   eax,  ebx

    setg  cl

    seta  cl

    sete  cl

使用单个标志位 设置

sete/setzsetcsetssetosetp

条件:ZF=1     CF=1    SF=1   OF=1  PF=1 

setne/setnzsetncsetnssetnosetnp

条件:ZF=0     CF=0      SF=0    OF=0   PF=0

使用多个标志位组合设置

setasetbsetgsetl

setaesetbesetgesetle​​​​​​​

  • 18
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值