Невозможно переместить 8-битный адрес в 16-битный регистр

Я пытаюсь назначить переменную для регистрации, вот код:

       ORG 100h

        var1 DB 10  ;
        var2 DB 20  ;

        MOV BX,var1 ; error : operands do not match: 16 bit register and 8 bit address
RET
END

Но если поменять местами 4-ю строку:

MOV BL, var1;

оно работает. Итак, мой вопрос: почему я не могу переместить 8-битную переменную в гораздо больший 16-битный регистр?

Я уже упоминал это, это и этот ОП, но он не отвечает на мой вопрос.

ПРИМЕЧАНИЕ:

  1. Я использую ассемблер emu8086.
  2. Я новичок в ассемблере, поэтому прошу прощения, если вопрос глупый.

person Ven    schedule 27.11.2015    source источник
comment
Вам нужно использовать movzx или movsx, если они доступны, для перемещения с нулевым или знаковым расширением соответственно. Он может быть недоступен в 8086, и в этом случае вам нужно перейти в BL, как вы сделали, и обнулить BH самостоятельно. А почему: потому что они создали такую ​​архитектуру :)   -  person Jester    schedule 27.11.2015
comment
@Jester: Это не так, только cbw. Я обновил вики тега stackoverflow.com/tags/8086/info со ссылкой на википедию с таблицей, когда различные инструкции были введены. Также с обличительной речью о том, как глупо изучать asm на 16-битном 8086. Но в любом случае, некоторые из основных insns 8086 отсутствуют, это movzx/sx и bt* bit-manip.   -  person Peter Cordes    schedule 27.11.2015
comment
голосование только потому, что это сообщение об ошибке плохо сформулировано и вводит в заблуждение.   -  person Peter Cordes    schedule 27.11.2015
comment
Кстати, на самом деле это является дубликатом stackoverflow.com/questions/15540450/, который вы связаны. Ответы там не пытаются объяснить, почему это ошибка, и movzx не работает на 8086, но все же. Проголосовал за то, чтобы закрыть это как дубликат этого, так как у этого есть более подробные ответы.   -  person Peter Cordes    schedule 27.11.2015


Ответы (2)


почему я не могу переместить 8-битную переменную в гораздо больший 16-битный регистр?

Поскольку для инструкции машинного кода MOV требуется, чтобы операнд-источник и операнд-приемник были одинакового размера. Это необходимо, потому что инструкция MOV сама по себе не указывает, как заполнить оставшиеся биты большего регистра назначения.

Чтобы разрешить операции перемещения разного размера, Intel добавила MOVZX и MOVSX в ЦП 80386, что позволяет использовать исходный операнд меньшего размера (целевым всегда является 32-битный регистр). Суффиксы -SX и -ZX обозначают, чем должны быть заполнены ранее неиспользованные биты регистра назначения.

На 16-битных процессорах Intel есть инструкция CBW (Convert Byte to Word), которая расширяет знак от 8 до 16 бит. К сожалению, это работает только для аккумулятора (зарегистрируйте AL/AX), поэтому вам придется сделать что-то вроде:

mov al,var1
cbw
mov bx,ax

cbw делает расширение знака. Если ваш var1 не подписан, вы можете сделать это просто так:

mov bl,var1
xor bh,bh  ; equivalent to mov bh,0 but faster and only one byte opcode

Или, как утверждает Питер Кордес:

xor bx,bx    ;clear the whole destination register
mov bl,var1  ;update the least significant byte of the register with the 8-bit value
person mcleod_ideafix    schedule 27.11.2015
comment
xor bx,bx / mov bl, var1 было бы лучше, потому что это больше похоже на одну из хороших идиом, которые вы хотели бы использовать в 32- или 64-битном режиме (обнуление полного регистра перед использованием меньшей части). Это разрушает ложную зависимость от старого содержимого полного регистра, но обнуление верхней и нижней половин по отдельности не поможет. Также допустимо movs/zx r16, r/m8. Он также действителен с 64-битной регистрацией назначения, но не рекомендуется для movzx, поскольку он идентичен movzx с 32-битной регистрацией. Есть новый опкод для movsx r64, r/m32, но не для movzx. - person Peter Cordes; 27.11.2015
comment
Кроме того, mov bh,bh представляет собой 2-байтовую инструкцию с тем же размером кода, что и mov bh, 0. Если вы собираетесь писать BH, mov на самом деле лучше подходит для 8-битных регистров на современных процессорах. Как именно работают частичные регистры в Haswell/Skylake? Написание AL, по-видимому, имеет ложную зависимость от RAX, а AH несовместимо. (Но оба способа плохи по сравнению с обнулением xor всего 16-битного регистра, как в моем предыдущем комментарии.) - person Peter Cordes; 08.12.2020

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

var1 — это не 8-битный адрес, это 16-битный адрес (не считая сегмента), который указывает на первую из двух 8-битных переменных. Таким образом, сообщение об ошибке ассемблера плохо сформулировано и сбивает с толку.

NASM сделает то, что вы сказали, и выполнит 16-битную загрузку. Вы найдете var1 в bl и var2 в bh. Предположительно, вы могли бы написать mov bx, word [var1] или word ptr или что-то еще, чтобы ваш ассемблер выдавал 16-битную загрузку.

(На самом деле NASM собирает mov BX, var1 в mov r16, imm16, помещая адрес в регистр. Всегда используйте [] для ссылок на память, для согласованности, потому что это работает в NASM и MASM вариантах синтаксиса Intel. NASM не поддерживает синтаксис mov BX, offset var1 для записи однако форма mov-immediate.)

person Peter Cordes    schedule 27.11.2015