这是学习汇编语言的第二章的总结。
书上的内容(页数)虽然比第一章多,但是如果第一章理解完全后,第二章其实就是对第一章部分内容的深入操作。这一篇主要就把一些操作总结一下。
我们已经理解了存储器的物理地址:把所有硬件的存储单元,按照一定规定,线性排列,组成一个大的逻辑存储器,然后给每一个存储空间分配一个唯一的物理地址。
第二章主要就是从8086CPU的角度,去看一下,CPU如何玩弄内存
- CPU主要配件
- 运算器
- 控制器
- 内部总线
- 寄存器
寄存器就是这一章的主角,CPU和内存交互时,需要临时保存各种数据或者指令(都是1和0),这些数据都是存在寄存器里的。8086是一个16位的CPU,他的寄存器都是16位的,也就是说能存16位二进制数据,4位十六进制。
这里都是使用8086CPU来作为例子
寄存器分为几种,我们一个个来看
-
通用寄存器
AX,BX,CX,DX 这四个是通用寄存器,用来存放一般性数据,8086CPU是十六位的,上一代CPU是八位的,为了良好的兼容性,我们可以用AH去表示AX的高8位(High),AL去表示AX的低8位(Low)这里要注意一下:假设AX = 1100 0011 0101 1010 其中1100 0011 是AH 而 0101 1010 是AL
这里嵌入一些我学习高级语言后的一些看法,错了请大佬拍砖。CPU如何操作,或者读取数据(二进制)其实都是我们告诉他的,对于底层一些已经写入CPU内部的规则,或者是应用层我们写的代码都是这样的。应用层数据会有int ,double,long 等等,其实就和AX和AH一样,我告诉你怎么处理这个数据,CPU就要按照我的规定去做。比如 char类型规定了是1个字节,然后我把这1个字节数据存进内存里,他就会在内存里占用8位二进制的大小,计算机看这8位数据,都是1和0,他就必须按照我的要求,完整的提取8位数据,而不是前4位+后2位,或者多读几位,都是不可以的。多了不行,少了也不行。这都影响提取数据后,换算的正确性。
当我们写入寄存器时,也必须严格按照字节位
1、AX = 0xFFFF AX+0x0001 = 0x0000
2、AX = 0x1234 AH = 0x12 AL=0x34
3、AX = 0xFFFF AH + 0x0001 => AX = 0xFF00 (溢出的会被截掉,AX,AH同理)
4、截掉的数据并不是丢弃了,这里暂时不讨论这个。 -
字(word)
字是一个新的单位,1个字等于2个字节,正好是一个8086CPU,通用寄存器的大小 -
汇编指令
- add
add ax,1 => ax = ax + 0x1
add ax,bx => ax = ax + bx - mov
mov ax,1 => ax = 0x1
mov bx,ax => bx = ax
- add
-
8086CPU是16位CPU,但是他的地址总线是20位的,那就代表他的寻址空间更大了,提高了逻辑存储器的上限。
我们来理一下关系:CPU内部指定寄存器会存着一个物理地址,然后通过地址总线定位到逻辑存储器的一个存储单元,然后控制总线给指定的硬件发送指令,最后数据总线进行数据传输。问题来了:16位的寄存器,怎么发出一个20位的物理地址
这里 8086CPU就出现了分段的概念
物理地址=段地址 左移4位 + 偏移地址1、段地址是什么?
段地址是一个4位十六进制的数据,假设为0x1234,按照上面说的左移4位(二进制位)就会变成0x12340多了一位哦。
2、偏移地址是什么?
偏移地址也是4位十六进制数的数据,假设为0x1234,那他就是0x1234
3、组合
0x12340+0x1234=0x13574
一共只能有5位十六进制,因为地址总线是20位二进制也就是5位十六进制。那谁来确定段该怎么分?
这个是靠CPU来决定的,这只是CPU来表示20位十六进制物理地址的方式,并不是真的把内存分段。所以一个物理地质,可以通过多种多样的分段方法来体现。
-
段寄存器 CS
CS也是CPU的寄存器,CS是用来存储段地址的,也是16位的 -
指令指针寄存器 IP
IP也是CPU的寄存器,是用来存偏移地址的。8086CPU,会从CS:IP处开始执行一条指令,CS和IP有点大方向和微调的感觉。IP只有16位,如果CS不变,IP变化,最多也只能搜索到65536个内存单元。
CPU会认为CS:IP指向内存单元都是指令而不是数据, 如果已经看过书了,会发现读取一次CS:IP处的指令后, IP的值会自动增加,至于如何改变,应该是根据读取的是什么指令。
具体的合并处理过程,记得看书哈,我这里简单走个图
CS:IP=》地址加法器(组成5位十六进制)=》地址总线=》内存
返回数据之后,IP的值会自己根据接收的数据指令,自动修改自己的值。 -
汇编指令
- jmp
jmp可以用来修改CS和IP的值 - jmp 100:99 => CS = 0x100 , IP = 0x99
- jmp还可以单独修改IP的值
jmp+合法寄存器:jmp AX => mov IP,AX
注意,mov命令是不能修改IP和CS的,因为8086CPU不允许。
- jmp
CPU唯一遵循的就是执行CS:IP所指向地址。
第二章剩下部分都是,实际操作问题,这里我大概说下我遇到的几个问题。
书上一些使用Debug去熟悉一些命令,第一,值都未必和你书上看到的一样(除了计算答案),
第二,书上实验会有一部分是让你往显存里直接修改内容,可能因为我是用模拟器的关系,所以显示不出来。
上面说的 add mov jmp 都是汇编指令,需要汇编编译器翻译成机器码,CPU才能看懂,我们还能通过Debug软件来直接测试学习8086CPU工作原理。
- Debug命令(这里就列一下,具体看书,书上有图)
- r 查看寄存器的值
- r 寄存器 可以修改寄存器的值 “r ax” = 修改寄存器ax的值
- d [xxxx:xxxx] [多少个] 用来查看逻辑存储器 “d 1000:100 1f” = 查看0x10100 处开始32个内存单元的值 (我用的bochs+freeDos模拟,这个命令后面不能加多少个。。。)
- e 修改内存的值
- u 查看指定内存内机器码对应的汇编指令
- a 给内存直接写入汇编指令,add mov jmp这种
- t 执行CS:IP 指向的存储单元