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

时间:2017-02-16 04:04:36

标签: c assembly syntax-error 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指令用于减法&amp;等等。但我不明白这些界限:

 __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&#39;

的操作数不匹配

那么,为什么我收到此错误?我该如何解决这个错误?我在google上搜索过这些内容,但我无法找到问题的解决方案。我正在使用Windows 10 os&amp;处理器是英特尔核心i3。

1 个答案:

答案 0 :(得分:4)

  

具体含义是什么:“= a”(foo):“a”(foo),“b”(bar));

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

  

错误:`mul'

的操作数不匹配

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

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

编辑:我无法在评论中回答您的问题。

我不太清楚从哪里开始。这些问题似乎表明你对汇编程序的工作方式没有很好的掌握。试着用SO答案教你asm编程并不实用。

但我可以指出你正确的方向。

首先,考虑一下asm代码:

movl $10, %eax
movl $15, %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。根据我链接到的文档,我们知道语法是mul value。这看起来很奇怪,不是吗?怎么只有mul的一个参数? 的价值是多少?

但是如果你继续阅读,你会看到“总是将EAX乘以一个值”。啊。所以“eax”寄存器总是隐含在这里。所以,如果你要写mul %ebx,那真的是mul ebx, eax,但因为它总是 是eax,所以没有真正的意义来写出来。

然而,它比这复杂一点。 ebx可以保存32位值。由于我们使用的是int(而不是unsigned int),这意味着ebx可能有一个大到2,147,483,647的数字。但等等,如果你乘以2,147,483,647 * 10会怎样?好吧,因为2,147,483,647已经是一个很大的数字,你可以存储在寄存器中,结果太大了,不适合eax。因此乘法(总是)使用2个寄存器来输出mul的结果。这就是当它引用“将结果存储在EDX:EAX中时”所指的链接。

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

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

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

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

但就我愿意而言。除此之外,参加asm课程。读一本书。

PS你也可以看看this回答以及随后的3条评论,说明为什么即使你的“添加”例子也是“错误的”。

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