Какова цель PUSH CS / POP DS перед REP MOVSW? - PullRequest
0 голосов
/ 04 декабря 2018

Почему в приведенном ниже коде мы нажимаем сегмент кода (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.............. 

Ответы [ 2 ]

0 голосов
/ 04 декабря 2018

Временная установка DS = CS, а затем ее восстановление выглядит неэффективной альтернативой использованию префикса переопределения CS для rep movsw.

Переопределение сегмента может изменить источник для movsw от DS:SI до CS:SI.(Назначение ES:DI не может быть переопределено).

(обновление: в оригинальном 8086/8088, произошла аппаратная «ошибка» / аномалия: при возобновлении после прерывания, произошедшего во время REP-Строковая инструкция, IP будет указывать на последний префикс инструкции, а не на первую. Таким образом, в зависимости от кодировки, cs rep movsw будет либо декодироваться как rep movsw, либо cs movsw. См. комментарии @ MichaelPetch,и https://www.pcjs.org/pubs/pc/reference/intel/8086/ для более 8086 ошибок и аномалий, которые были исправлены в более поздних процессорах x86.)


Этот код выполняет memcpy(dst, code_segment, sizeof(code_segment)), где dst сегмент: смещение (BX + 16):0.Инструкции до rep movsw устанавливают DS = BX + 16 и устанавливают DI = 0.

Затем код переходит на новое место, используя дальний ret после нажатия сегмента назначения (ES) исмещение внутри него.(Неэффективно: push offset SECONDRELOCATION должно работать просто отлично.)

Очевидно, этот ассемблер не поддерживает синтаксис, такой как ret far или retf, поэтому ему приходится собирать дальнюю инструкцию ret, объявив proc far вокруг ret инструкции.AAA - очень странное имя для этого процесса, потому что aaa также является действительным мнемоником инструкции x86 (ASCII Adjust после добавления) .

Таким образом, выполнение продолжается вSECONDRELOCATION: метка в копии только что созданного нами кода.


(size+1) / 2 округляет до целого числа слов, если только размер не переносится, в этом случае вместо него копируется ноль байтов64к.(В отличие от loop, rep проверяет счет перед тем, как выполнится один раз.)

Выполнение shr во время выполнения также глупо и может быть выполнено во время сборки с использованием чего-либокак mov cx, (offset endcode - startcode + 1) / 2.(Вы, вероятно, не можете разделить результат offset на 2, но вы можете найти расстояние между двумя метками в одном и том же разделе во время сборки.)

В любом случае, возможно, дело в том, чтобы переместить код вHIGHMEM, оставляя мало свободного места для использования программами, которые не могут использовать HIMEM.

0 голосов
/ 04 декабря 2018

Последовательность push cs, pop ds - это просто способ установить для вашего сегмента данных то же значение, что и для вашего сегмента кода.

Это похоже на использование push ax, pop bx вместо mov bx, ax, кроме того факта, что он использует память и может иметь различное влияние на определенные флаги, что я не смог потрудиться проверить, когда мое намерение состоит только в том, чтобы предоставить пример: -)

Одна из причин, по которой вы бы это сделали, восходит к старым временам сегментированной архитектуры x86 (в отличие от более современных селекторов), которая в настоящее время редко используется.У x86 были различные модели памяти, такие как крошечная, маленькая, компактная, средняя, ​​большая и огромная.

В основном это были различия в размерах и количестве сегментов кода и данных, которые вы могли использовать, и, из памяти, крошечныеозначало, что у вас был один сегмент, который содержал и код, и данные.

Следовательно, cs и ds должны быть установлены в одно и то же значение, чтобы все инструкции работали в этом сегменте по умолчанию.

В вашем конкретном случае вы сохраняете ds, устанавливая для него то же значение, что и cs, а затем восстанавливаете его.Ниже приведено более вероятное объяснение причины.


Что касается работы movsw, он просто копирует значение одного слова из памяти по адресу ds:si по адресу es:di, обновляяуказатели после (увеличение или уменьшение, в зависимости от установки флага направления).

Префикс rep делает это в цикле, уменьшая cx, пока не достигнет нуля.

Следовательноэто просто объемная копия памяти.


Теперь, поскольку источник repsw указан в сегменте ds, реальная причина, по которой вы видите, что push/pop устанавливаетсяds временно становится понятным - это потому, что источник данных явно лежит в сегменте кода.

...