在汇编程序中,我可以使用 MUL 命令并获得 64 位结果 EAX:EDX,我如何在 C 中做同样的事情?http://siyobik.info/index.php?module=x86&id=210
我使用 uint64_t 并转换结果的方法不起作用^^
感谢您的帮助(=
我
在汇编程序中,我可以使用 MUL 命令并获得 64 位结果 EAX:EDX,我如何在 C 中做同样的事情?http://siyobik.info/index.php?module=x86&id=210
我使用 uint64_t 并转换结果的方法不起作用^^
感谢您的帮助(=
我
任何体面的编译器都会在被问到时这样做。
例如使用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
贴一些代码。这对我有用:
#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;
}
#包括
/* 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
这里称为乘长,这是 x86 的 gnu 汇编器喜欢它的方式)。
在这种情况下,其中一个参数是直接从堆栈中提取的,而不是放在寄存器中(这4(%esp)
意味着堆栈指针上方的 4 个字节,被跳过的 4 个字节是返回地址),因为数字被传递给函数并且会被推入堆栈(根据 x86 ABI(应用程序二进制接口))。
如果您在代码中内联函数或只是在其中进行数学运算,则很可能会导致在mul
许多情况下使用该指令,尽管优化编译器也可以用更简单的代码替换一些乘法,如果他们知道它可以工作(例如如果一个或多个参数是已知的,它可以把它变成一个转变甚至一个常数)。
在 C 代码中,必须将至少一个参数转换为 64 位值,以便编译器生成 64 位结果。即使编译器在乘以 32 位值时必须使用产生 64 位结果的代码,它也可能不认为它的上半部分很重要,因为根据 C 操作的规则通常会产生具有相同类型的值作为其组成部分中范围最大的值(除非您有时会争辩说这并不完全是它的作用)。
您不能在 C 中完全做到这一点,即您不能将两个 N 位值相乘并获得一个 2N 位值作为结果。C 乘法的语义与机器乘法的语义不同。在 C 中,乘法运算符总是应用于相同类型的值T
(所谓的通常算术转换负责)并产生相同类型的结果T
。
如果在乘法中遇到溢出,则必须为操作数使用更大的类型。如果没有更大的类型,那么您就不走运了(即,您别无选择,只能使用库级的大乘法实现)。
例如,如果您平台的最大整数类型是 64 位类型,那么在您的机器上的汇编级别,您可以访问mul
产生正确 128 位结果的操作。在语言级别,您无法使用这种乘法。
看看你是否可以为你的编译器获得相当于__emul 或 __emulu的东西(或者如果你有一个 MS 编译器就使用它)。虽然 64 位乘法应该自动工作,除非你坐在一些限制或其他有趣的问题后面(比如 _aulmul)
您的意思是将两个 32 位量相乘以获得 64 位结果?
这在 C 语言中是无法预见的,要么你有两个 32 位,uint32_t
然后结果是相同的宽度。或者你之前投到,uint64_t
但你失去了特殊(和快速)乘法的优势。
我看到的唯一方法是使用内联汇编程序扩展。gcc 在这方面做得很好,你可能会产生相当优化的代码。但这不能在不同版本的编译器之间移植。(不过,我认为许多公共领域的编译器都采用了 gcc)