汇编笔记

一、基础概念

0.汇编基础

能够被计算机直接识别的语言称之为机器语言,比如:00100000这种的,汇编语言是需要通过编译器转变为机器语言的。

计算机构成:输入/输出设备、存储器、运算器、控制器

1.基础单位信息

bit=位 1/0 计算机最小信息单位

Byte=字节=8bit=B=1个存储单元 计算机最小存储单位

字(word)=2B=2byte

存储地址和存储内容一般用16进制表示

0x..或者H=十六进制(0,F) B=二进制(0,1) D=十进制(0,9)

2.CPU对存储器的读写

ROM=>BOIS芯片

CPU通过地址总线寻址、数据总线传输数据、控制总线进行操作来完成一些处理。

地址对应的是数据,因此地址总线的宽度也就是其一次最大能寻找到多少个字节的数据。

不同CPU的寄存器个数是不同的,但是都有通用寄存器

3.寄存器

概念:CPU中程序员可以用指令读写的部件,寄存器数量有限(8086中有14个寄存器),读写速度快。

屏幕快照 2018-11-08 下午9.17.52.png

内存单元是一个单元存放一个字节(8位二进制)

通用寄存器可用于传送和暂存数据,也可参与算术逻辑运算,并保存运算结果。除此之外,它们还各自具有一些特殊功能。

数据是不能直接送入段地址寄存器(DS)中的;

16位寄存器可以拆分为两个8位寄存器进行使用;

mov a1,[0],此处的[]说明操作的是一个内存单元,[0]中的0说明这个内存单元的偏移地址是0,它的段地址默认放在ds寄存器中,使用时会被去出来。

PS:

1
2
3
4
累加寄存器在不同位计算机中的名字不同
16位-AX
32位-EAX
64位-RAX

16位数据寄存器不能存放数据地址,但是32位的可以

3.1 数据寄存器

屏幕快照 2018-11-08 下午9.21.03.png

3.2 标志寄存器

屏幕快照 2018-11-09 下午8.54.44.png

3.2.1运算结果标志位

ZF标志(ZeroFlag):

零位标志位,它记录相关指令执行后的结果是否为0,如果是0,那么ZF=1,如果结果不为0,那么ZF=0。

PF标志(ParityFlag):

奇偶标志位,它记录相关指令执行后,其结果的所有二进制位中1个个数是否为偶数,如果是偶数,PF=1,反之为0。

SF标志(SignFlag):

符号标志位,它记录相关指令执行后,其结果是否为负,如果结果为负,SF=1,如果非负,SF=0。

CF标志(Carry进位,Flag标志):

进位标志位,一般情况,进行无符号运算时,它记录运算结果的最高位向更高位的进位值,或从更高位的借位值,如果运算结果的最高位产生了一个进位或借位,那么其值为1,否则其值为0。

OF标志(Overflow溢出,Flag标志)

溢出标志位,在进行有符号数运算的时候,如果结果超出了机器所能表示的范围称为溢出,OF的值被置为1,否则OF的值为0。

注意:这里所说的溢出,只是对有符号运算而言。

3.2.2状态控制标志位

TF标志(TrapFlag)

追踪标志位,当追踪标志被置为1时,CPU进入单步执行方式,即每执行一条指令产生一个单步中断请求,这中方式主要用于程序的调试。

IF标志(Interrupt-enable Flag):

中断允许标志位,用来决定CPU是否响应CPU外部的可屏蔽中断发出的中断请求,但不管该标志为何值,CPU都必须响应CPU外部的不可屏蔽中断所发出的中断请求,以及CPU内部产生的中断请求。

当IF=1时,CPU可以相应CPU外部的可屏蔽中断发出的中断请求。

当IF=0时,CPU不响应CPU外部的可屏蔽中断发出的中断请求。

CPU的指令系统中也有专门的指令来改变标志位IF的值。

4.物理地址

通常文件中至少含有两个段:代码段(存储程序的指令–可读,不可写,可执行)、数据段(存储需要的数据的指令–可读,可写,可执行)

二进制左移N位相当于这个二进制数乘以2的N次方

物理地址=段地址*16(又称基址)+偏移地址

任何时刻8086CPU都会将CS:IP指向的内容作为即将执行的指令(可以使用jmp对其进行修改操作)

一个物理地址可以对应多个逻辑地址,在编程的时候使用的是逻辑地址(=段基地址+段内偏移地址)

5.段地址

屏幕快照 2018-11-08 下午9.38.04.png

可以将若干地址连续的内存单元看做一个段

8086CPU有4个段寄存器,每个段寄存器用来确定一个逻辑段的起始位置,每种逻辑段均有各自的用途:

CS(代码段):指明代码的起始地址

利用CS:IP取得下一条要执行的指令

SS(堆栈段):指明堆栈段的起始地址

利用SS:SP操作堆栈顶的数据

DS(数据段):指明数据的起始地址

利用DS:EA存取数据段中的数据

ES(附加段):指明附加段的起始地址

利用ES:EA存取附加段中的数据

PS:

1.在内存中,指令和数据没有任何区别,都是而二进制信息,只是CPU将有的数据看成指令,有的看成数据

2.一般的寄存器,如AX,可以使用mov ax,123来完成对其中数值的修改。但是像CS,IP这样的寄存器(用来从内存中寻址执行指令的)只能使用转移指令来修改,比如jmp–jum [段地址:]偏移地址,段地址和’:’缺省将只修改IP的值

3.操作中如果没有指明段前缀,则一般访问的是DS

1
2
3
mov ax,[1000H]
;这两行都是等价的
mov ax,ds:[1000H]

6.mov,add,sub指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mov 寄存器,数据
比如:
mov ax,8
mov 寄存器,寄存器
比如:
mov ax,bx
mov 寄存器,内存单元
比如:
mov ax,[0]
mov 内存单元,寄存器
比如:
mov [0],ax
mov 段寄存器,寄存器 //相反也对
比如:
mov ds,ax

关于mov的操作对象的说明:
屏幕快照 2018-11-11 下午4.59.54.png

PS:

指令=操作码(+操作数)

7.栈(后入先出)

两个关键寄存器:SS,SP->段地址,段偏移地址。这对寄存器将会指出栈顶地址。栈大小由我们自己安排所以要小心超界问题。

1
2
3
4
5
6
mov ax,0123H
psuh ax
mov bx,2266H
push bx
pop ax //2266H
pop bx //0123H

PS:

堆栈操作都是以字(2字节)为单位操作的。

8.开发环境配置

win7及以上系统都没有debug了,所以都需要这个DOSBOX

MAC OS环境下DOSBOX汇编环境的搭建

9.debug

功能:

  1. 可以查看CPU寄存器的各种内容
  2. 可以查看内存的使用情况
  3. 可以在机器码级别跟踪程序的运行

常用操作:
屏幕快照 2018-11-08 下午10.56.20.png

二、程序

0.程序运行

1.程序加载到内存

2.CPU使用寄存器CS:IP找到程序即将执行指令的位置

1.伪指令

伪指令不对应机器码,由编译器进行处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 将名字为codesg(标号 )的代码段跟cs寄存器联系起来
assume cs:codesg
// XXX segment 到 XXX ends标识了一个代码段
codesg segment
mov ax,0123H
...
// 下面这两段实现了程序返回
mov ax,4c00H
int 21H
codesg ends
end // 汇编程序结束的标志

将代码保存为asm格式的文件后就可以采用微软的masm汇编编译器来编译汇编代码。(注意编译后生成的是filename.obj还需要将其链接为可执行文件filename.exe,连接可以使用微软的Overlay Linker3.60连接器)

2.[bx]和loop指令

mov ax,[bx]
功能:bx中存放的数据作为一个偏移地址EA,段地址SA默认在ds中,将SE:EA处的数据送入ax中,即(ax)=((ds)*16+(dx))

inc bx 是指bx中的内容加1

PS:用’()’来表示一个寄存器或者内存单元中的内容。比如(ax)就表示寄存器ax中的内容

loop指令实现循环公布功能,cx中保存了循环次数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
assume cs:codesg
codesg segment
mov ax,0123H
mov cx,11
// s是一个标号
// 只要cx中的值不为0,则loop都回去执行标号s出的值
s: add ax,ax
loop s
mov ax,4c00H
int 21H
codesg ends
end
3.dw和end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
assume cs:codesg
codesg segment
dw 0123h,0456h,0789h,0defh
start: mov ax,0123H
mov cx,11
// s是一个标号
// 只要cx中的值不为0,则loop都回去执行标号s出的值
s: add ax,ax
loop s
mov ax,4c00H
int 21H
codesg ends
end start

dw定义了多个字符型数据,每个数据占用16个字节的内存空间。取用时从cs去的段地址,dw最先定义所以段偏移为0,之后bx加2操作进行连续取用。

end除了通知编译器程序结束外,还可以告诉编译器程序的入口在什么地方。

三、更灵活的定位内存地址的方法

0.七种寻址方式

寻址方式: 指令中指明操作数存放位置的表达方式。

寻址方式可以分为:

立即数寻址方式(存放在指令当中)

mov AL,10H-->立即数(只能是源操作数,即寄存器或者存储器)

寄存器寻址方式(存于寄存器中)

inc cx;加1
dec cs;减1
mov ax,bx

存储器寻址方式(存放于存储器之中)
|
|    mov ax,[25000H]-->存储器操作数
|
|->  直接寻址方式
|
|->  寄存器间接寻址方式
|
|->  寄存器相对寻址方式
|
|->  基址加变址寻址方式
|
|->  相对加基址变址寻址方式

屏幕快照 2018-11-11 下午4.59.54.png

1.and和or指令

1
2
3
4
5
;可以将操作对象的相应位设为0,其它位保持不变
and a1,11111110B
;可以将操作对象的相应位设为1,其它位保持不变
or a1,00000001B

2.ASCII

a字符–>61H存储在指定空间中

1
2
3
4
5
6
7
;使用'......'指明数据是以字符的形式给出的
data segment
db 'unIX'
data ends
;注意:小写字母的ASCII码值比大写字母的ASCII码值大20H

3.指令处理数据的长度

1
2
3
4
;一个字单元
mov word ptr ds:[0],1
;一个字节单元
mov byte ptr ds:[0],1

4.伪指令dd

dd->字节型数据
dw->字型数据

1
2
3
4
5
6
7
8
data segment
;数据为01H,在data:0处,占1个字节
db 1
;数据为0001H,在data:1处,占1个字
dw 1
;数据为00000001H,在data:2处,占2个字节
dd 1
data ends

5.dup

dup配合db,dw,dd进行数据重复

1
2
3
4
;db 重复的次数 dup (重复的字节型数据)
db 3 dup (0,1,2)
;定义了9个字节
;相当于db 0,1,2,0,1,2,0,1,2

四、转移指令的原理

可以修改IP,或同时修改CS和IP的指令统称为转移指令。

1.操作符 offset

offset 可以取得标号的偏移地址

2.jmp指令

jmp为无条件转移指令,可以只修改IP,也可以同时修改CS和IP

1
2
3
4
;转到标号处执行命令,这个是
jmp short 标号
;段间转移
jmp far ptr 标号

3.jcxz指令

jcxz条件转移指令

1
jcxz 标号

4.loop指令

loop指令为循环指令

1
loop 标号

5.in指令

用于CPU从外设端口接收数据

6.out输出指令

用于CPU向外设端口发送数据

7.xchg交换指令

8.地址传送指令:LEA & LDS & LES

1
2
3
;reg16--16位通用寄存器
;mem--存储单元
LEA reg16,mem

9.标志传送指令:LAHF & SAHF & PUSHF & POPF

五、算数运算指令的原理

1.加法指令

• ADD(Addition) 加法指令

• ADC(Add withCarry)带进位加法指令

• INC(Increment)加 1指令

• AAA(ASCIIadjustforaddition)加法ASCII调整指令

• DAA(Decimaladjustforaddition)加法十进制调整指令

2.减法指令

8086有7条减法指令:

• SUB(Subtraction)减法指令

• SBB(SubtractionwithBorrow)进位减法指令

• DEC(Decrement by 1)减1指令

• NEG(Negate) 求补指令

• CMP(Compare)比较指令

• AAS(ASCII Adjust for Subtraction) 减法ASCII调整指令

• DAS(Decimal Adjust for Subtraction) 减法十进制调整指令

3. 乘法指令

1)无符号乘法(MUL)

2)带符号乘法(IMUL)

4.除法指令

1)无符号除法(DIV)

2)带符号除法(IDIV)

3)字节扩展指令(CBW)

4)字扩展指令(CWD)

5.十进制调整指令

共六条

• AAA非压缩BCD码的加法十进制调整

• DAA压缩BCD码的加法十进制调整

• AAS非压缩BCD码的减法十进制调整

• DAS压缩BCD码的减法十进制调整

• AAM乘法的十进制调整

• AAD除法的十进制调整

六、逻辑运算和移位指令

针对二进制0/1进行的操作

1.逻辑运算指令

• AND逻辑“与”指令(有0则0)

• TEST测试指令(只改变标志位)

• OR逻辑“或”指令(有1则1)

• XOR(exclusive OR)逻辑“异或”指令(相同为0,不同为1)

• NOT逻辑“非”指令(不能是立即数)

2.移位指令

• SAL (Shift Arithmetic Left)算术左移(无符号数乘2,最高位进CL)

• SAR (Shiftarithmeticright)算术右移(无符号数除2,最低位进CF)

• SHL (Shift logical left)逻辑左移(最低位不变,)

• SHR (Shiftlogicalright)逻辑右移(最高位不变,低位移入CF)

• ROL (Rotateleft)循环左移

• ROR (Rotateright)循环右移

• RCL (Rotateleftwith carry)带进位循环左移(就是循环时是带CF的)

• RCR (Rotateright withcarry)带进位循环右移

七、串操作类指令

• “串”就是内存中一段地址相连的字节B或字W

• 串操作,也叫数据块操作;

• 可实现存储器数据间的直接传送;

• 8086有5种基本串操作:

MOVS(Move string)串传送指令

CMPS(Compare string)串比较指令

SCAS(Scan string)串扫描指令

LODS(Load from string)取串指令

STOS (Store in to string)存串指令

1.标志处理指令

• CLC (Clearcarryflag)清C标志

• STC(Setcarryflag )置C标志

• CMC(Complementcarryflag)对C求反

• CLD(Cleardirectionflag)清D标志

• STD(Setdirectionflag)置D标志

• CLI(Clearinterruptflag)清I标志

• STI (Setinterruptenableflag)置I标志

2.其他处理机控制指令

• NOP(Nooperation)空操作

• HLT(Halt) CPU暂停状态

• WAITCPU等待状态

• ESC交权

• LOCK(Lockbus)总线锁定

八、opcode

操作码(Operation Code, OPCode) 描述机器语言指令中,指定要执行某种操作的机器码。

OPCode在不同的场合中通常具有不同的含义,例如PHP虚拟机(Zend VM)、java虚拟机(JVM)

以及一些软件保护虚拟机中的最小操作单元都可以称之为OPCode。

九、参考

https://www.kanxue.com/book-31.htm

《汇编语言(第3版)》王爽著