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

              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的指令,都是设置标志位的,然后一般会和别的指令成对执行,比如比较完毕就判断结果.

汇编例子

  

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的地方执行

最少需要两个跳转是吗

这样浪费了很多指令周期

所以我们可以写成这样

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执行)

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

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

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

例如

  取配件   组装     喷漆

      取配件   组装      喷漆

          取配件   组装   喷漆...

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

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

比如流水线的代码

  

mov ax,1

sub ax,2

cmp ax,ax

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

  

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(他是乘数,你给多少,都是和他相乘的)

汇编例子

  

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不支持这样写

SHL ax,3
;支持这样写 SHL ax,1 默认的是往左移动一位
上面第一句,那些是以后出现的

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

例如

  

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不变

  

时间: 2024-10-05 20:05:50

16位汇编第六讲汇编指令详解第二讲的相关文章

16位汇编第五讲各种指令详解第一讲

汇编指令详解 8080指令详解 1.8086系统下,Inter指令系统共有117条指令(看似很多,分一下类) 1.数据传送类指令(专门传送数据的) 2.算术运算类指令(加减乘除的运算的) 3.位操作类指令(或  异货 与 -.) 4.串操作类指令 (内存拷贝,内存连续地址拷贝的操作) 5.控制转移类指令(跳转,比如C语言的Goto) 6.处理机控制类指令(计算机的待机 ,重启 等等,让CPU待机睡眠的指令) 学习指令的注意事项 1.指令的功能,也就是这个指令可以实现什么操作.通常的话,指令就是指

Git应用详解第二讲:Git删除、修改、撤销操作

前言 前情提要:Git应用详解第一讲:Git分区,配置与日志 在第一讲中我们对Git进行了简单的入门介绍,相信聪明的你已经了解Git的基本使用了. 这一讲我们来进一步深入学习Git应用,着重介绍Git的一些常见操作,包括:删除文件.比较文件.撤销修改.修改注释与查看帮助文档. 一.删除文件 1.git rm <file> 该命令用于删除版本库中的文件:删除工作区和暂存区中的文件都会报错: 若用该指令删除工作区中的文件,会报找不到文件的错误: 若用该指令删除暂存区中的文件,报如下错误: 所谓版本

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

                                          16位汇编第六讲汇编指令详解第第三讲 1.十进制调整指令 1. 十进制数调整指令对二进制运算的结果进行十进制调整,以得到十进制的运算结果 2.分成压缩BCD码和非压缩BCD码调整 简而言之: 以前的时候你有个手表,里面的数字是九,如果加一个1就是0了,就会产生进位, 不过这个是10进制进位的,所以应该是 a了,但是a的话就出错了.所以我们就出来了这个调整指令直接变为零,然后进位,也就是16进制码当做10进制使用

几种基本汇编指令详解

几种基本汇编指令详解 常见寄存器 寄存器 16位 32位 64位 累加寄存器 AX EAX RAX 基址寄存器 BX EBX RBX 计数寄存器 CX ECX RCX 数据寄存器 DX EDX RDX 堆栈基指针 BP EBP RBP 变址寄存器 SI ESI RSI 堆栈顶指针 SP ESP RSP 指令寄存器 IP EIP RIP 汇编指令 mov movb(8位).movw(16位).movl(32位).movq(64位) 寄存器寻址: movl %eax, %edx eax -> edx

深入理解计算机系统(3.3)---数据传送(或者说复制)指令详解

本文转载地址:http://www.cnblogs.com/zuoxiaolong/p/computer15.html 引言 上一章我们已经介绍了汇编语言的基础部分,包括数据格式.寄存器以及操作数的标识方式,接下来我们就应该去认识一下汇编语言当中的各个指令了.这些指令大多数都非常简单,但是组合在一起却能模拟出我们程序当中想要的任何效果,确实是十分神奇的一件事. 数据传送指令 数据传送指令的目的是为了将一个数据从一个位置复制到另外一个位置.既然如此,那么数据传送指令就会包含一个源操作数和一个目的操

数据传送指令详解

数据传送指令详解 前言 上一章我们说了汇编语言的基础,包括数据格式,寄存器以及操作数的标识方式,接下来我们就应该去认识一下hiU币按语言当红真难过的格各个指令了.这些指令大部署很简单,但是组合在一起却能模拟出我们程序当中香烟的任何效果,确实很神奇. 数据传送指令 数据传送指令的目的是我了将一个数据从一个位置复制到另一个位置.既然如此,那么数据传送至零就会包含一个源操作数和一个目的操作数,指令会将源操作数的值复制到目的操作数并覆盖. 数据传送指令一共可以分为5种,分别是mov,movs,movz,

特殊的算术操作指令详解

特殊的算术操作指令详解 前言 上一讲,我们说了常见的算术与逻辑运算指令,其中比较有特点的是leal指令,本次我们在介绍几个较特殊的操作指令,这些指令可以让只有32位的寄存器存储64位的数据是不是很吊? 正文 我们来看一下这些指令的大致介绍,如果又仔细看过上一讲的内容,可能会发现这里的指令有些眼熟,但是他们的作用却截然不同.以下是书中的一张概图: 第一个指令很眼熟吧,他就是我们上一章说的imull乘法指令的双字形式.不过可以看出,这里的imull指令已经完全变了了个人,他将结果存入两个寄存器.接下

[转]JVM指令详解(上)

作者:禅楼望月(http://www.cnblogs.com/yaoyinglong) 本文主要记录一些JVM指令,便于记忆与查阅. 一.未归类系列A 此系列暂未归类. 指令码    助记符                            说明 0x00         nop                                什么都不做 0x01        aconst_null                   将null推送至栈顶 二.const系列 该系列命令主要

迈向angularjs2系列(2):angular2组件和指令详解

<%= INIT %> 内容 一:angular2 helloworld! 为了简单快速的运行一个ng2的app,那么通过script引入预先编译好的angular2版本和页面的基本框架. index.html: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> &l