.hd-box .hd-fr

Linux 0.11 第 2 回 | 从 0x7c00 到 0x9000

2022-09-30 20:02低并发编程(闪客)22评

本文来自微信公众号:低并发编程 (ID:dibingfa),作者:闪客

书接上回,上回书咱们说到,CPU 执行操作系统的最开始的两行代码

mov ax,0x07c0mov ds,ax

将数据段寄存器 ds 的值变成了0x07c0,方便了之后访问内存时利用这个段基址进行寻址。

接下来我们带着这两行代码,继续往下看几行。

mov ax,0x07c0mov ds,axmov ax,0x9000mov es,axmov cx,#256sub si,sisub di,direp movw

此时 ds 寄存器的值已经是 0x07c0 了,然后又通过同样的方式将es寄存器的值变成0x9000,接着又把cx寄存器的值变成256(代码里确实是用十进制表示的,与其他地方有些不一致,不过无所谓)。

再往下看有两个sub指令,这个 sub 指令很简单,比如

sub a,b

就表示

a = a - b

那么代码中的

sub si,si

就表示

si = si - si

所以如果 sub 后面的两个寄存器一模一样,就相当于把这个寄存器里的值清零,这是一个基本玩法。

那就非常简单了,经过这些指令后,以下几个寄存器分别被附上了指定的值,我们梳理一下。

ds = 0x07c0

es = 0x9000

cx = 256

si = 0

di = 0

还记得上一讲画的 CPU 寄存器的总图么?此时就是这样了

干嘛要给这些毫不相干的寄存器附上值呢?其实就是为下一条指令服务的,就是

rep movw

其中rep表示重复执行后面的指令。

而后面的指令movw表示复制一个(word 16 位),那其实就是不断重复地复制一个字

那下面自然就有三连问:

重复执行多少次呢?是 cx 寄存器中的值,也就是 256 次。

从哪复制到哪呢?是从 ds:si 处复制到 es:di 处。

一次复制多少呢?刚刚说过了,复制一个字,16 位,也就是两个字节。

上面是直译,那把这段话翻译成更人话的方式讲出来就是,将内存地址 0x7c00 处开始往后的 512 字节的数据,原封不动复制到 0x90000 处

就是下图的第二步。

没错,就是这么折腾了一下。现在,操作系统最开头的代码,已经被挪到了0x90000这个位置了。

再往后是一个跳转指令。

jmpi go,0x9000   mov ax,cs  mov ds,ax

仔细想想或许你能猜到它想干嘛。

jmpi是一个段间跳转指令,表示跳转到0x9000:go处执行。

还记得上一讲说的 段基址: 偏移地址 这种格式的内存地址要如何计算吧?段基址仍然要先左移四位,因此结论就是跳转到0x90000 + go这个内存地址处执行。忘记的赶紧回去看看,这才过了一回哦,要稳扎稳打。

再说 go,go 就是一个标签,最终编译成机器码的时候会被翻译成一个值,这个值就是 go 这个标签在文件内的偏移地址。

这个偏移地址再加上 0x90000,就刚好是 go 标签后面那段代码mov ax,cs此时所在的内存地址了。

那假如mov ax,cx这行代码位于最终编译好后的二进制文件的0x08处,那 go 就等于 0x08,而最终 CPU 跳转到的地址就是0x90008处。

所以到此为止,前两回的内容,其实就是一段512字节的代码和数据,从硬盘的启动区先是被移动到了内存0x7c00处,然后又立刻被移动到0x90000处,并且跳转到此处往后再稍稍偏移go这个标签所代表的偏移地址处,也就是mov ax,cs这行指令的位置。

仍然是保持每回的简洁,本文就讲到这里,希望大家还跟得上,接下来的下一回,我们就把目光定位到 go 标签处往后的代码,看看他又要折腾些什么吧。

后面的世界越来越精彩,欲知后事如何,且听下回分解。

广告声明:文内含有的对外跳转链接(包括不限于超链接、二维码、口令等形式),用于传递更多信息,节省甄选时间,结果仅供参考,IT之家所有文章均包含本声明。

下载IT之家APP,分享赚金币换豪礼
相关文章
大家都在买广告
热门评论
查看更多评论