在REP MOVSW之前按PUSH CS/POP DS的目的是什么? [英] What's the purpose of PUSH CS / POP DS before a REP MOVSW?

查看:299
本文介绍了在REP MOVSW之前按PUSH CS/POP DS的目的是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么在下面的代码中我们推入代码段(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覆盖前缀的一种无效选择.

细分受众群可以更改movsw的来源DS:SICS:SI. (ES:DI的目标不能被覆盖).

(更新:在原始8086/8088上,存在硬件错误"/异常:从REP字符串指令期间发生的中断恢复后,IP将指向 last 前缀指令,而不是第一条指令.因此,根据编码,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):0. rep movsw之前的指令设置DS = BX + 16并设置DI = 0.

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

显然,此汇编器不支持ret farretf之类的语法,因此他们必须通过在ret指令周围声明一个proc far来汇编一段远的ret指令. AAA是该过程的一个非常奇怪的名称,因为 aaa也是有效的x86指令助记符(

.

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


(size+1) / 2会四舍五入为整数,除非大小自动换行,否则它将复制零字节而不是64k. (与loop不同,rep在执行一次 之前检查计数.)

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

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

Why in below code we push code segment (PUSH CS) and then popping it into the data segment (POP DS)?

I am giving these lines explicitly as line1 and line2. Please let me know how MOVSW is working here.

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.............. 

解决方案

Temporarily setting DS = CS and then restoring it looks like an inefficient alternative to using a CS override prefix on rep movsw.

A segment override can change the source for movsw from DS:SI to CS:SI. (The destination of ES:DI can't be overriden).

(update: on original 8086/8088, there was a hardware "bug" / anomaly: on resuming from an interrupt that happened during a REP-string instruction, IP would point to the last prefix of an instruction, not the first. So depending on the encoding, cs rep movsw would either decode as rep movsw or cs movsw. See @MichaelPetch's comments, and https://www.pcjs.org/pubs/pc/reference/intel/8086/ for more 8086 errata and anomalies that have been fixed in later x86 CPUs.)


This code is doing a memcpy(dst, code_segment, sizeof(code_segment)), where the dst segment:offset is (BX + 16):0. The instructions before rep movsw set up DS = BX+16 and set DI=0.

Then the code jumps to the new location, using a far ret after pushing the destination segment (ES) and an offset within it. (push offset SECONDRELOCATION would work, but only on 186+. This DOS code needs to maintain backwards compat with 8086, unfortunately.)

Apparently this assembler doesn't support syntax like ret far or retf, so they have to assemble a far ret instruction by declaring a proc far around the ret instruction. AAA is a very weird name for that proc, because aaa is also a valid x86 instruction mnemonic (ASCII Adjust after Addition).

So execution continues at the SECONDRELOCATION: label in the copy of the code we just made.


(size+1) / 2 rounds up to a whole number of words, unless the size wraps in which case it copies zero bytes instead of 64k. (Unlike loop, rep checks the count before executing once.)

Doing the shr at runtime is also dumb, and could have been done at assemble time using something like mov cx, (offset endcode - startcode + 1) / 2. (You probably can't divide an offset result by 2, but you can find the distance between two labels in the same section at assemble time.)

Anyway, probably the point is to relocate the code into HIGHMEM, leaving low memory free for use by programs that can't use HIMEM.

这篇关于在REP MOVSW之前按PUSH CS/POP DS的目的是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆