Vst*_*why 2 assembly real-mode x86-16
为什么在下面的代码中我们推送代码段(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..............
Run Code Online (Sandbox Code Playgroud)
暂时设置DS = CS,然后恢复它看起来像是使用CS覆盖前缀的低效替代方法rep movsw.
跨段可以更改源为movsw从DS:SI到CS:SI.(ES:DI无法覆盖的目的地).
(更新:原始8086/8088,有一个硬件"错误"/异常:从REP-string指令发生的中断恢复时,IP将指向指令的最后一个前缀,而不是第一个.所以取决于关于编码,cs rep movsw将解码为rep movsw或cs movsw.请参阅@ MichaelPetch的评论,并https://www.pcjs.org/pubs/pc/reference/intel/8086/了解更多8086勘误和已在以后的x86 CPU中修复的异常.)
这段代码正在执行amemcpy(dst, code_segment, sizeof(code_segment)),其中dstsegment:offset是(BX + 16):0.rep movsw设置DS = BX + 16并设置DI = 0 之前的指令.
然后代码跳转到新位置,ret在推送目标段(ES)和其中的偏移之后使用远.(效率不高:push offset SECONDRELOCATION应该工作得很好.)
显然,这个汇编器不支持的语法像ret far或者retf,所以他们必须装配远远ret声明一个指令proc far的周围ret指令. AAA这个proc是一个非常奇怪的名称,因为aaa它也是一个有效的x86指令助记符(加法后的ASCII调整).
因此,执行继续在SECONDRELOCATION:我们刚刚创建的代码副本中的标签处.
(size+1) / 2舍入到整数个单词,除非大小包装,在这种情况下它复制零字节而不是64k.(不像loop,rep检查计数之前执行一次).
shr在运行时执行也是愚蠢的,并且可以在汇编时使用类似的东西完成mov cx, (offset endcode - startcode + 1) / 2.(您可能无法将offset结果除以2,但您可以在汇编时找到同一部分中两个标签之间的距离.)
无论如何,可能重点是将代码重新定位到HIGHMEM中,使低内存空闲,供不能使用HIMEM的程序使用.