内联汇编中的乘法指令错误

multiplication instruction error in inline assembly

考虑以下程序:

#include <stdio.h>
int main(void) {
        int foo = 10, bar = 15;
        __asm__ __volatile__("add  %%ebx,%%eax"
                             :"=a"(foo)
                             :"a"(foo), "b"(bar)
                             );
        printf("foo+bar=%d\n", foo);
}

我知道add指令用于加法,sub指令用于减法等等。但是我不明白这些行:

 __asm__ __volatile__("add  %%ebx,%%eax"
                             :"=a"(foo)
                             :"a"(foo), "b"(bar)
                             );

:"=a"(foo) :"a"(foo), "b"(bar) ); 的确切含义是什么?它能做什么 ?当我在这里尝试使用 mul 指令时,我收到以下程序的以下错误:

#include <stdio.h>
int main(void) {
        int foo = 10, bar = 15;
        __asm__ __volatile__("mul  %%ebx,%%eax"
                             :"=a"(foo)
                             :"a"(foo), "b"(bar)
                             );
        printf("foo*bar=%d\n", foo);
}

错误:“mul”的操作数数量不匹配

那么,为什么会出现此错误?我该如何解决这个错误?我在 google 上搜索过这些,但找不到解决我的问题的方法。我正在使用 windows 10 os & 处理器是 intel core i3.

What is the exact meaning of :"=a"(foo) :"a"(foo), "b"(bar) );

这里有详细的说明如何将参数传递给asm指令here。简而言之,这就是说 bar 进入 ebx 寄存器,foo 进入 eax,执行 asm 后,eax 将包含 foo 的更新值。

Error: number of operands mismatch for `mul'

是的,这不是 mul 的正确语法。也许您应该花一些时间阅读 x86 汇编程序参考手册(例如,this)。

我还要补充一点,使用内联汇编通常是 bad idea


编辑:我无法将对您问题的回复放入评论中。

我不太确定从哪里开始。这些问题似乎表明您根本不了解汇编程序的工作原理。试图在 SO 答案中教你 asm 编程并不实用。

但我可以为您指明正确的方向。

首先,考虑一下这段asm代码:

movl , %eax
movl , %ebx
addl %ebx, %eax

你明白那是什么意思吗?完成后 eax 中会有什么? ebx中会有什么?现在,将其与此进行比较:

int foo = 10, bar = 15;
__asm__ __volatile__("add  %%ebx,%%eax"
                     :"=a"(foo)
                     :"a"(foo), "b"(bar)
                     );

通过使用 "a" 约束,您要求 gcc 将 foo 的值移动到 eax 中。通过使用 "b" 约束,您要求它将 bar 移动到 ebx 中。它执行此操作,然后执行 asm 的指令(即 add)。在退出 asm 时,foo 的新值将在 eax 中。明白了吗?

现在,让我们看看mul。根据我 link 告诉你的文档,我们知道语法是 mul value。这看起来很奇怪,不是吗? mul怎么可能只有一个参数呢? 的乘积是多少?

但是如果你继续阅读,你会看到 "Always multiplies EAX by a value." 啊。所以这里总是隐含 "eax" 寄存器。所以如果你要写 mul %ebx,那实际上是 mul ebx, eax,但是因为它总是 has 是 eax,所以写出来没有实际意义.

然而,它比那要复杂一点。 ebx 可以保存一个 32 位值的数字。由于我们使用的是整数(而不是无符号整数),这意味着 ebx 可以有一个大到 2,147,483,647 的数字。但是等等,如果将 2,147,483,647 * 10 相乘会怎样?好吧,因为 2,147,483,647 已经是您可以在寄存器中存储的最大数字,所以结果太大而无法放入 eax。所以乘法(总是)使用 2 个寄存器输出 mul 的结果。这就是 link 提到 "stores the result in EDX:EAX."

时的意思

所以,你可以这样写你的乘法:

int foo = 10, bar = 15;
int upper;
__asm__ ("mul %%ebx"
         :"=a"(foo), "=d"(upper)
         :"a"(foo), "b"(bar)
         :"cc"
         );

和以前一样,这将 bar 放入 ebx,将 foo 放入 eax,然后执行乘法指令。

并且在 asm 完成后,eax 将包含结果的下半部分,edx 将包含上半部分。如果 foo * bar < 2,147,483,647,则 foo 将包含您需要的结果,并且 upper 将为零。否则,事情会变得更复杂。

但这就是我愿意去的地方。除此之外,采用 asm class。读一本书。

PS 您也可以查看 this 答案,后面的 3 条评论说明为什么您的 "add" 示例也是 "wrong."

PPS 如果这个答案解决了您的问题,请不要忘记点击它旁边的复选标记,这样我就可以获得我的业力值。