简体   繁体   中英

multiplication instruction error in inline assembly

Consider following program:

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

I know that add instruction is used for addition, sub instruction is used for subtraction & so on. But I didn't understand these lines:

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

What is the exact meaning of :"=a"(foo) :"a"(foo), "b"(bar) ); ? What it does ? And when I try to use mul instruction here I get following error for the following program:

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

Error: number of operands mismatch for `mul'

So, why I am getting this error ? How do I solve this error ? I've searched on google about these, but I couldn't find solution of my problem. I am using windows 10 os & processor is intel core i3.

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

There is a detailed description of how parameters are passed to the asm instruction here . In short, this is saying that bar goes into the ebx register, foo goes into eax, and after the asm is executed, eax will contain an updated value for foo.

Error: number of operands mismatch for `mul'

Yeah, that's not the right syntax for mul . Perhaps you should spend some time with an x86 assembler reference manual (for example, this ).

I'll also add that using inline asm is usually a bad idea .


Edit: I can't fit a response to your question into a comment.

I'm not quite sure where to start. These questions seem to indicate that you don't have a very good grasp of how assembler works at all. Trying to teach you asm programming in a SO answer is not really practical.

But I can point you in the right direction.

First of all, consider this bit of asm code:

movl $10, %eax
movl $15, %ebx
addl %ebx, %eax

Do you understand what that does? What will be in eax when this completes? What will be in ebx? Now, compare that with this:

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

By using the "a" constraint, you are asking gcc to move the value of foo into eax. By using the "b" constraint you are asking it to move bar into ebx. It does this, then executes the instructions for the asm (ie add ). On exit from the asm, the new value for foo will be in eax. Get it?

Now, let's look at mul . According to the docs I linked you to, we know that the syntax is mul value . That seems weird, doesn't it? How can there only be one parameter to mul ? What does it multiple the value with ?

But if you keep reading, you see "Always multiplies EAX by a value." Ahh. So the "eax" register is always implied here. So if you were to write mul %ebx , that would really be mean mul ebx, eax , but since it always has to be eax, there's no real point it writing it out.

However, it's a little more complicated than that. ebx can hold a 32bit value number. Since we are using ints (instead of unsigned ints), that means that ebx could have a number as big as 2,147,483,647. But wait, what happens if you multiply 2,147,483,647 * 10? Well, since 2,147,483,647 is already as big a number as you can store in a register, the result is much too big to fit into eax. So the multiplication (always) uses 2 registers to output the result from mul . This is what that link meant when it referred "stores the result in EDX:EAX."

So, you could write your multiplication like this:

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

As before, this puts bar in ebx and foo in eax, then executes the multiplication instruction.

And after the asm is done, eax will contain the lower part of the result and edx will contain the upper. If foo * bar < 2,147,483,647, then foo will contain the result you need and upper will be zero. Otherwise, things get more complicated.

But that's as far as I'm willing to go. Other than that, take an asm class. Read a book.

PS You might also look at this answer and the 3 comments that follow that show why even your "add" example is "wrong."

PPS If this answer has resolved your question, don't forget to click the check mark next to it so I get my karma points.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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