16位汇编第六讲汇编指令详解第二讲

2018-01-05 17:42:45 浏览数 (1)

              16位汇编第六讲汇编指令详解第二讲

1.比较指令

  CMP指令

  1.CMP指令是将目的操作数减去源操作数,按照定义相应的设置状态标志

  2.CMP指令执行的功能与SUB指令(相减指令)一样,但是不同的是CMP指令之根据结果设置标志位

  而不修改值

 可以操作的指令格式

  CMP reg,imm/reg/mem

  CMP mem,imm/reg

上面是CMP指令的语法,具体的也可以查询帮助文档,inter手册

inter手册查的办法

第一个框代表了CMP指令的所有语法

比如

  reg,reg 表示可以比较寄存器 CMP AX,BX ....

 下面的则是机器的操作码.根据二进制的机器码可以反逆向出来汇编指令

比如:

机器码是39代表的是CMP指令

一般CMP的指令,都是设置标志位的,然后一般会和别的指令成对执行,比如比较完毕就判断结果.

汇编例子

代码语言:javascript复制
cmp al,100
jz below
    ;al == 100会跳转到below执行(jz下面将,这里理解为跳转)

 2.CPU的流水线,汇编的无分支,以及优化

   什么是CPU的流水线,这样说吧,上面我们说了,CMP会和跳转一起使用,但是你知道这样的代码吗?

使用一条跳转,可以执行很多条指令.CPU的指令周期很长,这里说一下强制跳转JMP

看下JMP

可以看出,最快的需要15个指令周期,最慢的需要24 (EA:寻址方式,的有效寻址的周期)大小

那么我们可以优化一下吗

比如 C语言中的三目运算符       a == 0 ? 0:-1;  如果a < 0,成立,则a = 0,否则= -1

如果在汇编中你想怎么写,   是不是先判断ax == 0? 如果 ==0 ,我就跳转到0的地方,执行,否则跳转到-1的地方执行

最少需要两个跳转是吗

这样浪费了很多指令周期

所以我们可以写成这样

代码语言:javascript复制
mov ax,3

neg ax

sbb ax,ax

我敢说,学过汇编的人从来都只是说学过,而汇编是一门艺术,我们学习汇编,并不是学习他的指令或者语法,比如上面简单的三条汇编指令,会汇编的人都能明白,但是我想问一下,什么意思懂吗?

这个就是无分支三目运算符

简单看一下吧

ax = 3 (浪费了4个指令周期,因为有立即数,要内存寻址,所以该浪费的还是得浪费)

neg ax 这个是对3求补,上堂课也说了,汇编的求补指令的原理就是 0 - 操作数(ax))的结果

0 - 3的话,计算机也不会算,所以要把-3变为补码,让0去相加

原码:  1000 0011   (负数的源码最高位是1) 

反码   1111 1100    (反码最高位不变,其余各位取反)

补码:  1111 1101    (-3的补码)

0 上补码

0000 0000

1111 1101 

1111 1101  (还是负数)

在计算机中表示  FD    此时CF位被设置,因为计算机判断进位的方法就是看最高位,如果最高位以前是0,那么经过计算最高位为1,则判断进位了.

CF = 1

SBB  ax,ax

带借位的相减

首先ax的值就是FD了,两个相减没了,但是注意,这里有符号位,所以相减的同事要把符号位减去

1111 1101

-

1111 1110(需要加上符号位1,那么二进制就成为了这种)

 = F (-1)那么看上面的推理过程

结果就是给一个3,对齐求补码,然后算出结果为-1

当然这个只是教怎么玩汇编,不过分析程序的时候可能遇到这种优化

CPU的流水线

  上次我们说了一个JMP指令,指令周期特别长,我们可以优化成上面的那样,但是仅仅是优化了吗?

我们不妨这样想,上面的确实是优化了,但是其实内部还有CPU的流水线的优化

什么是流水线

比如一个工厂,组装汽车的,分为三步骤

第一步,取配件  (取指令)

第二步,组装  (译码(解析指令))

第三步,喷漆      (CPU执行)

我们需要三个工人,可以这样想,第一个人专门取配件,第一次执行的时候,组装的喷漆的都等待

当配件拿到手了,那么开始组装(这个时候第一个人又去取配件了),这时候喷漆的等着

当给了喷漆的了,那么这个时候喷漆,组装,已经可以正常开始工作了.

例如

  取配件   组装     喷漆

      取配件   组装      喷漆

          取配件   组装   喷漆...

只有第一次执行的时候,组装需要等待取配件,喷漆等待组装,第一次组装的时候,第二次已经开始了

上面是什么意思那,就是说,组装需要等待,喷漆也要等待.我们可不可以错开,不让他们依赖指向性

比如流水线的代码

代码语言:javascript复制
mov ax,1

sub ax,2

cmp ax,ax

每次的结果都需要等待上一次的结果,我们可以写成这样

代码语言:javascript复制
1 mov ax,1
2 
3 mov bx,1
4 
5 sub ax,2
6 
7 mov cx 3
8 
9 cmp ax,ax

其中第二行,和倒数第二行都是我随便加的,就是为了不让指令依赖于上次执行,这就是最简单的流水线,不用等待.

在这里可以说下上面的三目运算符的优化了,为什么不光光是优化,以为JMP跳转的时候,CPU的流水线可能正常执行,比如已经知道到组装了,这个时候你来个跳转,那么又要从头开始,而且组装后面的都不执行了,所以不光光是为了优化掉跳转,还有流水线的作用,上面的代码看着很恶心,可是真是的环境就是这样,不是教你怎么去写,而是教你怎么去看,让你明白他为什么这样写.当然流水线的优化还有很多种.这里只是最简单的一个例子      

 3.乘法指令

  MUL (无符号字节乘法)

    指令格式: ax = al * r8/m8

    ax(16位寄存器)存放 al * r8(八位寄存器)或者 m8(内存中八位的值)

看下inter手册

这里看一下,除法的指令周期很长,最低的70-77,所以也可以优化

这里可以看出  al要放乘数  其余寄存器放乘数

例如   ax = bl * al(他是乘数,你给多少,都是和他相乘的)

汇编例子

代码语言:javascript复制
mov al,2 (倍数是2倍)
mov bl,8
mul bl

此时算出的记过就放在ax中,因为8位*8位的数字不会超过16位的

无符号的字乘法

当我们16位*16位的怎么办,8 *8的结果是放在ax中

16 *16 则放在 DX(数据寄存器)(AX累加寄存器)当中

高16位放到DX当中,低16位放到AX中

其中乘法的 操作数都需要我们自己给,比如 MUL bl, 算出bl的乘法,默认会和al相乘

乘法指令是利用 OF(overflow溢出标志)和CF(进位标志)来判断乘积的高一班是否具有有效数值

有符号的字节乘法

  IMUL r8/m8

    ax = al * r8/m8 (和上面一样,结果放到ax中,al可以×八位的寄存器,或者内存取出的数值的8位数值

和内存取出来的数值相乘(400的偏移处我给的是11所以最后ax结果是11)

  有符号的字乘法

16*16的和无符号的一样

  高位放到DX当中,低位放到AX当中

谈到这里我们发现,乘法的指令周期特别长,我们也可以做优化,可以用位运算

对标志位的影响:

  会影响OF和CF标志

4.位运算,左移右移

1.左移指令

  这个算是附加的,主要是我们要用位运算吧乘法优化掉

SHL  左移 ,高位补零,看下语法

可以是寄存器,内存,不支持立即数,因为立即数哪里都是- ,带有1的则是默认写的时候是左移一位,只能写1

如果给1以上,就要放到CL当中了

寄存器和CL低八位寄存器(注意这里是CL则我们写的时候要注意如果寄存器左移动的时候,则给CL指定个数)

左移,最高位补零

2的二进制

0000 00010   SHL 之后  0000 0100 (4)

8086不支持这样写

代码语言:javascript复制
SHL ax,3
;支持这样写 SHL ax,1 默认的是往左移动一位
上面第一句,那些是以后出现的

说道左移,则可以用它来替代掉乘法

例如

代码语言:javascript复制
mov al,2
mov bl,3
mul al

替换成
mov bl,3
mov cl,2
shl bl,cl

仔细看一下,我们转大了,inter指令周期最起码缩少了10倍,所以说有的时候写一行汇编代码,需要想很长时间,

比如 

mov ax,0

你认为是很快了是吗,其实inter指令周期是4,不行的话自己可以查询看一下,  reg,imm这一行

但是你写为

xor ax,ax (xor代表异或的意思,相同为假,不同为真,ax和ax肯定各个二进制位相同,此时相同为0,则都变成0了)

和上面的一样,ax都是变为0,而我则赚了一个1个指令周期,其实还有很多这样的汇编代码,都是这样做出来的

所以说学习汇编,把它当做一门艺术来看.

2.右移指令

   SHR 逻辑右移,SAR算术右移

两个的不同

SHR 移动的时候,以0来填充

SAR 移动的时候,符号位填充,也就是真正的右移

和左移相反

右移也可以用于正数的除法

但是除法有除法优化的原理,以后讲,这里掌握两个指令即可.

5.除法指令

除法指令也分为有符号除法,和无符号除法

  ax / r8,m8的商,放到AL中,余数放到AH中

  16位除法

  ax /r16,m16, 16位的商放到AX当中(也就是结果放到AX中),余数放到dx中

DIV (无符号字节除法)

  指令 DIV r8/m8

  或者 DIV r16/m16

6.符号扩展

什么是符号扩展?

  符号扩展是指用一个操作数的符号位(也就是最高位)扩展变大,比如8位变为16位,符号扩展不改变数据大小

CBW al符号扩展至AH  (字节扩展)

如果al的最高有效位为0,则AH ==00

AL的最高有效位为1,折AH = FFH AL不变

字扩展

CWD AX的符号扩展至DX

AX的最高有效位是0,则DX ==00

如果为1,则DX = FFFFH AX不变

 学习资料: 

链接:http://pan.baidu.com/s/1hsKi3sw 密码:yis3

0 人点赞