Question

In Assembler i can use the MUL command and get a 64 bit Result EAX:EDX, how can i do the same in C ? http://siyobik.info/index.php?module=x86&id=210

My approach to use a uint64_t and shift the Result don't work^^

Thank you for your help (=

Me

Was it helpful?

Solution

Any decent compiler will just do it when asked.

For example using VC++ 2010, the following code:

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

result = (unsigned long long)a * b ;

generates the following assembler:

mov         eax,dword ptr [b] 
mov         ecx,dword ptr [a] 
mul         eax,ecx 
mov         dword ptr [result],eax 
mov         dword ptr [a],edx 

OTHER TIPS

Post some code. This works for me:

#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;
}

See if you can get the equivalent of __emul or __emulu for your compiler(or just use this if you've got an MS compiler). though 64bit multiply should automatically work unless your sitting behind some restriction or other funny problem(like _aulmul)

You mean to multiply two 32 bit quantities to obtain a 64 bit result?

This is not foreseen in C by itself, either you have tow 32 bit in such as uint32_t and then the result is of the same width. Or you cast before to uint64_t but then you loose the advantage of that special (and fast) multiply.

The only way I see is to use inline assembler extensions. gcc is quite good in this, you may produce quite optimal code. But this isn't portable between different versions of compilers. (Many public domain compilers adopt the gcc, though, I think)

#include

/* 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. */
}

This produces:

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

When compiled with:

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

Which uses the mul instruction (called mull here for multiply long, which is how the gnu assembler for x86 likes it) in the way that you want.

In this case one of the parameters was pulled directly from the stack rather than placed in a register (the 4(%esp) thing means 4 bytes above the stack pointer, and the 4 bytes being skipped over are the return address) because the numbers were passed into the function and would have been pushed onto the stack (as per the x86 ABI (application binary interface) ).

If you inlined the function or just did the math in it in your code it would most likely result in using the mul instruction in many cases, though optimizing compilers may also replace some multiplications with simpler code if they can tell that it would work (for instance it could turn this into a shift or even a constant if the one or more of the arguments were known).

In the C code at least one of the arguments had to be cast to a 64 bit value so that the compiler would produce a 64 bit result. Even if the compiler had to use code that produced a 64 bit result when multiplying 32 bit values, it may have not considered the top half of it to be important because according to the rules of C operations usually result in a value with the same type as the value with the largest range out of its components (except you can sometimes argue that is not really exactly what it does).

You cannot do exactly that in C, i.e. you cannot multiply two N-bit values and obtain a 2N-bit value as the result. Semantics of C multiplication is different from that of your machine multiplication. In C the multiplication operator is always applied to values of the same type T (so called usual arithmetic conversions take care of that) and produces the result of the same type T.

If you run into overflow on multiplication, you have to use a bigger type for the operands. If there's no bigger type, you are out of luck (i.e. you have no other choice but to use library-level implementation of large multiplication).

For example, if the largest integer type of your platform is a 64-bit type, then at assembly level on your machine you have access to mul operation producing the correct 128-bit result. At the language level you have no access to such multiplication.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top