0

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.

Destructor
  • 14,123
  • 11
  • 61
  • 126

1 Answers1

4

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.

Community
  • 1
  • 1
David Wohlferd
  • 7,110
  • 2
  • 29
  • 56
  • What does "a" & "b" indicate here ? – Destructor Feb 16 '17 at 04:28
  • If you read the docs I linked to for asm, you will see that the quoted strings are "constraints" that describe how to map the C language variables to something asm can understand (see the i386 section [here](https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html)). "a" refers to the eax register. "b" refers to ebx. – David Wohlferd Feb 16 '17 at 04:36
  • ok thank you. I got it. But I still have one problem. I want to multiply values of foo & bar variables & store result in foo. I've visited the link you given about mul insruction, but I still have hard time to know what exactly should I do to achieve this ? – Destructor Feb 16 '17 at 04:40
  • GCC has the shorthand `A` for the register pair EDX:EAX, so `long long out; asm("mul %2" : "=A"(out) : "a"(foo), "r"(bar) : "cc");` lets you treat the whole result as a 64-bit value. – ephemient Feb 16 '17 at 05:32
  • @DavidWohlferd: ok thanks for the detailed explanation. What will happen if result of foo * bar > 2,147,483,647 ? I think it will be undefined behaviour because of signed int overflow. – Destructor Feb 16 '17 at 10:30
  • @Destructor: the gcc has super shortcut for multiplication: `long long r = foo * bar;` ... and you don't even need inline assembly, so it's win-win. – Ped7g Feb 16 '17 at 12:51
  • Consider. If foo were 1, that could be written in binary as 00000000000000000000000000000001. Multiplied by 2 gives us 00000000000000000000000000000010. Again gives us 00000000000000000000000000000100, etc. Eventually, you are going to overflow. But that's what the `upper` is used for. As the bits shift further and further left, eventually they shift out of eax and into edx. That's why I said that as long as `upper` was 0, `foo` had the answer you wanted. Note: This is what *asm* does. Straight C will give you undefined behavior. – David Wohlferd Feb 16 '17 at 21:43