Если вы хотите рассматривать ваши значения как подписанные, вам нужно movsx
. Предполагая синтаксис NASM:
default rel
; ... declarations and whatever
movsx rax, word [a + 1*2] ; a is an array of dw = words
movsx rcx, byte [b + 1*1] ; b is an array of db = bytes
add rax, rcx
mov [result], rax ; result is a qword
(MASM или GNU .intel_syntax будет использовать word ptr
вместо word
, просто добавьте ptr
в спецификатор размера для операнда памяти.)
1
может быть регистром типа [a + rsi*2]
или [b + rsi]
, так что вы можете легко перебирать массивы. Ссылка на содержимое ячейки памяти. (режимы адресации x86)
Я написал 1*2
вместо 2, чтобы указать, что это индекс 1 (2-й элемент массива), масштабированный по размеру элемента. Ассемблер оценит константное выражение и просто использует тот же (относительный к RIP) режим адресации, что и для [a]
, но с другим смещением.
Если вам нужно, чтобы он работал в позиционно-независимом коде (гдеВы не можете использовать режим адресации [disp32 + register]
с 32-битным абсолютным адресом для символа), сначала lea rdi, [a]
(RIP-относительный LEA) и выполнить [rsi + rsi*2]
.
Если выЕсли вам нужно нулевое расширение, вы бы использовали movzx
movzx eax, word [a + 1*2] ; a is an array of dw = words
movzx ecx, byte [b + 1*1] ; b is an array of db = bytes
; word and byte zero-extended into 64-bit registers:
; explicitly to 32-bit by MOVZX, and implicitly to 64-bit by writing a 32-bit reg
; add eax, ecx ; can't overflow 32 bits, still zero-extended to 64
sub rax, rcx ; want the full width 64-bit signed result
mov [result], rax ; result is a qword
Если бы вы знали, что старшие биты вашего полного результата всегда будут равны нулю, просто используйте EAX (размер 32-битного операнда), за исключениемконец. Преимущества использования 32-битных регистров / инструкций в x86-64
Этот код соответствует C как
static uint16_t a[] = {...};
static uint8_t b[] = {...};
static int64_t result;
void foo(){
int64_t rax = a[1] - (int64_t)b[1];
result = rax; // why not just return this like a normal person instead of storing?
}
Говоря о том, что вы можете посмотреть навывод компилятора в проводнике компилятора Godbolt и ознакомьтесь с этими инструкциями и режимами адресации.
Обратите внимание, что mov al, [b + 1]
загрузит байт и объединит это в младший байт RAX.
Обычно вы этого не хотите;movzx
- это обычный способ загрузки байта в современном x86. Современные процессоры x86 декодируют x86 в RISC-подобные внутренние мопы для переименования регистров + выполнения вне порядка. movzx
позволяет избежать ложной зависимости от старого значения полного регистра. Это аналог ARM ldrb
, MIPS lbu
и т. Д.
Слияние с младшим байтом или словом RAX - странная вещь CISC, которую может делать x86, но RISC не может.
Вы можете безопасно читать 8-битные и 16-битные регистры (и вам нужно это для хранения слов), но обычно избегайте записи частичных регистров, если у вас нет веских причин и вы понимаете возможную производительностьпоследствия ( Почему GCC не использует частичные регистры? ). например, вы обнулили полный пункт назначения перед cmp + setcc al
.