首先来看第一条关键汇编指令:rep movw

Bootsect代码详解

关于这个movw指令,查了网上很多说法,这里我调查的情况是:在INTEL 80386的数据手册中没有movw指令,只有movsw指令。

按照之前学习的内容,bootsect使用的是intel的as86汇编器编译,as86的mov语法是mov Destination Source;从第47行的mov语法看确实是as86汇编器语法。而movw是GNU as汇编器(AT&T)支持的指令关键字。显然,这里是书中的一个错误。但是,这段程序似乎可以在BOCHS中编译通过,此处是个关于AS86与AT&T汇编器相关知识的一个入口,暂且存疑了。

 

关于movsw可以参考下面80386手册中的解释:

Bootsect代码详解

MOVS是个字符串指令,将ESI指向的字符串元素移动到EDI指向的位置处。movsb/movsw/movsd分别可以对字节、字和双字进行操作。目的段寄存器不能被段覆盖前缀覆盖,源段寄存器可以被覆盖。【段覆盖前缀】。即目的段寄存器只能使用ES,不能使用其他的寄存器代替。源段寄存器是DS,可以被替代为其他的段寄存器。

movs指令和REP前缀一块使用,实现的是内存到内存的块传输。该操作需要初始化ECX、ESI和EDI寄存器。ECX指定了具体的字节、字和双字个数。

第三点是DF标志位,方向标志位,当DF=0时,复制操作的方向是从第一个元素到最后一个元素,步长为+1;当DF=1时,复制操作是反方向进行的,步长为-1。CLD指令会将DF置为0,STD指令将DF置为1。

说明:具体的段覆盖前缀参考下图:

Bootsect代码详解

i386有些默认的段寄存器是不能被替换的:

Bootsect代码详解

比如上文提到的ES用于目的字符串,SS用于堆栈指令,CS用于指令获取操作等。

此处分割线。

继续向下分析代码:

Bootsect代码详解

实地址模式下内存地址0x07C0:0000处的代码已经被成功的复制到内存地址0x9000:0000处。下面再执行后续代码,CPU就直接跳转到0x9000这个段地址处了。jmpi(JMP intersegment)是实地址模式下的段间跳转指令。该指令执行后CS==0x9000,IP==go。因此,后续操作的ds es和ss段皆设置成了0x9000。

这里需要重点说明下此处的堆栈操作,正如上图书中所示,后续牵扯到了出入栈和call调用操作,需要设置堆栈。堆栈是通过SS:SP来确定内存地址的,SS已经被设置为0x9000,那么SP应该设置在哪呢?

Bootsect代码详解

答案:根据上篇文章的内存map可知,0x90200开始将会存放大概4个扇区即(4*512字节)的setup可执行代码,加上bootsect的512字节也就是0x90A00,考虑到堆栈是sp指向堆栈顶部,所以SP要指向大于(0x90A00+堆栈大小)地址即可。这里选择了0x9ff00。堆栈大小为0x9ff00-0x90A00=0xF500=61.25K。bootsect在内存中的搬移,以及搬移后设置SS:SP的操作过程就解析到这里,后面一篇文章将继续分享从磁盘2/3/4/5扇区读取setup的过程。

相关文章:

  • 2022-12-23
  • 2021-12-03
  • 2022-12-23
  • 2021-12-23
  • 2021-04-12
  • 2021-12-23
  • 2021-05-13
猜你喜欢
  • 2021-08-11
  • 2021-07-14
  • 2021-10-05
  • 2021-05-16
  • 2021-05-22
  • 2021-08-25
  • 2022-12-23
相关资源
相似解决方案