为什么在下面的代码中我们推入代码段(PUSH CS),然后将其弹出到数据段(POP DS)中?

我将这些行明确地指定为line1和line2。请让我知道MOVSW在这里如何运作。

IF  HIGHMEMORY
PUSH DS
MOV BX, DS
ADD BX, 10H
MOV ES, BX
PUSH CS.           ;line1
POP DS.            ;line2
XOR SI, SI
MOV DI, SI
MOV CX, OFFSET SYSSIZE  +  1
SHR CX, 1
REP MOVSW.    ;line3
POP DS
PUSH ES
MOV AX, OFFSET SECONDRELOCATION
PUSH AX
AAA PROC FAR
RET
AAA ENDP
SECONDRELOCATION:
more code here..............

最佳答案

暂时设置DS = CS,然后恢复它似乎是对rep movsw使用CS覆盖前缀的一种无效选择。

A segment override can change the source for movswDS:SICS:SI。 (ES:DI的目标不能被覆盖)。

(更新:在原始的8086/8088上,存在硬件“错误” /异常:从REP字符串指令期间发生的中断恢复后,IP将指向指令的最后一个前缀,而不是第一个前缀。因此,取决于在编码上,cs rep movsw可以解码为rep movswcs movsw。请参阅@MichaelPetch的注释和https://www.pcjs.org/pubs/pc/reference/intel/8086/,以获取更多8086勘误表和更高版本x86 CPU中已修复的异常信息。)



这段代码正在执行memcpy(dst, code_segment, sizeof(code_segment)),其中dst segment:offset是(BX + 16):0rep movsw之前的指令设置DS = BX + 16并设置DI = 0。

然后,在推入目标段(ES)和其中的偏移量后,使用远的ret将代码跳转到新位置。 (push offset SECONDRELOCATION可以使用,但只能在186+上使用。不幸的是,此DOS代码需要与8086保持向后兼容。)

显然,该汇编器不支持ret farretf之类的语法,因此他们必须通过在ret指令周围声明proc far来汇编远方的ret指令。 AAA是该过程的一个非常奇怪的名称,因为aaa is also a valid x86 instruction mnemonic (ASCII Adjust after Addition)

因此,执行将在我们刚刚编写的代码的副本中的SECONDRELOCATION:标签处继续。



(size+1) / 2舍入为整数,除非大小自动换行,在这种情况下,它会复制零字节而不是64k。 (与loop不同,rep在执行一次之前检查计数。)

在运行时执行shr也是愚蠢的,并且可以在汇编时使用mov cx, (offset endcode - startcode + 1) / 2之类的方法完成。 (您可能无法将offset结果除以2,但是在组装时可以找到同一部分中两个标签之间的距离。)

无论如何,大概的重点是将代码重新放置到HIGHMEM中,从而使低内存可用于无法使用HIMEM的程序。

09-06 01:37