imull операция по сборке ia32
Я хочу сделать незаметную операцию в сборке и вернуть результат в C.
Сигнатура моей функции 'long long multiplicar(void)' и код:
multiplicar:
movl op1, %eax
imull op2, %eax
adcl $0, %edx
ret
Мой op2 - 3. Когда мой op1 -399, работает хорошо (дает 1197). Но когда мой op1 -399, я получаю 4294966093 и не знаю почему. Я должен использовать CDC?
Мои op1 и op2 - длинные длинные типы. Спасибо
1 ответ
imul
Инструкция, если ей даны 32-битные операнды, выполняет 32-битное умножение со знаком. Это дает результат до 64 битов, однако в формах с двумя / тремя операндами сохраняется только наименее значимое слово с переполнением, указанным через перенос.
Обратите внимание, что перенос - это только однобитовый флаг, используемый для обнаружения ошибок, и он не может переносить информацию, необходимую для объединения нескольких умножений с повышенной точностью.
В этом случае после последнего редактирования кажется, что цель состоит в том, чтобы умножить две 64-битные переменные вместе и получить усеченный 64-битный результат. Достижение этого с помощью 32x32=>64-битного примитива требует связывания воедино четырех умножений, что равнозначно методу начальной школы. То есть (a<<32|b) * (c<<32|d) = (a*c<<64) + (a*d<<32) + (b*c<<32) + (b*d<<0)
, a*c
Однако здесь можно отбросить термин, поскольку нам требуются только младшие 64-битные значения результата.
Хотя это просто в теории, на практике временные записи и прямолинейность на ассемблере тонки и подвержены ошибкам. Дополнительным недостатком является то, что операции подписаны, для чего я бы предложил создать базовый примитив умножения без знака и настроить знаки отдельно.
К счастью, процессор фактически поддерживает 64-битное умножение изначально, если мы вместо этого используем модуль с плавающей запятой 8087. Обратите внимание, что во избежание ошибок округления управляющее слово с плавающей точкой должно быть установлено с полной 64-битной точностью (_controlfp(_PC_64,_MCW_PC)
), в отличие от 53 битов, которые обычно используются.
multiply: ;int64_t __cdecl multiply(int64_t lhs, int64_t rhs)
fildq 4(%esp)
fildq 12(%esp)
fmul
fistpq 4(%esp)
movl 4(%esp),%eax
movl 8(%esp),%edx
ret
Тем не менее, обратите внимание, что переполнения, требующие полной 128-битной точности, не дают правильного усеченного 64-битного результата, и вопрос о том, не является ли переполнение, должен быть обработан.