Как использовать команду mov с указателем Word в ассемблере

В приведенном примере мы снова столкнулись с использованием атрибутивного оператора byte ptr, который позволяет в явной форме задать размер операнда. Однако если раньше этот оператор использовался, чтобы извлечь байт из данного, объявленного, как слово, то здесь его назначение иное. Транслятор, обрабатывая команду:

re>mov byte ptr ES:0, ‘! ‘

Не имеет возможности определить размер операнда-приемника. Разумеется, видеобуфер, как и любая память, состоит из байтов, однако надо ли рассматривать эту память, как последовательность байтов или слов? Команда без явного задания размера операнда:

re>mov ES:0, ‘! ‘

Вызовет ошибку трансляции, так как ассемблер не сможет определить, надо ли транслировать это предложение, как команду пересылки в видеобуфер байта 21h, или как команду пересылки слова 0021h.

Между прочим, на первый взгляд может показаться, что в обсуждаемой команде достаточно ясно указан размер правого операнда, так как символ (в данном случае "!") всегда занимает один байт. Однако транслятор, встретив обозначение "!", сразу же преобразует его в код ASCII этого символа, т.е. в число 21h, и уже не знает, откуда это число произошло и какой размер оно имеет.

Стоит еще отметить, что указание в команде описателя word ptr:

re>mov word ptr ES:0,’!’

Не вызовет ошибки трансляции, но приведет к неприятным результатам. В этом случае в видеобуфер будет записано слово 002lh, которое заполнит байт 0 видеобуфера кодом 21h, а байт 1 кодом 00h. Однако атрибут 00h обозначает черный цвет на черном фоне, и символ на экране виден не будет (хотя и будет записан в видеобуфер).

При желании можно избавиться от необходимости вводить описатель размера операнда. Для этого надо пересылать не непосредственное данное, а содержимое регистра:

re>mov AL,’!’ mov ES:0,AL

Здесь операндом-источником служит регистр AL, размер которого (1 байт) известен, и размер операнда-приемника определять не надо. Разумеется, команда: mov ES:0,AX заполнит в видеобуфере не байт, а слово.

Для адресации к видеобуферу в вышеприведенном примере использовался сегментный регистр дополнительных данных ES. Это вполне естественно, так как обычно регистр DS служит для обращения к полям данных программы, а регистр ES как раз и предназначен для адресации всего остального. Однако при необходимости можно было воспользоваться для записи в видеобуфер регистром DS:

re>mov AX,0B800h;Сегментный адрес mov DS,AX; видеобуфера в DS mov byte ptr DS:0, ‘! ‘;Символ в видеобуфер

Любопытно, что хотя обозначение DS: здесь необходимо, транслятор не включит в код команды префикс замены сегмента, так как команда без префикса выполняет адресацию по умолчанию через DS.

Если, однако, по умолчанию выполняется адресация через DS, то нельзя ли опустить в последней команде обозначение сегментного регистра? Нельзя, так как обозначение DS: число указывает, что число является не непосредственным операндом, а адресом операнда. Команда (неправильная): mov 6.10 должна была бы переслать число 10 в число 6, что, разумеется, лишено смысла и выполнено быть не может.

Команда же: mov DS:6.10 пересылает число 10 по относительному адресу 6, что имеет смысл. Таким образом, обозначение сегментного регистра с двоеточием перед операндом говорит о том, что операнд является адресом. В дальнейшем мы еще столкнемся с этим важным правилом.

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

Рассмотрим последовательно эти режимы.

Работа с данными и памятью

Если мы попытаемся использовать в инструкции два несовместимых по размеру операнда, то мы получим ошибку. Например:

re>.data num byte 17 .code main proc mov eax, num ret main endp end

В данном случае в 32-разрядный регистр EAX мы пытаемся поместить значение 8-разрядной переменной num. И в принципе то переменная num вполне может поместить в EAX, но ассемблер требует, чтобы оба операнда были одного размера. Соответственно программа не скомпилируется, и мы получим ошибку.

Чтобы решить данную проблему, мы можем применять преобразование типов. Преобзование имеет следующую форму:

re>тип ptr значение

Сначала указывается тип данных, в который мы преобразуем (byte, word, dword и т.д.). Далее идет оператор ptr , после которого указывается преобразуемое значение. Например, изменим предыдущую программу, применив преобразование:

re>.data num byte 17 .code main proc mov eax, dword ptr num ret main endp end

Выражение dword ptr num означает, что значение num преобразуется к типу dword.

Подобным образом можно преобразовывать константы

re>num = 19 .code main proc mov eax, dword ptr num ret main endp end

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

re>.data num word 0FFFEh .code main proc mov al, byte ptr num ret main endp end

Здесь 16-разрядную переменную num (равная FFFEh или 65534 в десятичной системе) преобразуем в 8-разрядный тип byte для помещения в регистр AL. При преобразовании будет из 16 бит в 8 бит в num будет отброшен старший бит и останется число FEh или 254.

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

Оцените статью
InternetDoc.ru
Добавить комментарий