暂时设置 DS = CS 然后恢复它看起来是使用 CS 覆盖前缀的低效替代方案rep movsw
.
段覆盖可以更改源movsw http://felixcloutier.com/x86/MOVS:MOVSB:MOVSW:MOVSD:MOVSQ.html from DS:SI
to CS:SI
。 (目的地为ES:DI
不能被覆盖)。
(更新:在原始 8086/8088 上,存在一个硬件“错误”/异常:从 REP 字符串指令期间发生的中断恢复时,IP 将指向last指令的前缀,而不是第一个。所以根据编码,cs rep movsw
会解码为rep movsw
or cs movsw
。请参阅@MichaelPetch 的评论,以及https://www.pcjs.org/pubs/pc/reference/intel/8086/ https://www.pcjs.org/pubs/pc/reference/intel/8086/有关更多 8086 勘误表和已在更高版本的 x86 CPU 中修复的异常情况。)
这段代码正在做一个memcpy(dst, code_segment, sizeof(code_segment))
,其中dst
段:偏移量是(BX + 16):0
。之前的说明rep movsw
设置 DS = BX+16,设置 DI=0。
然后代码跳转到新位置,使用farret
在推送目标段(ES)和其中的偏移量之后。 (push offset SECONDRELOCATION
可以,但仅限于 186+。不幸的是,这个 DOS 代码需要保持与 8086 的向后兼容。)
显然这个汇编器不支持这样的语法ret far
or retf
,所以他们必须组装一个远ret
通过声明一个指令proc far
周围的ret
操作说明。AAA
这个过程的名字很奇怪,因为aaa也是有效的 x86 指令助记符(添加后的 ASCII 调整) http://felixcloutier.com/x86/AAA.html.
所以执行继续在SECONDRELOCATION:
在我们刚刚制作的代码副本中添加标签。
(size+1) / 2
向上舍入为整数个字,除非大小回绕,在这种情况下它会复制零字节而不是 64k。 (不像loop
, rep
检查计数before执行一次。)
正在做的shr
在运行时也是愚蠢的,可以在汇编时使用类似的东西来完成mov cx, (offset endcode - startcode + 1) / 2
。 (你可能无法将offset
结果除以 2,但您可以在组装时找到同一部分中两个标签之间的距离。)
不管怎样,重点可能是将代码重新定位到 HIGHMEM 中,留下低内存以供不能使用 HIMEM 的程序使用。