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,所以同一个内存会有多个不同的分段方式

image-20221015181243784

CS: code segment 代码段寄存器


3 Debug的使用

  1. 启动debug

将工作目录挂载到相应文件夹,我这里是d:\codeprojects\8086,也就是让dos认为我这个目录是c盘

  1. 用R命令查看改寄存器内容

    -r 查看寄存器内容,最右边可以看见相应的ASCII码

    -r ax 改变寄存器内容

  2. D命令查看内存内容

    -d 预设地址内存处128个字节的内容,继续-d 就会继续查看下个128字节地址内容

    -d 2000:0000 查看2000:0000起始的128字节内容

    -d 2000:0 F 查看2000:0000起始的F个数据

  3. E命令改变内存中的内容

    -e 2000:0000 12 34 56 指名地址后,后面跟上16进制数据

    -e 2000:0 以逐个询问方式进行修改,空格表示接受并继续,回车结束

  4. U命令将内存中的机器指令翻译成汇编指令

image-20221015213619429
  1. A命令 以汇编指令格式在内存中写入机器指令

先用-r指令查看 CS和IP寄存器位置,比如CS位073f

-a 073f:100

然后开始输入汇编指令

mov ax,bx

add ax,bx

之后可以用 -d 073f:100查看数据

-u查看机器代码

  1. T命令执行机器指令

    从当前PC计数器内容开始执行,逐条执行
    从寄存器CS:IP存的指令开始执行,不断-t就会一条条执行下去

  2. Q 退出debug


4 CS、IP和代码段

CS:代码段寄存器 IP: 指令指针寄存器
CS作为段地址,IP作为偏移地址,经过位址加法器形成20bit地址

5 jmp指令

修改CS:IP的值,控制CPU执行我们的目标指令

方法1:直接rcs,rip
方法2:jmp指令

怎么使用

  1. jmp 段地址:偏移地址
    比如 JMP 2AE3:3
    段地址会修改CS,偏移地址会修改IP
  2. 如果要只修改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中有两个与栈相关寄存器

  1. 栈段寄存器SS --存放栈顶的段地址
  2. 栈顶指针寄存器SP --存放栈顶的偏移地址

所以任意时刻 SS:SP 都指向栈顶元素

所有涉及到栈的,都要考虑栈溢出威胁,可惜8086这种汇编是没有这部分检查功能的,程序员要自己小心。


9 关于“段”的小结

  1. 编程时CPU会把一组内存单元划分为一个段,段的起始地址一定是16的整数倍。
posted @ 2022-11-13 16:05  wenli7363  阅读(120)  评论(0编辑  收藏  举报