汇编教程4:寄存器CPU工作原理2
最近在网上看了长篇小说<<疯狂的程序员>>。。嗯不错不错,看来这做程序员的人还大多有些相似的,不过每个人却还是有些不同的,就象我。。诶到现在还是一无所有,人财两空啊~~~~~~命苦不能怪政府。。
上一篇 寄存器CPU工作原理1,给大家介绍了几个寄存器,那几个寄存器因为是最常用的所以也叫通用寄存器,相信大家对这寄存器还是有了一个感性的认识了,但是CPU不能够只访问寄存器的,它要做更多的事情,比如读取内存。这应该说是CPU的基本功能之一吧,所以我们不了解下CPU访问内存的方法确实有点那个啊。。。 既然这样我们还是有必要了解下的。。。。。
CPU要访问内存它必须给出内存单元的地址,同时这些单元都是一维线性的。每一个内存单元都有一个唯一的地址。。这在前面的章节有所提及,那么CPU是怎么样给出内存单元的地址呢??想要了解这个问题,我们还得看看CPU的结构。。
我们通常说的8086CPU是16位的,那么这个16位代表了什么概念呢? 这个嘛。。 概括起来的讲啊主要是这几点。。
寄存器一次最多只能处理16位的数据。
寄存器的最大宽度为16位
寄存器和运算器之间的通路为16位
但是问题就来了,8086有20位地址总线(20位地址总线的寻址能力就有1M了),而CPU内部只能够处理16位的数据那改怎么办呢??这个问题嘛,当然不可以浪费了地址总线对吧。。~~如果是地址总线也改成16位的那么我们的CPU寻址能力就只有64K了,那可是天壤之别啊。。当然的想个办法对不。。别人说intel里面的人都是天才,从这方面说的话还是有些道理的。。他们想到了在CPU内部做一个加法器来进行合成一个20位的物理地址。。那么合成过程是怎么样的呢??嗯,,,好的请听我细细道来。
首先CPU中的相关部件(这个部件我们马上要提到)提供2个16位的地址,然后送入一个叫地址加法器的部件,然后地址加法器再把两个地址合成为一个20位物理地址。。那么现在问题又来了对吧。。。他是怎么样合成物理地址的呢??没有关系这里有个公式。。。套公式总是比想问题简单些的。。。额。合成地址的规则是这样的:
物理地址 = 段地址 * 16 + 偏移地址。。
毛主席说过,实践才是硬道理啊,给大家套个公式就明白了,比如现在CPU要访问内存地址单元124C8H的内存单元,那么我们就可以让段地址为1240H,然后让偏移地址为00C8H,套用公式就比较简单了:
124C8H = 1240H * 16 + 00C8H
注意拉,这里别弄错了,这里我们讨论的数据都是16进制的,所以*16只是把小数点移动了一位而已,嗯。。是不是已经感觉到了16进制的好处了。。当你在感叹16进制是多么好之余有没有想过。。我刚才写的那公式里面讲了什么。段。。段地址。。什么的!这个段地址又是什么概念呢?? 千万别以为是一段一段的地址啊!,其实内存里面是绝对没有分段的,分段只是来自CPU自己。其实分段以后是有好处的,这样我们就可以把一些连续的内存当作一个段来使用,套用上面的公式,段地址不变。。只是改动偏移地址。。哈哈这样就方便多了。我们知道偏移地址也是16位的,那么一个段最长呢也只能有64KB而已,明白了吗? 以为偏移地址只能够表示64KB的内存而已。。。
前面我们讲到了”CPU的相关部件提供两个地址”,这么一句话。。那到底是什么东西在提供段地址呢??又是什么东西提供偏移地址呢??,这又不得不让我想到了寄存器,回忆我们前面学习的(应该还不至于忘记吧)4个通用寄存器,那么是不是CPU内部只有那么多寄存器呢?不是的。。呐。我这里就再给你说一个寄存器。这个寄存器就是专门用来放段地址的,它就是CS寄存器,不过好像叫寄存器就俗了些,不可以体现出它和其他那些寄存器的区别来,因为那些寄存器都是放一般性数据,,这CS寄存器可就不同咯。。所以又给它改个名字,就叫段寄存器吧。。这样理解应该比较好理解吧!!
现在还有个小问题,我们有了一个叫CS的段寄存器,,那还得有一个放偏移地址的寄存器啊,这次倒霉的就是CPU中一个叫IP的寄存器(嗯,别和IP地址的IP弄混了)。。啊,原来是这样啊。现在是万事俱备只欠东风啊。。就让我们来套用这个公式吧。。
物理地址 = CS * 16 + IP
就这样,给出了物理地址,事实上当你为CS为什么不叫EX或者其他的名字的时候,我得告诉你一个天大的秘密:
在8086的CPU上,任意时刻,设CS中的内容为M,IP的内容为N,那么8086将从内存:
M * 16 + N 单元开始执行。。
你可能不以为然呐,这有什么了不起啊,我跟你说这就错了,有了这玩意可以玩的事情可就多了。。你想啊我们想让CPU执行一条指令我们要怎么办呢? 想到了吧,嘿嘿。。让我值得高兴的是,我比你先想到~~~~我们只要设 M * 16 + N 的值为我们想要的内存单元地址那不就得了吗? 对的,确实是这样。。
在任意时刻 CPU将CS : IP指向的内容当作指令执行
为了让你有个更感性的认识我非常有必要举个例子,这是毛主席说的,实践才是硬道理啊,比如我在 内存20000 -20003处有条指令,那么我们想让这条指令执行一下该这么办呢?我想应该是这样的
1。 让CS : IP的值指向 20000处
2。 读取并执行指令,同时IP值要加3
我说的第一点可能比较好理解了,可为什么要加3呢,其实是这样的,你想想啊。。。CPU从20000处开始读取指令,读取到指令后就会返回,然后呢执行,CPU在执行完了这条指令后当然知道这条指令是占几个字节,这里是3个字节。。所以CPU就会把IP的值加3。。。嗯,明白了吧,原来是这样啊。
知识这东西啊,确实是好东西。当然你得先把它学会对吧。。现在让我们回想一下,那个电脑为什么在一按电源就会呼啦啦自动执行指令。。那么我们由此可以判断出,一定是有什么东西在修改着CS : IP的值对吧。。那么事实上是这样的。。
8086在加点启动后(或者重启了电脑) CS : IP的值被分别设置为CS=F000H, IP=FFFFH也就是说CPU在启动的时候从FFFF0H单元开始执行第一条指令,有趣吧。。
所以我们可以得出结论:
想要让指令执行必须让CS:IP指向它,反过来,一条指令如果被执行了,那么CS:IP一定指向过它。。
是不是已经按耐不住了,忍不住想写几条指令给CPU执行了??事实上我是一个不喜欢调人胃口的人,但是此时此刻我不得不提醒你,你还记得mov, add。指令吗?不会那么快就把这两条指令忘了吧,如果忘记了。那么你应该再回头看看 寄存器(CPU工作原理1), 如果你还记得那么就比较简单了,例如我们还是在内存20000-20003处有条指令,那么我们可以这样写代码:
mov cs, 2000H
mov ip, 0H
如果你这样写的话,是要出错的,因为intel公司不给你这样干,这样写的指令是错误的。。你可能想问下为什么不行,那么我可以给你电话,你打电话去intel问下就清楚了,那么既然intel不给我们这样干,他总的提供让我们怎么修改CS和IP的值的方法吧,那么我可以明确的告诉你,方法是有的,就是用另外一条指令,它就是 jmp,使用方法:
同时修改CS 和IP的值: jmp 段地址 : 偏移地址
jmp 1000:2
只修改IP的值: jmp 某一合法寄存器
jmp ax ‘这条指令执行的效果和 mov ip, 0H的效果差不多
如果你看到了这里,并且前面的教程你都看了,并且明白了,那么我不得不佩服你的勇气,与毅力,好好努力,相信自己一定可以把汇编学好的。相信你看到这里也开始心里甜了吧,很多奥秘开始向你解开,我当初就是学到这里的时候想,我一定要把汇编学下去,并且要学好。。相信你也是一样,下一篇我就要给大家将debug的使用了,虽然那东西简陋但是还是有必要了解下的。。因为它简单,学起来方便。。OK今天就到这里吧,晚上2点了!!