Java教程

汇编语言学习

本文主要是介绍汇编语言学习,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

汇编学习笔记

ps:xxxxxB 表示一串二进制数 xxxxxH 表示一串十六进制数

1.基础知识:

汇编语言

汇编指令 被编译器翻译成 010101001 机器指令/机器码 由cpu执行
伪指令 由编译器执行的
符号体系 由编译器执行的

ex:
内存地址 十六进制指令 汇编指令 数据
073F:0100 7403 JZ 0105
073F:0102 E99700 JUMP 019C

一个字节 = 2个十六进制位 = 8个二进制位
1byte = 8bit 1bit = 1个二进制位

1KB = 1024byte 2^10 = 1024
1MB = 1024KB
1GB = 1024MB

地址线 和 数据线 和 控制线:
CUP读取内存中的内存地址和数据通过 地址线 和 数据线 和 控制线:

地址线  读取内存地址  地址线的根数决定读取的地址的大小(寻址能力)
32根地址线的寻址能力为2^32=4GB  (32位操作系统)

数据线  读取数据     数据线的根数决定读取的数据的大小 

控制线  控制读取、写入

内存:
RAM 允许读取和写入 断电后,指令和数据就丢失了

ROM  只允许读取      断电后,指令和内存还存在,一般用于计算机启动

端口:
CPU 通过端口来访问外接设备 鼠标键盘等:

端口 port 港口 用来装货和卸货 这里的货指数据

端口号   60H 就是端口号
input out指令 和端口有关  读取   写入       控制线  读写信息

CPU 可以通过 主板上电路 读到 所有数据
CPU 就像人的大脑,主板就像人的骨骼,主板上的电路就像是附加在骨骼上的神经

汇编语言 针对cpu的 地址线 数据线 控制线
cpu中一定有可以存放 地址信息 和数据 信息的地方 ——寄存器
我们汇编程序员 就是 通过 汇编语言 中的 汇编指令 去 修改 寄存器里的内容
从而 控制 cpu 就可以 控制整个计算机了

MOV AX,0005 AX就是一个数据寄存器

073F:0100 7403 JZ 0105

DS ES SS CS 都是 冒号左边的 一种 地址信息 IP比较像冒号右边的


2.debug调试工具的使用

            u指令——可以将内存中的 机器指令 翻译成 汇编指令
            d指令——可以 查看 内存中的内容
            r指令—— 可以 查看 和 修改寄存器的值 
            e指令——可以 修改 内存单位的内容 
            a指令——可以  以汇编指令的格式 在内存中写入 机器指令
            t指令—— 执行 当前 cs:ip 所指向的 机器指令
            p指令——执行汇编程序,单步跟踪。与T指令不同的是:P指令              
					不会跟踪进入子程序或软中断。p指令还可以用于结束
					本次循环,进入下一次循环
			g指令——执行汇编指令。(指令从开始运行到目标指令为止,
				   前面的所有指令都会被执行)

程序的跟踪

debug + 程序名(带.exe)
-u 查看指令
-t 单步执行
!!!!注意 需要用 -p 执行 int 指令
-q 退出(退出debug,回到DOS状态)

运行程序时cx寄存器的值为程序的长度(单位是字节)

-g指令
-g[=起始地址] [断点地址] ("[ ]"代表可选参数)
意思是从起始地址开始执行到断点地址。
如果不设置断点,则程序一直运行到中止指令才停止。
8086 CPU中 在任意时刻,cpu将CS,IP 所指向的内容 全部当作指令来执行:

在内存中 指令和数据 是没有区别的,都是二进制信息,
是我们汇编程序员 通过修改 寄存器里的内容(地址寄存器),告诉cpu
数据在哪里 指令在哪里。

!!!!CS 和 IP 决定了CPU从哪里开始读取指令!!!!

指令的执行过程

1,cpu从cs:ip 所指向的内存单元读取指令,存放到 指令缓存器中,
2,ip = ip + 所读指令的长度,从而指向 下一条指令,
3,执行指令缓存器中的内容,回到步骤1


3.寄存器:

分为三类:
数据寄存器、地址寄存器(段地址寄存器和偏移地址寄存器)、标志位寄存器

数据寄存器:
AX
BX 也可以被当作 偏移地址寄存器
CX cx也有其他作用
DX ax,dx 用来处理数据的

因为他们有一个特殊的地方 是其他寄存器 所没有的

通用寄存器,存放数据的,数据寄存器

容量 2byte = 16bit = 0000 0000 0000 0000 ~ 1111 1111 1111 1111
或者0~FFFF 或者 0~65535 总共65536种状态

他们可以各自分割为2个8位寄存器
AX = AH + AL AX的高8位构成 AH寄存器 H=high
BX = BH + BL AX的低8位构成 AL寄存器 L=low
CX = CX + CL
DX = DH + DL 0000 0000 ~ 1111 1111 或者 0~FF 或者 0~255
256种状态

为了兼容
8086CPU 8位寄存器 为了保证 以前编写的程序 稍加修改 就能运行在 8086 cpu上

内存最小单元? 字节 8bit
cpu从内存中读取一个 字节 8bit 字节型数据 8位数据 ——> 8位寄存器

8086CPU 一次性可以 处理 2种尺寸的数据

字节型数据 1byte = 8 bit - 8位寄存器中
字型数据 2byte = 16 bit - 16位寄存器中

2个字节:
一个字节 是 这个字型数据 的 高位数据 还有一个字节 是这个 字型数据的 低位字节

地址寄存器:

地址信息 也可以当成一种数据

段地址:偏移地址
ds:sp
es:bp
ss:di
cs:ip

8086 CPU 给了他 20根地址线 ,16位寄存器无法表示 所以采取这么一个计算方式
利用两个16位寄存器,达到能找到20位的地址

0000 0000 0000 0000 0000 ~ 1111 1111 1111 1111 1111 或 0~fffffH

地址加法器 地址计算方式

段地址 x 16(10H)+ 偏移地址(0~ffffH) = 物理地址
段地址 x 16 = 基础地址
基础地址 + 偏移地址 = 物理地址

ex:
段地址 : 偏移地址
F230H X10H + C8H = F23C8H

如果偏移地址需要超过ffffH,则无法找到物理地址

ES寄存器
段地址寄存器 类似DS寄存器和数据相关

通常习惯: ds 代表 数据从哪里来
es 代表 数据到哪里去

SI和DI寄存器
类似 bx寄存器,不过这两个寄存器不能分成两个8位寄存器
特殊用法:
[bx+si/di+5] (里面的顺序可以调换) 但是 不能像[bx+si+di] 这样用


标志位寄存器: ——flag寄存器

它是一个16位寄存器,有16个二进制位,有的位置上具有对应的标志位

8086CPU中的flag寄存器的各个位含义:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
OF DF IF TF SF ZF AF PF CF

标志位的取值 与运算指令(ex:add,sub,inc,mul,div,or,and等)有关,
与传送指令(ex:mov,push,pop等)无关
!!!!inc指令不影响CF标志位!!!!!

真值表

标志真值为1假值为0
OFOVNV
SFNGPL
ZFZRNZ
PFPEPO
CFCYNC
DFDNUP

CF
英文:carry flag 进位标志位(针对无符号运算)、
将两个操作数都当作无符号数进行运算
它的真值CY 英文 carry yes 表示有进位
它的假值CN 英文 carry no 表示没有进位
*CF标志位还能表示是否借位

ZF
英文 :zero flag 零标志位
它的真值ZR 英文 zero 表示结果为0
它的假值NZ 英文 not zero 表示结果不为0

PF
英文:parity flag 奇偶校验标志位
它的真值PE 英文 parity even 表示结果为偶数
它的假值PO 英文 parity odd 表示结果为奇数
取值是看二进制中的1的个数是奇数还是偶数.
ex: 00000011B–3,具有偶数个1,PF标志就是PE

SF
英文: sign flag 符号标志位(正负标志位)
它的真值NG 英文 negative 表示结果为负数
它的假值PL 英文 plus 表示结果为正数

计算在进行运算时 可以将数字当作无符号的运算,也可以当作有符号的
运算,如果我们需要知道有符号运算的结果的正负,SF就派上了用场。

OF
英文:overflow flag 溢出标志位(针对有符号运算)
将两个操作数都当作有符号数进行运算
它的真值 OV 英文 overflow 表示结果溢出
它的假值 NV 英文 not overflow 表示结果无溢出

DF
英文 :direction flag 方向标志位
它的真值 DN 英文 down 表示每次串传递操作后,si,di递增
它的假值 UP 英文 up 表示每次串传递操作后,si,di递减
-128~127 ;有符号
-32768~32767 ;结果超过这个范围为溢出


4.寄存器(内存的访问)

ds段地址寄存器 访问数据用的

mov al,ds:[0]
mov al,ds:[1]
mov ds:[0],ax
mov ds:[1],bh
(debug中需要省略ds:,只用写mov al,[0],mov [0],ax)

数据段 ——编程时候的一种数据安排

字节型数据 字型数据 在内存中的存放

字型数据 在内存中存储时,需要2个地址连续的内存单元存放,

高位字节 存放在 高地址中
低位字节 存放在 低地址中

cpu和内存之间的交互注意点:
1.数据从哪里来 内存地址
2.数据的长度 字节型数据 字型数据
3.寄存器是相互独立的

数据和指令的区别:
本质是没有区别,都是一串二进制数字

CS:IP 读取的 当作指令

DS:[偏移地址] 读取的 当作数据

程序员 去修改 寄存器中的内容 从而决定 数据从哪里来,指令从哪里来


5.栈

栈的概念: 一段连续的内存单元,也就是一段连续的内存地址

内存角度:
入栈 push 将16位寄存器 或者 内存中的 字型数据 -> 栈顶标记上方,修改栈顶标记

出栈 pop 将栈顶标记 所标识的 字型数据 -> 16位寄存器 或者 内存中,修改栈顶标记

栈顶标记是内存地址
段地址 和 偏移地址 来表示

在8086 CPU中 在任意时刻 将段地址寄存器SS 和 偏移地址寄存器SP 所组合
出来的 内存地址 当作栈顶标记

ex:
push ax 修改SP寄存器中的数值 SP = SP - 2
将 AX 中 字型数据 -> SS:SP 所组合出来的 内存地址中 入栈

pop bx 将SS:SP 所组合出来的 内存地址中的 值 -> BX 中
修改SP寄存器中的数值 SP = SP + 2 出栈

栈的设置:

栈的位置 由栈顶标记 决定 即SS:SP决定
栈的大小 由SP决定

起始地址 + 你所设定的栈的大小 的 字节数
0000 + 16(10H) = 10H ss:sp所组合出来的 栈顶标记

ex: ss:sp=2000:0010 栈的位置在地址2000:0010处,栈的大小为
10H(16byte)即16个字节型数据大小,8个字型数据大小

栈的大小最好设置成16(byte)的倍数,防止出现一些 稀奇古怪的 问题

栈顶越界:

入栈或出栈的 指令或数据的数量 超过栈的大小,即栈顶越界
该操作 会导致 一连串的错误(ex:原来栈中的数据被覆盖)
所以 在编程过程中用到栈时 需要特别注意,安排好栈的大小。

栈的最大空间可以设置为多少

SP寄存器的变化范围 0~ffffH 一共65536个字节,32768个字型数据,即64kb

SS = 2000H SP = 0
就是设置了一个可以存放 32768个字型数据的箱子(栈)

栈的作用:

1.临时性保存数据
ex:call指令将当时的ip临时保存到了栈中,等会ret指令出现时将ip取回

2.进行数据交换
ex:将ax,bx中的数据存入栈中,再通过栈取回数据达到数据交换的目的

内存段的安全问题 数据段 代码段 栈段

随意地向某一段内存空间中 写入内容 是非常危险的

mov 指令 由于我们不小心修改了 系统存放在 内存中的 重要数据 或者
重要指令 导致的 程序的崩溃 系统的崩溃

所以我们需要向安全的内存空间去写入内容
0:200~0:2FFH 256个字节

使用 操作系统 分配给你的 内存空间

在操作系统的环境中,合法的通过 操作系统取得的 内存空间 都是安全的
因为操作系统不会让一个程序 所使用的 内存空间 和 其他程序 以及系统
自己的 空间 产生 冲突 ,操作系统可以看作是一个管理内存的程序。

一种是 系统加载程序时 为 程序分配的 内存空间
另一种是 程序在执行的过程中 向系统 再去申请的 内存空间


程序的编译与链接

编译 asm -> obj
链接 obj -> exe

exe 可执行文件

系统是怎么知道 要分配多大的内存 给 这个 程序的? 也就是这个exe

因为 exe文件 中 除了 我们整个程序的源代码 还包括了 一些信息
ex:文件有多大 程序在哪里 等等

这些信息称为描述信息

系统就是根据这些描述信息 进行 相关的设置


mam编译规则

data segment 告诉了编译器 data 段 从这里开始
data ends 告诉了编译器 data 段 在这里结束 为了分配内存
段的名字可以随意取,这里取作data,是为了方便阅读和理解

我们在编写.asm文件时,不加H默认为10进制,加H表示为16进制,若像4c00
不加H,编译时报错Non-digit in number,因为不加H默认为10进制,
而10进制中是不允许出现字母的,也有些编译器要求以0x开头表示16进制

而debug中默认所有数字都是16进制。
比如用A命令输入mov ax,100a,不用加H,否则出错

编写.asm时使用到 [bx] 时可以完整的打出 ds:[bx] 或者省略 ds:,直接打 [bx]

masm 要求 在以字母 为最高位的 数据 前面需要加个“0”,否则编译报错
ex: mov ax,B08CH(编译会出错) 需要改成 mov ax,0B08CH

在debug中 mov ax,[0] = mov ax,ds:0 ,而在masm编译器中会被翻译成
mov ax,[0] = mov ax,0。结果截然不同,所以避免使用 [数字] ,用 [bx] 代替,
或者 用 段寄存器:[数字] 代替(ex:ds:[0])。


程序返回的功能

系统在加载程序的时候 给程序分配内存 设置寄存器
程序返回则将 内存 和 寄存器 都还给 系统

因为内存是有限的,所以程序返回是必要的


程序段前缀数据区(PSP区)
从ds:0 开始的256个字节
它是用来 系统和程序之间 进行的通信,里面包含 程序的名字,程序中的代码

PSP区 ds:0 (占256个字节= 16x16= 100H)
物理地址: ds x 10H + 0 = ds x 10H

程序区 ds+10H:0
物理地址: (ds + 10H)x 10H + 0 = ds x 10H + 100H
(PSP区和程序区在内存上是连续的)


6.汇编指令及伪指令 总结:

汇编指令MOV——移动指令 将XX数据移动到XX寄存器中,
或者将XX寄存器(中的数据)移动到另一个寄存器中

在使用 mov 时 要保证 数据与 寄存器之间 位数一致性

ex:
mov ax,4e20H
mov ah,ffH
mov bx,ax
mov cl,bl
mov dl,bh
mov ax,dx

!!!! 数据与寄存器之间要 保证一致性!!!!!
8位寄存器 给 8位寄存器 8位数据 给 8位寄存器
16位寄存器 给 16位寄存器 16位数据 给 16位寄存器


汇编指令ADD——加法指令
ex: add ax,0008H —— ax = ax + 0008H
将逗号左边的值与逗号右边的值相加,再将结果存入逗号左边
ex: add ax ,bx—— ax =ax + bx
SUB——减法指令
英文单词 subtract
ex sub ax,0008H—— ax = ax - 0008H
将逗号左边的值减去逗号右边的值,再将结果存入逗号左边
ex sub ax,cx—— ax =ax -cx

8位寄存器 进行8位运算 保存8位数据
16位寄存器 进行16位运算 保存16位数据

寄存器和寄存器之间是相互独立,在运算时不会影响到其他寄存器
ex:AH和AL,BH和BL…


汇编指令——[BX]和LOOP指令:

mov bx,10h
mov ax,[bx] 这时相当于将ds:10h中的内容存入ax寄存器

指令 inc bx = add bx,1 不过这个指令占用的内存更少,节约了内存

LOOP 指令 循环指令 跳转(jmp)指令 按照次数来跳转
循环次数 跳转次数 保存在 cx寄存器中

loop指令 2个步骤

  1. 先cx = cx -1
  2. 后判断cx中的值,不为0 则跳转(jmp)到 标号(内存地址)的 位置 继续执行
    若 cx = 0,则执行下面的 指令

ex:
mov cx,16
mov dl,0
s: mov ds:[bx],dl
inc dl
inc bx
loop s
mov ax,4c00H
int 21H

s:——标号

执行到指令loop s 时 先让cx的值减一,然后判断cx中的值是否为0,不为零,
跳转到 标号开始处 的代码 开始执行:mov ds:[bx],dl,inc dl,inc bx
然后又执行到 loop s,再先将cx -1 ,然后判断x中的值是否为0,重复
以上操作,直到 cx = 0 ,跳出循环,改为执行loop s下方的代码,
mov ax,4c00h ,int 21h。

在debug中遇到 loop指令 可以用 -p 指令 一键跳出循环,代替 繁琐的
-t 指令 操作,节约时间; 还可以通过-g 指令 达到同样的效果


dw

英文单词是 define word 定义字型数据(一个数据占2个字节)

ex: dw 0001h,0002h,0003h(数据之间用逗号隔开)

程序运行时 cpu 将这些数据 自动保存在 从cs:0开始的地址上,cs:0、
cs:1、cs:2。

dw 作用 不仅是定义了一串存放在cs:0处的 字型数据,还可以为该程序开辟一段
内存空间 。
ex:dw 0,0,0,0,0,0,0,0 为该程序开辟了一段 16个字节 的空间


db
英文单词是 define byte 定义字节型数据(一个数据占1个字节)


end
结束程序的伪指令
后面跟上标号,可以描述程序的入口(即程序从哪里开始执行)

ex:
assume cs:code
code segment
dw 1,2,3,4,5,6,7,8
start: mov ax,0
mov bx,0
mov cx,8
a: mov ax,cs:[bx]
add bx,2
loop a
mov ax,4c00H
int 21h

code ends
end start

这个程序 最后一行 end start 告诉了cpu 这个 程序从start 标号处开始执行,
即从 mov ax,0 处开始执行程序(即cs:ip指向该处)

包含多个段的程序:

一个段(segment)最小占用16个字节,占用的字节总是 16的倍数


汇编指令 and 和 or

(逻辑运算指令:按照二进制位进行逻辑运算)

and 与运算 作用:将操作对象的相应位置设为0,其他位不变

ex:mov ax,01100011b
and ax, 00111011b
执行后:ax = 00100011b (两个全为1,结果才为1) 串联

or 或运算 作用: 将操作对象的相应位设成1,其他位不变
ex:mov ax,01100011b
or ax,00111011b
执行后:ax=01111011b (两个只要有一个为1,结果就为1) 并联

小技巧:按alt + 右边小键盘数字 可以将数字转换成字符
ex: alt+65 =‘A’


word ptr和byte ptr 伪指令

确定数据的大小(长度)的方法
word ptr 16位标志
byte ptr 8位标志
ex: mov word ptr ds:[0],1 将16位的1(0001)放入ds:[0]处
mov byte ptr ds:[0],1 将8位的1(01)放入ds:[0]处
Inc word ptr ds:[0 将ds:[0]处的数据加上一个16位的1


汇编指令 div指令 除法指令

除数:有8位和16位两种,在一个 寄存器 或者 内存单元中

被除数:默认放在 AX 或者 AX 和 DX 中
如果除数为8位,被除数则为16位 ,默认存放在 AX中
如果除数为16位,被除数则为32位,DX存放高16位,AX存放低16位

结果:
如果除数为8位,则AL(低位)储存除法操作的商,AH(高位)储存除法操作的余数
如果除数为16位,则AX储存除法操作的商,DX储存除法操作的余数

ex:div bl
div byte ptr ds:[0]
div dx
div word ptr ds:[1]


dd伪指令
定义double world 数据(32位/8个16进制位)


dup伪指令
重复定义数据
格式: 数据长度类型 重复次数 dup (重复的数据)
ex: dw 100 dup(1) 定义100个dw类型的0
ex: db 3 dup(0,1,2) 定义db类型的0,1,2三遍(一共9个db数据)
ex: db 2 dup (‘abc’,‘ABC’) 定义’abc’,'ABC’字符串两遍(一共4个字符串12个字节)


OFFSET 操作符 (由编译器处理)
功能:取得标号处的偏移地址

ex: start: mov ax,OFFSET start(取得标号start处的偏移地址)
s: mov bx,OFFSET s (取得标号s处的偏移地址)


汇编指令——jmp 指令

英文单词 jump
转移指令, 可以修改 cs 和 ip 这2个寄存器 决定了cpu从哪里读取指令
ex:
jmp 2000:0
jmp 寄存器

    *在编写asm文件时 jmp 后面还可以跟上标号,编译器会自动将标号
      翻译成对应标号处的地址

jmp指令 要给出 两种信息:

(1)转移的目的地址
(2)转移的距离(段间转移、段内短转移,段内近转移)

1.利用标号使用jmp:

8位位移 -128~127 jmp short xx 段内短转移
16位位移 -32768~32767 jmp near ptr xx 段内近转移(xx表示标号)
这两种jmp只修改ip寄存器
(实际上是利用位移来转移)

位移 = 标号处偏移地址地址 - jmp指令后一个字节的偏移地址
ex:0010 - 0002 = 0008(取byte)= 08 jmp short xx 机器码为 EB08
ex:0103 - 0003 = 0100(取word)= 0100 jmp near ptr xx 机器码为E90001

无限制位移范围 jmp far ptr xx 这种jmp同时修改cs和ip寄存器

2.无标号使用jmp:

jmp 16位寄存器 仅修改ip寄存器的值 = mov ip ,16位寄存器
ex: jmp ax = mov ip,ax

jmp word ptr 内存单元地址(段内转移)
ex: mov ax,0123h
mov ds;[0],ax
jmp word ptr ds:[0]
结果 (ip)= 0123h

jmp dword ptr 内存单元地址(段间转移)
结果:(cs)= 目标地址+2 ;(ip) = 目标地址
ex: mov ax,0123h
mov ds:[0],ax
mov word ptr ds:[2],0
jmp dword ptr ds:[0]
结果(cs)= 0 ;(ip)= 0123h

计算机中是没有减法的,减法在计算机内是用加上一个负数表示的
负数的是正数通过补码的方式进行转变的
补码的方式:将一个正数 变成二进制后 按位取反(0->1/1->0)最后再加上1

ex:-5=5进行补码=00000101—>11111010+1=111111011=FB


汇编指令——jcxz 指令

短转移指令 修改ip寄存器 范围 -128~127
格式: jcxz 标号(如果(cx)= 0,转移到标号处执行)
jcxz 标号 = if((cx)== 0 )jmp short 标号


汇编指令 CALL 和 RET

call指令
call ——调用指令,类似调用函数,遇到ret回到调用点处

为无条件转移指令,可以只修改ip(jmp short/jmp near ptr/寄存器),
也可以同时修改cs和ip(jmp far ptr)。

位移的方式 将转移的目的地址存放在内存中

call 标号 = push ip + jmp near ptr 标号

指令执行过程:
1.cpu从cs和ip寄存器所组合出来的地址中 读取指令 将其读到 指令缓存器中
2.ip = ip + 所读指令的字节数
3.执行 指令缓存器的内容,回到第一步

call 指令原理

{将位移保存在机器码中

将转移的目的地址存放在内存中

将转移的目的地址存放在机器码中 call far ptr s

将转移的目的地址存放在寄存器中 call ax,call bx}

利用call指令实现调用子程序,记得分清 局部变量 和 全局变量

局部变量:调用函数时,将函数中 需要用到的 寄存器的 原本的值
通过 push 保存,在程序结束后 通过 pop 取回

ret指令
ret 执行该指令 相当于执行了 pop ip
retf 执行该指令 相当于执行了 pop ip 和 pop cs


汇编指令 mul ——乘法指令

两个相乘数 要么都是 8位 要么都是 16位 分为 8位乘法 和 16位乘法

8位乘法:
一个数字默认存放在 al 中 另一个数字 存放在 其他 8位寄存器中
或者 字节型内存单元中
ml 8位寄存器 意思是 al * 8位寄存器里的值
mul byte ptr ds:[0] 意思是 al * byte ptr ds:[0]中的值
结果:得到一个16位数值 存放在 ax 中

16位乘法:
一个数字默认存放在 ax 中 另一个数字 存放在 其他 16位寄存器中
或者 字型内存单元中
mul 16位寄存器 意思是 ax * 位寄存器里的值
mul word ptr ds:[0] 意思是 ax * word ptr ds:[0]中的值
结果:得到一个32位数值 低存放在 ax 中 高16位存放在dx中


汇编指令 adc
英文意思:add carry ——带进位的加法(适用于大于16位的加法)

adc ax,bx 执行后 (ax)=(ax)+(bx)+CF(cf位里的值0/1)
对比 add ax,bx 执行后 (ax)=(ax)+(bx)
ex:要实现 1EF000H + 201000H
结果的低16位存放在ax中,高16位存放在dx中

代码: mov ax,F000H
mov dx,001EH
add ax,1000H
adc dx,0020H


汇编指令 sbb
带借位的减法 类似adc(适用于大于16位的减法)

sbb ax,bx 执行后 (ax)=(ax)-(bx)- CF(cf位里的值0/1)
对比sub ax,bx 执行后(ax)=(ax)-(bx)


汇编指令 cmp
英文:compare 比较
执行cmp后将两个操作数相减,但是不保存结果,只改变标志位

对比sub指令:sub ax,bx 执行后 (ax)= (ax)-(bx)
cmp ax,bx 执行后 不改变ax的值(ax),
仅通过(ax)-(bx)的结果来,修改标志位(zf,cf,sf,of)

cmp ax,bx 的不同情况 讨论:

1.ax = bx —— zf = 1 代表ax,bx相等

2.ax != bx —— zf = 0 代表ax不等于bx

3.ax < bx —— cf = 1 代表ax小于bx

4.ax >= bx —— cf = 0 代表ax大于等于bx

5.ax > bx —— cf = 0 且 zf = 0 代表ax大于bx

6.ax <= bx —— cf = 1 或 zf = 1 代表ax小于等于bx


汇编指令 je,jne,ja,jna,jb,jnb
条件跳转指令,常与cmp指令配合使用(类似高级语言的if)
注意:以上跳转指令都是短跳转,即跳转范围为-128~127

指令 英文 含义 条件
je jump equal 如果相等则跳转 zf=1

jne jump not equal 如果不相等则跳转 zf=0

ja jump above 如果大于则跳转 cf=0且zf=0

jna jump not above 如果不大于则跳转(小于等于) cf=1或zf=1

jb jump below 如果小于则跳转 cf = 1

jnb jump not below 如果不小于则跳转(大于等于) cf = 0


汇编指令 cld,std
设置DF标志位值的指令

cld,英文:clear direction,清除方向设置(恢复正向),设置df = 0
std,英文:set direction,设置方向(设置反向),设置df = 1


汇编指令 movsb,movsw
串传送指令

movsb 复制字节型数据,根据ds:[si](原始地址)
和es:[di](目的地址),df位(控制复制的方向)

movsw 复制字型数据 ,根据ds:[si](原始地址)
和es:[di](目的地址),df位(控制复制的方向)


汇编指令 rep
重复指令
根据 cx 的值 重复执行后面的指令

ex:rep movsb 设置合适的cx值 可以实现,将所有位于
原始地址的 字型数据 复制到 目标地址中


汇编指令 pushf 和 popf
pushf:将flag寄存器中的值保存在栈中
popf: 将栈中的值取出存入flag寄存器中

!这两个指令是直接使用的,不带任何的操作数


7.内中断

发生了需要CPU立刻去处理的信息

1.除法错误 divide overflow 中断信息
2.单步执行
3.执行into指令
4.执行int指令

需要一个程序去处理
cs:ip ==》 需要处理的程序入口 段地址:偏移地址

中断向量表 存放在内存 0000:0000~0000:03FF中
中断类型码
0号处理中断信息的程序地址 cs:ip 0
1号处理中断信息的程序地址 cs:ip 1
2号处理中断信息的程序地址 cs:ip 2
… … …
CPU通过 中断类型码 找到中断向量表 中 与之对应的 程序地址的 位置

中断过程
1.取得中断类型码 N
2.保存标志位寄存器 =》 栈 pushf
3.将标志位寄存器的第8位 TF 和 第9位 IF 设置为0
4.push cs
5.push ip
6.cs = N * 4 + 2 ip = N *4

中断处理程序返回的办法:
iret (pop ip
pop cs
popf)

对比ret(pop ip)

这篇关于汇编语言学习的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!