#assembly #x86 #syntax-error #masm
# #сборка #x86 #masm
Вопрос:
.data
num1 word 0FEEDh
.code
main PROC
mov ecx, 0E4C7FFFDh ;ecx = 0E4C7FFFD hex
sub ecx, num1 ;;;;; error on this line
Я хочу иметь возможность вычитать переменную num1
из регистра ecx
, но эта попытка дает:
ошибка A2022: операнды команд должны быть одинакового размера
Я очень новичок в сборке и пытаюсь разобраться в основах. Как я могу это сделать?
Ответ №1:
ecx
это 32-разрядный регистр, dword (двойное слово); в терминологии x86 СЛОВО составляет 2 байта.
Когда вы пытались:
sub ecx, num1 ;ecx = ecx - num1
Ассемблер проверил label num1
и обнаружил, что он имеет тип word
, и поэтому попытался сгенерировать
sub ecx, word ptr [num1] ;ecx = ecx - num1
но этот код операции не существует.
sub r32, r/m32
Форма существует sub
, но загрузка 4 байт из 2-байтовой переменной приведет к извлечению 2 байт мусора в старшей половине.
sub ecx, dword ptr [num1] ; don't *just* change to this
Это будет сборка, но вам нужно будет перейти num1
на dword, чтобы оно было правильным. (Если только вы не хотели также прочитать все 2 байта, которые вы собрали после num1, в свой раздел .data). И если вы используете num1 dword 0FEEDh
, MASM sub ecx, num1
будет работать, потому что он определит правильный размер для операнда памяти. Если вы хотите, чтобы MASM сверял размеры ваших переменных с тем, как вы их используете, не используйте переопределения размера операндов, если они вам не нужны (например, для копирования 4 байт сразу из строки.)
Ассемблер рекомендует устранить проблему, создав num1
переменную dword или изменив ecx
на cx
. Это не так ( cx
не может сохранить вашу константу, но masm
не знает этого); однако есть еще одна возможность. Вы можете расширить нулевое значение до нулевого регистра и вычесть это:
movzx edx, num1 ; zero-extending load from a byte or word var
sub ecx, edx
Или, если num1
подписано ( masm
имеет SWORD
, но я обычно вижу WORD
, что используется как для подписанного, так и для неподписанного):
movsx edx, num1 ; sign-extending load
sub ecx, edx
Комментарии:
1.
sub ecx, byte num1
не существует!sub r32, m8
Кодировка отсутствует. Может быть, вы перепутали сsub r/m32, imm8
, с немедленным расширением знака? Единственными целочисленными скалярными инструкциями x86, которые выполняют загрузку со знаком или с расширением до нуля, являютсяmovsx
иmovzx
, другие инструкции требуют, чтобы их операнд памяти имел ту же ширину, что и размер операнда.2. @PeterCordes: Приготовьтесь, я проверю, что
nasm
сгенерировано, когда оно успешно собрано.3. Обратите внимание, что это вопрос MASM, где
sub ecx, word ptr num1
находится операнд источника памяти. В NASMsub ecx, byte num1
просто предлагает ассемблеру использовать imm8 для кодирования адреса . Фактическая эквивалентная инструкция NASMsub ecx, byte [num1]
, которая не будет собираться. (Помните, что имена пустых символов — это операнды памяти в MASM, адреса в NASM).4. @PeterCordes: Да, только что понял, что я все испортил.
5. Когда вы исправите это, я думаю, что также важно использовать синтаксис MASM повсюду; тем более
mov eax, word [foo]
, что на самом деле выполняется сборка в MASM сword
расширением до числа 2, так что это становитсяmov eax, [foo 2]
безумно непрозрачным и запутанным для новичков, которые не до конца понимают, чтоword ptr
делает, не говоря уже о MASM против NASMword ptr
противword
.