参考王爽老师的《汇编语言_第2版》
前12章的笔记
8086共14个16位寄存器
通用寄存器
AX
AH
AL
BX
BH
BL
CX
CH
CL
DX
DH
DL
CS:指令段寄存器【代码段】
IP:指令偏移寄存器【代码偏移】
设CS中的内容为M IP中的内容为N,CPU将从内存M*16+N单元开始,读取一条指令并执行
即任意时刻 CS:IP指向的内容就是计算机下一步的执行内容
每执行完一条长度为N的指令 IP会自增N IP=IP+所读取指令的长度,从而指向下一条指令
通用寄存器的值 可以使用mov指令改变 如 mov ax,123
但是mov不能改变CS和IP的值,修改CS IP 可以用jmp 若想同时修改CS IP的内容,可以使用 jmp 段地址:偏移地址 完成
jmp 2AE3:3 执行后 CS=2AE3H IP=0003H CPU将会从2AE33H处读取指令并执行 注意:CSIP代表地址,地址中的内容才是指令内容
jmp ax 表示段地址CS不变 偏移地址IP改为ax中的值
DS:存放要访问数据的段地址【数据段】
mov ds,bx 将bx的段地址放到ds中(不能将数值直接放入ds中,需要借助中间寄存器)
因为CPU不支持将数据直接送入DS中 如 mov ds,1000H 所以要使用一个中间变量,先将1000H放入一个寄存器中 mov bx,1000H 再将bx的段地址放入ds
改变DS的方法:
mov ax,1000H
mov ds,ax
默认数据段地址为DS 可以显示的修改段地址 如 mov ax,CS:[] 此时 段地址为CS
栈:
SS:栈段【栈段】
SP:栈顶偏移【栈偏移】
SS:SP -> 栈顶
PUSH 和 POP cpu从栈顶寻址
PUSH 栈顶上移 入栈 超过栈顶
POP 栈顶下移 出栈 超过栈底 都会造成栈溢出
push ax 将ax入栈
pop ax 将数据出栈后放入ax
SI
DI
SI和DI于BX功能类似,只是BX可以分成BH和BL 而SI和DI不能
[] 中,只能出现四个寄存器 BX SI DI BP 。 如:[ax] --> 错误 不允许除了这四个之外的寄存器出现在[]中
且这四个也有固定的组合P162 如:[SI+DI] -->错误 不允许这样组合
BP
一般情况,默认数据段地址为DS,若使用BP 则默认段地址为SS 如 mov ax,[bp] 表示 mov ax,(SS:BP)
段地址也可以显示给出
ES
PSW
标志寄存器,是一个16位的寄存器,每一位都有特殊的含义
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
第6 位ZF:记录相关指令执行后结果是否为0 如果为0 ZF=1 否则 ZF=0
第2 位PF:记录相关指令执行后所有bit位中1的个数是否为偶数 如果有偶数个1 PF=1 否则 PF=0
第7 位SF:记录相关指令执行后结果是否为负 如果为负 SF=1 否则SF=0 (只对有符号值来说,对于无符号值 SF没有意义)
第0 位CF:进位标志位
第11位OF:溢出标志位 如果执行结果发生溢出 OF=1 否则OF=0
第10位DF:方向标志位 控制每次操作后SI、DI的增减 DF=0 每次操作后SI、DI递增 df=0 => (si)=(si)+1 (di)=(di)+1
DF=1 每次操作后SI、DI递减 df=1 => (si)=(si)-1 (di)=(di)-1
一些指令的记录:
mov指令可以完成的传输
1、将数据直接送入寄存器 mov ax,1000
2、将一个寄存器中的内存送入另一个寄存器 mov ax,bx
3、将一个内存单元中的内容送入另一个寄存器 mov ax,[偏移地址] ,此时需要配合DS使用,
因为只有偏移地址是无法定位内存地址的,还需要段地址才行,而此时的段地址就存在DS当中
所以在看到 [] 时,一定要注意此时的DS,括号里的是偏移地址,加上DS才是完整的地址 DS:[]
[] -> DS:[]
从内存单元写到寄存器 格式是 mov ax,1000H
从寄存器写到内存单元 需要先修改好DS 然后 mov [],ax 就是将ax的值写入 DS:[] 这个地址当中
修改DS分两步步:
1)mov ax,1000H
2)mov ds,ax 此时 DS=1000H 即段地址为1000H
4、mov ax,ds 将段寄存器送入通用寄存器 也是可以的
5、mov [0],cs 将段寄存器送入内存中 也是可以的
loop
(cx)=(cx)-1 (cx)<>0 则继续循环
如:mov cx,11
s: add ax,ax
loop s
每执行一次loop (cx)都会减一,每次执行loop时 都会判断(cx)是否为0 为0停止循环,不为0 则跳到s
我们在纯DOS方式下 可以直接用汇编语言去操作真实的硬件,因为运行在CPU实模式下的DOS没有能力对硬件系统进行全面严格的管理
但是在windows unix 这些运行于CPU保护模式下的操作系统中,用汇编语言去操作真实的硬件是不可能的,因为硬件已经被操作系统利用CPU的
保护模式全面严格的管理着, 所以 想要修改硬件 需要了解CPU的保护模式,破解保护模式
and 将相应位设为0
or 将相应位设为1
指令处理的数据长度
1.通过寄存器的名称指明处理数据的长度
如:mov ax,1 ax则指明是字操作,即两个字节
如:mov al,1 al则指明是字节操作,即一个字节
2.在没有寄存器名称存在的情况下,用操作符 X ptr 指明内存单元的长度
如:mov word ptr ds:[0],1 word则指明是字操作
如:mov byte ptr ds:[0],1 byte则指明是字节操作
jcxz => jump if cx=zero
call 和 ret 都会改变CS:IP 和 SS:SP
call 开始一个函数 IP增加 SP减小
ret 结束一个函数 IP还原 SP增加
call前 会push IP 将下条指令保存起来 先把IP保存到栈中 先压栈 后跳转
ret 后 会pop IP 平栈 再把IP从栈中送入指令段中 pop
栈存在的意义
在执行子程序的过程中,不改变寄存器的现状,在子程序开始时 先将寄存器的内容保存起来,在子程序结束后 再恢复寄存器之前的状态
adc带位加
sbb带位减
cmp比较
je 等于时jmp zf=1 时跳转 e equal
jne 不等于时jmp zf=0 时跳转 ne not equal
jb 小于时jmp cf=1 时跳转 b below
jnb 不小于时jmp cf=0 时跳转 nb not below
ja 大于时jmp cf=0且zf=0 时跳转 a above
jna 不大于时jmp cf=1或zf=1 时跳转 na not above
pushf 将标志寄存器压栈
popf 将标志寄存器出栈
后面就是中断相关的内容,以后遇到了再看吧