MUL (ассемблер) в C - PullRequest
       5

MUL (ассемблер) в C

0 голосов
/ 04 ноября 2010

В Ассемблере я могу использовать команду MUL и получить 64-битный Результат EAX: EDX, Как я могу сделать то же самое в C? http://siyobik.info/index.php?module=x86&id=210

Мой подход к использованию uint64_t и сдвигу результата не работает ^^

Спасибо за вашу помощь (=

Me

Ответы [ 6 ]

3 голосов
/ 04 ноября 2010

Любой приличный компилятор просто сделает это , когда его спросят.

Например, используя VC ++ 2010, следующий код:

unsigned long long result ;
unsigned long a = 0x12345678 ;
unsigned long b = 0x87654321 ;

result = (unsigned long long)a * b ;

генерирует следующий ассемблер:

mov         eax,dword ptr [b] 
mov         ecx,dword ptr [a] 
mul         eax,ecx 
mov         dword ptr [result],eax 
mov         dword ptr [a],edx 
1 голос
/ 04 ноября 2010

Опубликовать код.Это работает для меня:

#include <inttypes.h>
#include <stdio.h>

int main(void) {
  uint32_t x, y;
  uint64_t z;
  x = 0x10203040;
  y = 0x3000;
  z = (uint64_t)x * y;
  printf("%016" PRIX64 "\n", z);
  return 0;
}
0 голосов
/ 04 ноября 2010

Вы не можете сделать это точно в C, то есть вы не можете умножить два N-битных значения и получить 2N-битное значение в качестве результата.Семантика умножения Си отличается от умножения вашей машины.В Си оператор умножения всегда применяется к значениям того же типа T (так называемые обычные арифметические преобразования позаботятся об этом) и выдает результат того же типа T.

Если вы сталкиваетесь с переполнением при умножении, вы должны использовать больший тип для операндов.Если нет более крупного типа, вам не повезло (т.е. у вас нет другого выбора, кроме как использовать реализацию большого умножения на уровне библиотеки).

Например, если самый большой целочисленный тип вашей платформы равен 64-Bit, то на уровне сборки на вашем компьютере у вас есть доступ к операции mul, которая дает правильный 128-битный результат.На уровне языка у вас нет доступа к такому умножению.

0 голосов
/ 04 ноября 2010

# включает

/* The name says it all.  Multiply two 32 bit unsigned ints and get
 * one 64 bit unsigned int.
 */
uint64_t mul_U32xU32_u64(uint32_t a, uint32_t x) {
  return a * (uint64_t)b; /* Note about the cast below. */
}

Это производит:

mul_U32xU32_u64:
    movl    8(%esp), %eax
    mull    4(%esp)
    popl    %ebp
    ret

При компиляции с:

 gcc -m32 -O3 -fomit-frame-pointer -S mul.c

Который использует инструкцию mul (здесь она называется mull для умножения long, как это нравится ассемблеру gnu для x86) так, как вы хотите.

В этом случае один из параметров был извлечен непосредственно из стека, а не помещен в регистр (вещь 4(%esp) означает 4 байта выше указателя стека, а пропущенные 4 байта являются адресом возврата), поскольку числа были переданы в функцию и были бы помещены в стек (в соответствии с x86 ABI (двоичный интерфейс приложения)).

Если вы встроили функцию или просто сделали в ней математические вычисления, это, скорее всего, во многих случаях приведет к использованию инструкции mul, хотя оптимизирующие компиляторы могут также заменить некоторые умножения на более простой код, если они могут сказать, что это сработает (например, оно может превратить это в сдвиг или даже в константу, если известен один или несколько аргументов).

В коде C хотя бы один из аргументов должен был быть приведен к 64-битному значению, чтобы компилятор выдал 64-битный результат. Даже если компилятор должен был использовать код, который выдает 64-битный результат при умножении 32-битных значений, он, возможно, не считал верхнюю половину этого значения важной, поскольку в соответствии с правилами операций C обычно приводят к значению с тем же типом как значение с наибольшим диапазоном из его компонентов (за исключением того, что иногда можно утверждать, что это не совсем то, что он делает).

0 голосов
/ 04 ноября 2010

Вы хотите умножить две 32-битные величины, чтобы получить 64-битный результат?

Это не предусмотрено в C само по себе, либо у вас есть 32-битное значение, такое как uint32_t, а затем результаттакой же ширины.Или вы приводите ранее к uint64_t, но затем вы теряете преимущество этого специального (и быстрого) умножения.

Единственный способ, который я вижу, - это использовать встроенные расширения на ассемблере.GCC хорош в этом, вы можете создать довольно оптимальный код.Но это не переносимо между разными версиями компиляторов.(Многие компиляторы общественного достояния принимают gcc, хотя, я думаю)

0 голосов
/ 04 ноября 2010

Посмотрите, можете ли вы получить эквивалент __ emul или __emulu для вашего компилятора (или просто используйте его, если у вас есть компилятор MS).хотя умножение на 64 бита должно работать автоматически, если только вы не сидите за какими-то ограничениями или другими забавными проблемами (например, _aulmul)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...