繁体   English   中英

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

[英]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) );的确切含义是:"=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。

:“ = a”(foo)的确切含义是:“ a”(foo),“ b”(bar));

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

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

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

我还要补充一点,使用内联asm通常不是一个好主意


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

我不太确定从哪里开始。 这些问题似乎表明您根本不了解汇编程序的工作方式。 试图通过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位的数值。 由于我们使用的是整数(而不是无符号整数),因此这意味着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"
         );

如前所述,这会将bar放在ebx中,并将foo放在eax中,然后执行乘法指令。

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

但这是我愿意去的。 除此之外,参加ASM课程。 读一本书。

附注:您可能还会看到答案以及随后的3条注释,这些注释说明了为什么即使您的“添加”示例也是“错误的”。

PPS如果此答案解决了您的问题,请不要忘记单击其旁边的复选标记,以便获得我的业障积分。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM