Работа с QWords

Я учусь и в ходе этого работаю над преобразованием ассемблера, которое часто использует QWORD (x86-32bit). Теперь в моем справочном материале нет ничего о работе с такими значениями, кроме очевидного разделения их на 32-битные регистры. Я думаю, они на старой стороне. Более новые процессоры имеют инструкции mmx и sse и тому подобное. Будет ли мне хорошо, если я изучу эти инструкции для решения этой проблемы? Как лучше всего обрабатывать значения QWORD?


person Glenn1234    schedule 17.10.2012    source источник


Ответы (2)


Работа с 64-битными целыми числами может быть легкой, а может и сложной; в зависимости от того, какие операции вы хотите выполнить.

Для булевой арифметики (И, ИЛИ, ХОТ, НЕ) легко работать с целыми числами любой длины, просто разделив их.

Для сложения и вычитания легко поддерживать целые числа любой длины, объединяя вместе инструкции ADC (сложение с переносом) или SBB (вычитание с заимствованием). Например (128-бит):

add eax,[value]
adc ebx,[value+4]
adc ecx,[value+8]
adc edx,[value+12]  ;edx:ecx:ebx:eax = 128-bit result of addition

Отрицание — это просто вычитание (-x = 0 - x).

Для сдвига влево/вправо легко поддерживать целые числа любой длины, объединяя вместе инструкции SHLD или SHRD. Например (128-бит):

shld edx,ecx,12
shld ecx,ebx,12
shld ebx,eax,12
shl eax,12          ;edx:ecx:ebx:eax = 128-bit result of shift left by 12

Если счетчик сдвига слишком велик (например, вы хотите сдвинуться влево на 44 бита), вам нужно сначала переместить данные, а затем сдвинуть на «исходный счет MOD 32». Например:

mov edx,ecx
mov ebx,ebx
mov ebx,eax
mov eax,0          ;edx:ecx:ebx:eax = original value shifted left by 32
shld edx,ecx,12
shld ecx,ebx,12
shld ebx,eax,12
shl eax,12         ;edx:ecx:ebx:eax = original value shifted left by 44

Для умножения ЦП поддерживает «32-битный * 32-битный = 64-битный результат». Для чего-то большего вы можете умножить любое целое число ширины на любое целое число ширины. Это похоже на то, как вы умножаете большие числа вручную, используя основание 10 (где каждая цифра представляет собой значение от 0 до 9), за исключением того, что вы используете основание 4294967296 (где каждая цифра представляет собой 32-разрядное целое число). Например, чтобы умножить 34 на 58 с использованием базы 10, вы должны сделать:

result_digit0to1 = 4*8 = 32
result_digit1to2a = 4*5 = 20
result_digit1to2b = 3*8 = 24
result_digit2to3 = 3*5 = 15
result = result_digit0to1 + (result_digit1to2 + result_digit1to2) * 10 + result_digit2to3 * 100;
result = 32 + (20 + 24) * 10 + 15 * 100
result = 32 + 440 + 1500
result = 1972

По сути, каждая цифра одного числа умножается на каждую цифру другого числа, при этом отслеживается положение/величина цифр; а результат представляет собой сумму промежуточных результатов.

Для «64-битного * 64-битного = 128-битного результата» вы должны сделать что-то вроде:

result_bits0to63 = first_bits0to31 * second_bits0to31;
result_bits32to95a = first_bits32to64 * second_bits0to31;
result_bits32to95b = first_bits0to31 * second_bits32to64;
result_bits64to128 = first_bits32to64 * second_bits32to64;
result = result_bits0to63 + ( (result_bits32to95a + result_bits32to95b) << 32) + (result_bits64to128 << 64)

Однако это работает только для целых чисел без знака. Для целых чисел со знаком вам нужно удалить знаковый бит и выполнить беззнаковое умножение, а затем установить знак в результате (result_sign_bit = first_sign_bit XOR second_sign_bit).

Для деления вы в конечном итоге делаете «длинное деление base2». Вы сдвигаете делитель как можно дальше влево, не теряя старшего установленного бита (при этом отслеживая «сдвинутые биты»). Затем вы возвращаете его в исходное положение по одному биту за раз, сравнивая его с делимым значением. Если сдвинутый делитель меньше, чем делимое значение, вы вычитаете сдвинутый делитель из делимого значения и устанавливаете соответствующий бит в результате. После того, как делитель был возвращен в исходное положение, делимое значение становится остатком.

Как и умножение, деление действительно работает только для целых чисел без знака, и вам нужно заранее удалить бит знака, затем выполнить беззнаковое деление, а затем установить знак (как в результате, так и в остатке).

Если вы понимаете все это; тогда вы сможете (например) выполнять 512-битные математические операции с 64-битным ЦП или 65536-битные математические операции с 16-битным ЦП или математику «любой ширины» на любом ЦП.

person Brendan    schedule 18.10.2012

Лучший подход — использовать инструкции, которые работают с QWORD, если это явно не запрещено курсом. Тогда вам придется использовать, как вы утверждаете, 32-битные регистры для выполнения этой работы. Вы можете написать несколько подпрограмм для выполнения базовых логических инструкций с помощью QWORD.

person m0skit0    schedule 17.10.2012
comment
Это не для курсовой работы, а для изучения ASM (хотя я хочу, чтобы результаты были достаточно быстрыми), поэтому я хочу знать, что работает лучше всего. - person Glenn1234; 18.10.2012
comment
Тогда, как я уже сказал: Лучший подход — использовать инструкции, которые работают с QWORD. Это быстрее, чем делать это с помощью 32-битных инструкций. - person m0skit0; 18.10.2012