03(分段,内存,地址加法器,寻址,机器码拆分,8086手册)

分段,机器码,也就是指令拆分

分段

分段其实是十六位CPU一种非常独特的一种访问内存的方式,发展到了32位就没有这种东西了

分段思想各种编程中都有体现,比如内核,某种程度也能体现分段的这种思想

十六位CPU的分段,访问内存的地址转换方式

学完这节课什么叫做生产力限制了想象力

1、

16位他能操作的最大长度是2个字节,如果是32位,他能操作的最大长度是4个字节

2个字节的表示范围有多大?

2的16次方,0到65535

16位,最大FFFF

如果说它现在有个1FFFF,

这个地址他能访问到吗??

这个十六位的你最多给FFFF,在加个1是不是就变成0了,所以你没法访问这个长度

所以CPU如果16位的话,他能够最大64K,2的16次方,65536,实际上就是64K

2、

刚才有同学提到了8086他访问内存是多大的?

其实8086真正的他可以允许访问最大的内存是1M

1M是多大呢?(程序内存大小0xFFFFF)

这个就是1M的范围

2的20次方

8086这个CPU他允许最大内存是1M,

这里有个很矛盾的地方,,

他的数据操作的最大长度,他是16位的,按理说他的访问范围是64K,但是他的内存

十六位只能访问这么大,

剩下的怎么访问到的呢?

把这个内存分成一段一段的

访问的时候我可以拿出段的地址,在加上一个偏移,通过这种方式访问内存

这样的话,我想访问高地址,我就可以直接把这一段的内存基址给它变了,这样段内偏移就不用特别大,反正一个word就够了,可以访问比较高的地址段

段基址 *0x10

这里有个问题,段内的偏移我门可以用一个word表示,但是段的基址

比如我想访问1FFFF,段的基址设置成1234,段内偏移

这个段基址加上这个偏移,是不是就能达到这个地址1FFFF

发现没有,这个能用一个word来表示吗

这个段位于内存高地址的时候,这个内存好像也不能用一个word表示是吧

做法很简单把最后一个0去掉

只存前面的,把0去掉

怎么算的呢?

1000*10+FFFF=1FFFF

(这里的*10转换成十进制就是16)

这里隐含,每个段的段基址他其实需要跟16个字节对齐的

因为你都要乘以16

分段寻址

这个是刚才讨论的问题

十进制16

2的4次方,左移4位,加上段偏移

073F*10+0100=074F0

063F*10+1200=075F0

043F*10+0120=04510

段基址+段偏移

中间冒号分开

EA:

enable address

有效地址

内存分布

一个段最小能有多小?

不同的段,段基址之间有16个字节,

最小一般是16个字节

一个段最大,2的16次方,就是64K

在8086里面段与段之间要隔开的,在8086的内存里面他的分段是特别灵活的,他允许段和段之间可以重叠

也可以段与段之间不重叠

这个都是靠程序员去管控的

设置成重叠就是重叠的,设置成不重叠的就不是重叠的

一般我们写程序的时候不让段重叠

所以你要地址重复的话,

这个有三个段寄存器都能够拿到

这个时候写代码就要注意了

这得算好

debug没有加载任何程序,默认出来都是四段合一的

在段不重叠的情况下,如果说每个段是10个字节,可以划分出多少个段?

65536个

如果每个段达到最大64K,段与段之间不重叠,可以划分多少个段呢?

可以划分16个

划分段

段与段之间是没有重叠的

程序员自己去安排这个段

写十六位程序先把自己栈空间,堆空间,代码区,数据区 开辟出来,然后在开辟显存器

问题:一个物理地址是否只能由一个逻辑地址表示?

肯定不只是一个

所以一个物理地址可以由任意个逻辑地址表示

段基址064f+1000最后算出来是074f0

段基址073f+100最后算出来的也是这个物理地址

所以一个物理地址可以由多个逻辑地址去表示

测试 逻辑地址分段,修改,物理地址

现在这里值变成了123456789

然后 我门换一个073f:100

两个不同的逻辑地址,但是最后同一个物理地址

也能访问到这个物理地址

004f:7000

段基址也可以是074f,偏移0也可以算到物理地址

分段除以16要能除尽

除16除不尽,所以这个地址不能用作段基址

不是随便给个段偏移就可以了,一定要是能够段基址除16能除尽的

物理地址多个逻辑地址表示,分类原则一般是不会碰到的

一般设的时候都不会把几个段重叠放在一块

了解分段之后,我们就要了解一下dos系统的内存分布了

dos内存分布

dos系统,就是我们说的8086虽然提供了1M的内存,但是也跟我们32位编程一样,也不是说,这1M都是给你访问的

32位编程系统提供了4G的内存,但也不是说4G都是你的,2G也不都是你的啊,掐头去尾,这个也是

大致了解一下内存的分布

00000-00400 中断向量表

相当于DOS系统API的地址区,

介绍向量,介绍中断的时候

00400-00500 bios数据区

00500-0A000 系统代码

dos系统代码在这里

0A000-A0000 可以用的内存

A0000-FFFFF 系统一些其它的资源

掐头去尾总共600K的样子

这600K够干什么?!

当时设计8086的1M多大啊

当时单任务,当你跑你自己代码的时候,其实系统是不跑的

你跑完之后,在跑回系统,系统才是正常运行的

所以那个时候病毒很多

,因为只要你的代码获取了执行权限

是不是整个内存随便访问

然后一点权限都没有

所以那个时候只要程序跑起来了,刷XX了

段寄存器

ES那个段需要就给那个段用用,常用串操作

SS堆栈段

命令练习

当用这个段的时候时候把ds改过去,他是可以改的

两个一块用的时候,这个可以是es,额外的帮忙的

1M的内存寻址需要多少根线(引脚)?

一根线代表1位,

所以虚拟1M内存需要20位,所以就需要20根地址线

什么叫引脚?

就是他内部的线,露在外面的

这个全封闭在CPU里面不跟外部接触吧

读数据写数据也是通过这几个线

这个线是复用的,指的这个引脚的功能不是单一的,他还可以用作地址,设置地址的时候这几个线用上了

还包括这几个

CPU线

数据总线16位的,也就是这一块,他跟外面读数据的时候一次性只能读16位,写也只能往外写16位

8位指令队列,要给EU做译码用,8位意味着一次性读的一个字节

更清楚的告诉你们,他每次解析指令是一个字节,解析的,因为8位8位读的

地址线到这里变成20位

首先段寄存器,在跟其它一些段偏移做加法,得到地址

这个东西不干别的就是用来算地址的

所以你看8086,本身16位CPU只能寻址到64K,所以为了寻址到1M,专门在CPU里面加了电子器件,专门算地址

当然算物理地址

地址加法器

逻辑地址转换物理地址,就干这一件事

他的输入是两个16位

或者输入是两个word,然后输出是一个20位的地址值

寻址

到了32位多一种

比例因子

取数据

数据到哪里去取,告诉CPU数据到那个地方去取

那么这个数据可以存到那呢?

内存里面可能会有,寄存器里面可能会有,

寄存器当程序跑起来的时候已经加载到内存了

还有机器码本身,指令里面本身就有数据

取指令这是一条完整的指令

他译码的时候是不是在指令中就可以吧这个数据就拿到了

需要在去寄存器里面取到1234吗?

还是去内存里面取1234?

1、立即寻址 mov al,80h

立即数寻址演示视频:

立即数寻址.gif

C/C++里面叫整数常量,到汇编叫立即数

2、寄存器寻址 mov cl,dl

数据存在寄存器中,要拿数据要从寄存器里面去拿数据

栗子:

xor ax,ax

mov cx,10

mov dx,1

:Lable1

inc dx

cmp dx,cx

jep Lable1

dx变成1234了

这个是寄存器寻址

寄存器寻址演示视频:

寄存器寻址.gif

立即数

B0本身要给AL赋值了

他读完B0之后知道要给AL赋值了,他要等34过来

然后之间存过去就行了

寄存器

mov ds,ax

ax,ds的信息存在这里了

待会拆指令的时候知道有些位是表示存东西的,有些位是表示数据指令的

操作码之间表示操作数

寄存器寻址,需要注意的是

段寄存器之间不能赋值

通用寄存器和段寄存器之间互相赋值没什么事

段寄存器不允许直接赋立即数

同样的

段寄存器之间也是不能够赋值的

因为他没设计这样的线路啊

这是段寄存器与段寄存器之间不能赋值

不能直接赋立即数

所以你要赋值的话需要拿一个通用寄存器做中转

指令指针寄存器不能用作寻址

这类通过某些指令,跳转函数调用,这一类的指令去改他的值

返回ret

他不是说绝对不能改,学了更多指令就可以改了

学了流程转移指令在看

都不能用ip寄存器运算

3、直接寻址 mov al,[1064h]

首先数据是在内存里面

然后我们通过段偏移之间获取这个数据

实际数据是ds

ds是2000H+个0是段基址,

从这里取出45H这个值

然后这个值存到AL里面

这个是直接寻址

ds默认2000H

r dx命令是这样修改寄存器的

这个是机器码

这里指明1064包括内存里面存的值7845

ax的值变成了7845

直接寻址演示视频:

直接寻址.gif

为什么不走指令队列?走地址加法器?

指令才走这里,这里是8位的;这里才是16位的

所以他只能通过这个线

4、寄存器间接寻址 mov ax,[si]

首先数据是存在内存里面的,段偏移是存在寄存器里面的

所以他是先要取寄存器,寄存器里面取出段偏移然后在算内存地址,在从内存里面取出数据

这叫做寄存器间接寻址

可以用于间接寻址的寄存器这四个

ds 3000

si 2000

先从si取出2000然后跟ds算出来物理地址,然后在到内存里面把这个数据取出来,然后给了ax

演示:

使用通用寄存器寻址

这个地址(2000:1064)是7845

(ds直接从寄存器取就是段基址)

使用bp寄存器寻址

cx是00

分段

堆栈

bp默认都是ss

si,di默认都是ds


演示视频:

寄存器寻址.gif

5、寄存器相对寻址 mov [si+10h],ax

相对寻址他其实也是数据在内存里面,然后稍微跟间接寻址不一样的地方是

这里寄存器加上一个偏移

真正的段内偏移是寄存器和立即数相加后的偏移,他是真正的段内偏移

相对寻址的寄存器也是这几个

两个B,两个I

演示:

debug把这个位置算出来了

把数据写过去了

视频演示:

寄存器相对寻址.gif

这个写法跟演示的写法不一样

si没起作用,汇编器出了问题

这个组合比较灵活,一般就这种写法

6、基址变址寻址 mov ax,[bp+si]

段内偏移是由两个寄存器算出来的

这里提到的寄存器也是由相对寻址里面的四个寄存器来,BX,BP,SI,DI

但是组合要注意,

只能由两个B,和两个I组合

B叫做基址寄存器,I叫做变址寄存器

演示:

两个B和两个I之间可以随便组合

但是B跟B不能组合,I跟I不能组合


演示视频:

基址变址寻址.gif

花式的写法

除了地址加地址加法器,其它的四则运算都是在ALU

7、基址变址相对寻址 mov ax,[bx+di+100h]

其实相较刚才的可以加偏移

其实这种方式是用来访问数组的

演示:

只能处理16位,写的更多处理不了

访问第一行

访问第二行

访问第一行

访问第二行

访问数组

演示视频:

基址变址相对寻址.gif

带相对的都是加立即数

第8种32位汇编在讲

幺蛾子 寻址内存不能到内存

之前看的所有例子都是内存到寄存器,或者寄存器到内存,寄存器到寄存器

但是没有内存到内存的指令

没见过那个处理器支持内存到内存的

机器码

机器码 汇编语句

助记符

汇编语言操作数可以有一个,可以有两个,最多两个

u的时候读机器码,翻译成汇编

通用CPU在译码的时候也是读的机器码

机器码里面存了指令,操作码,以及操作数

机器码有长有短,还存长度

intel指令集,都是一种变长的指令集

arm其实是定长的指令集

两种指令集设计的思想,和设计的思路是不一样的

这种变长的指令集一般我门也叫做复杂指令集,arm定长的叫做精简指令集

复杂指令集

两种指令集,是两种设计的方向,像复杂指令集,希望更多的功能由硬件完成,就是硬件给你提供更多的功能,

x32后面会学到多媒体指令集

但是指令集他能支持,他的功能非常强大,支持128位,16个字节去做,同时加减乘除运算

就是每个字节做加减乘除,或者4个dword同时做加减乘除

他可以做到什么呢?

对你图片反转,一条指令就可以把图片进行反转

功能强大,显卡挖矿,指令非常多,

精简指令集

更多的功能由程序员去完成,他只给你提供一些基本的指令,常用的指令

复杂指令集,百分之八十的功能,20的指令;80的没用上

精简指令集,就是百分之八十的指令

那个地方存了机器码,那个地方存了操作数?

这个方式适合分析任何的指令

操作码一样的,

助记符 目的操作数,源操作数

变化的是源操作数

所以我门对它进行拆分就能找出来,那个地方代表的源操作数

机器码拆分

这里不一样的位置,源操作数

mov dx,bp

推测是正确的

mov寄存器都是两个字节的

add变成01了

常数,内存

这是同一个指令

虽然助记符这里叫做mov但是到了机器码还是有区别的

000是ax

这是不是代表寄存器呢??

跟这里不一样

估计他用了另外一套索引方式

BX就是111,BP就是110,SI就是100,DI就是101,,,

这种组合应该是000

mov bx,[dp+di+1234]

两个字节就应该是10,1234是两个字节

接下来bx应该看上面,因为ax压根不能作为寄存器寻址011

bp+di

后面就是立即数

一样的是吧

所以通过验证我门的推断是正确的

我们就可以对它进行解析了

通过这种方式可以给任何处理器去写反汇编引擎

8086手册

这些东西在intel手册有详细的说明

还可以在拆,

d是啥意思呢?

d是1就到寄存器,d是0就来自寄存器,数据的方向

w是1的话,是一个word,0的话就是byte

mod是啥呢?

mod是 11的话,r/m就是一个REG寄存器字段

00说明偏移是0,高字低位被舍弃

mod是不是这一列

8B,mod是两个位

reg r/m

11作为寄存器字段,

这里11是不是作为寄存器了

01的话 DISP低字扩展到16位的一个偏移,如果是01他就是一个单字节立即数,单子节他需要扩展吗?双字节本身就是16位

10高位和低位都有的偏移,双字节

DISP立即数要看mod

EA Effective Address (逻辑地址)

知道EA是啥,到时候写IDA脚本帮助文档到处都是EA

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容