本文内容:

  • 总线
  • 寄存器

总线

地址总线

一个CPU如果有N条地址总线,那么可以寻找2^N个内存单元

image-20200611211433758

数据总线

数据总线的宽度决定每次传输的数据的位数,比如8086每次可以传输8位,8088每次可以传输16位数据,如果8086想要传输8位以上的数据,就得分开传输,实例如下:

image-20200611211546207

image-20200611211556803

控制总线

有多少根总线就意味着有多少种控制

小结

image-20200611211925112

image-20200611212010180

寄存器

image-20200612165909766

为了向下兼容低位的寄存器,这里可以把AX拆分为AHAL

image-20200612170039415

字节:一个字节占 8 bit 空间

字:一个字占两个字节空间,即 16 bit 空间

物理地址

image-20200612173010641

image-20200612173108860

划重点!!!

物理地址 = 段地址 * 16 + 偏移地址

物理地址 = 基础地址 + 偏移地址

如果段地址确定的话,只能通过偏移地址确定物理地址的话,最多能确定FFFFH64KB大小的物理地址空间

段寄存器

CS:IP

CS为代码段寄存器,顾名思义,是存放CPU要执行命令的段地址的寄存器

CS寄存器和DS寄存器(数据段寄存器是不一样的!

image-20200612174640710

image-20200613231228555

总而言之,过程很简单

就是CPU通过对CS:IP来合成物理地址进行指令读取,

在读取完毕后,IP的值会增加读取指令长度的值,记得,是在读完之后知道指令长度的情况下,才会增加!

从而让CS:IP的地址指向下一个指令的地址开头,如此循环

如果想修改CS和IP寄存器的值的话,该怎么办?

使用JMP指令即可

image-20200613231840740

如果只是想修改IP寄存器的值

可以采用jmp 合法寄存器的值的方式来修改

image-20200613231959592

image-20200613232457498

DS(数据段寄存器)

这里是指数据段寄存器

如果说想读取10000H内存地址处的内容到dl里面,就需要这么执行:

mov bx, 1000H
mov ds, bx
mov bl, [0]

由于DS寄存器的硬件设计原因,不可以直接mov, DS 1000H

需要通过中间寄存器来传递值

一般而言,mov指令格式为mov 寄存器名 内存单元地址

此时如果传递入得内存地址为[0],是指偏移地址为 0 ,但这个只是偏移地址,还需要段地址

此时就需要从DS寄存器来读取我们的段地址,所以说需要提前把段地址从中间寄存器中转到DS寄存器才可以执行

内存中的存储方式

由于一个字是两个字节,内存是连续的空间,所以一个字要占用两个内存单元

一个字的高地址会存储在内存的高地址上,而他的低地址会存储在内存的低地址上

image-20200613233206292

这里存储的数据是4E20H0012H

几个指令

image-20200613235625687

还存在的mov指令:

mov 寄存器, 段寄存器
mov 寄存器, 内存单元
mov 段寄存器, 内存单元

image-20200614000029785

数据段传送

对于内存单元的偏移的是一个字节还是一个字,要看目的操作数的类型

比如,我们的目的寄存器是ax,那么mov ax, [0]传输的是偏移地址在 0 处的一个字

如果目的寄存器是al,那么mov al, [0]传送的是一个字节

小结

image-20200614000520607

image-20200614000534355

栈简介

栈的概念这里就不写了,先入后出,这里列一下一个过程

image-20200614132305965

为了能随时找到栈的位置,CPU通过SS:SP

段地址存放在SS寄存器中,SP中存放偏移地址

任何时候,SS:SP都指向栈顶元素!

push ax的过程

  • 首先SP = SP - 2,栈被抬高,SS:SP指向当前栈顶的前面内存单元,成为新的栈顶
  • ax压入到当前SS:SP指向的内存单元,成为新的栈顶

image-20200614132732678

入栈时,栈顶存高地址往低地址方向减小

不过要注意的是,如果设定10000H~10010H为栈,当栈为空时,此时的SS:SP1000H:0010H

image-20200614133035349

因为前面提到过,任何时候SS:SP指向当前栈顶元素,假设此时栈中有一个字单元124EH,此时的栈结构为:

栈地址 元素 SS:SP
1000CH
1000DH
1000EH 4E <——SS:SP
1000FH 12
10010H

如果此时把这个124EH元素pop出来,SP = SP + 2,即SP = 000EH+ 2 = 0010H

那么新的SS:SP指向不就是1000:0010H?

栈地址 元素 SS:SP
1000CH
1000DH
1000EH 4E
1000FH 12
10010H <——SS:SP

入栈时,栈顶存低地址往高地址方向增加

pop ax过程如下:

  • 首先把SS:SP指向的元素送到ax当中
  • 然后SP = SP +2,新的SS:SP就是新的栈顶

image-20200614133950153

这里要注意的是,pop并不是真的把元素给弹出去了,里面的元素还是存在的,只不过是SS:SP的指向发生了变化,如果有新的元素被push进来,那么就是把原来pop出去的元素覆盖即可

栈越界问题

根据前面所学的东西,这里应该很明白栈在pushpop时候会产生越界问题

push产生的越界问题

image-20200614134506947

pop时产生的越界问题

image-20200614134528788

这里CPU是没法确定栈的上限和下限的,他只能通过SS:SP确定当前的状态,如果说一个程序员写程序,没有控制好数据的读写问题,很有可能出现栈溢出漏洞

pop和push指令

这里前面既然有push 寄存器pop 寄存器

那么肯定还有其他的形式

  • push 段寄存器
  • pop 段寄存器
  • pop 内存单元,如pop [0]
  • push 内存单元,如push [0]

​ 对于一些mov [0], ax等操作

我们可以同理用pushpop来操作

原理是使用mov ss, bx来设置栈的段地址,使用mov sp, 偏移地址来设定偏移地址,这样就可以把一段内存空间设为栈,此时就可以使用pushpop达到mov相同的作用了

不过时刻要记住

Push指令是先使得sp减2,然后让数据传入栈中

Pop指令是先把数据从栈中传入到寄存器,然后sp加2

这俩过程是相反的

小结

image-20200614140604213

image-20200614140624320

参考书籍

《汇编语言-第三版 王爽著》