8086 第二部分
第二章
0 引入
汇编指令不区分大小写
汇编中数字默认十进制,16进制的话要写成MOV AX, 18H
mov ax, 18 ----AX = 18;
mov ah, 18 ----AH = 18;
add ax,18 ----AX += 18;
add ax, bx ----AX += BX;
mov ax 00C5H --- 此时AX为00C5H
add al 93h --- ax为0058h,哪怕低位溢出,也同样丢弃,而不是0158H
1 8086物理地址寻址
CPU在访问内存单元时要给出内存单元的地址,内存单元的存储空间时一个一维的线性空间,而每个内存单元在空间中都有一个唯一的地址,这个地址就被称为物理地址。
但是很尴尬的是,对于8086来说,CPU的地址总线有20位,那么按理来说他的寻址范围有1MB,但是CPU寄存器都是16bit的,他一次也只能处理16位,所以CPU实际的寻址能力只有64KB,这里就有矛盾了。
解决方案
物理地址=段地址 左移4bit+偏移地址 ,注意物理地址唯一,但是段地址和便宜地址可以不唯一
这种方式就是一种偏移寻址方式,基地址=段地址左移4位的结果
比如物理地址 123C8H
可以是1230H + 00C8H,也可以是123CH+0008H组成。
本质就是用两级地址来完成超过能力的事情
2 内存的分段管理内存
内存不分段!!!
分段任务是由CPU完成的,内存只是一个一维连续单元
这样的好处是明显的,同一内存能够适配不同CPU,所以同一个内存会有多个不同的分段方式
CS: code segment
代码段寄存器
3 Debug的使用
- 启动debug
将工作目录挂载到相应文件夹,我这里是d:\codeprojects\8086
,也就是让dos认为我这个目录是c盘
-
用R命令查看改寄存器内容
-r 查看寄存器内容,最右边可以看见相应的ASCII码
-r ax 改变寄存器内容
-
D命令查看内存内容
-d 预设地址内存处128个字节的内容,继续-d 就会继续查看下个128字节地址内容
-d 2000:0000 查看2000:0000起始的128字节内容
-d 2000:0 F 查看2000:0000起始的F个数据
-
E命令改变内存中的内容
-e 2000:0000 12 34 56 指名地址后,后面跟上16进制数据
-e 2000:0 以逐个询问方式进行修改,空格表示接受并继续,回车结束
-
U命令将内存中的机器指令翻译成汇编指令
- A命令 以汇编指令格式在内存中写入机器指令
先用-r指令查看 CS和IP寄存器位置,比如CS位073f
-a 073f:100
然后开始输入汇编指令
mov ax,bx
add ax,bx
之后可以用 -d 073f:100查看数据
-u查看机器代码
-
T命令执行机器指令
从当前PC计数器内容开始执行,逐条执行
从寄存器CS:IP存的指令开始执行,不断-t就会一条条执行下去 -
Q 退出debug
4 CS、IP和代码段
CS:代码段寄存器 IP: 指令指针寄存器
CS作为段地址,IP作为偏移地址,经过位址加法器形成20bit地址
5 jmp指令
修改CS:IP的值,控制CPU执行我们的目标指令
方法1:直接rcs,rip
方法2:jmp指令
怎么使用
- jmp 段地址:偏移地址
比如JMP 2AE3:3
段地址会修改CS,偏移地址会修改IP - 如果要只修改IP寄存器
jmp AX
类似(mov IP,AX
,当然这个mov操作是非法的)
6 内存中字的存储
字的概念:计算机进行数据处理时,一次存取、加工和传送的数据长度称为字(word)
8086CPU,16位作为一个字。64位机器,64位为一个字
8086字的存储方式:高8位高字节,低8位低字节
字单元
由两个地址连续的内存单元组成,存放一个字型数据(16位)的,就能称为一个字单元
同样是高位地址存高位字节
对于上图,注意以下几种问法的区别
0地址单元中存放的字节型数据是:20H
0地址字单元存放的字型数据是: 4E20H
7 用DS和[address]实现字的传送
在8086机器中,内存地址要由段地址和偏移地址一起给出,这里提供了一种解决方法,就是DS寄存器+[数据]
//语义是将内存中10000H(1000:0)的数据读入AL寄存器
MOV BX,1000H
MOV DS,BX
MOV AL,[0]
//将数据写进相应内存
MOV BX,1000H
MOV DS,BX
MOV [0],AL
注意下面两种写法,第二种才是对的,8086不支持直接对ds寄存器赋值,CS、IP寄存器也一样
8 栈及栈操作的实现
现在CPU都存在栈设计,8086可以用栈的方式访问内存空间,某一部分内存可以当作栈来使用
8.1 8086栈操作
注意8086是以字为单位对栈进行操作
PUSH AX :将ax中的数据送入栈中
POP AX :将栈顶取出数据送入AX
8.2 CPU是如何知道一段内存被当作栈来使用呢?
8086中有两个与栈相关寄存器
- 栈段寄存器SS --存放栈顶的段地址
- 栈顶指针寄存器SP --存放栈顶的偏移地址
所以任意时刻 SS:SP
都指向栈顶元素
所有涉及到栈的,都要考虑栈溢出威胁,可惜8086这种汇编是没有这部分检查功能的,程序员要自己小心。
9 关于“段”的小结
- 编程时CPU会把一组内存单元划分为一个段,段的起始地址一定是16的整数倍。