11

I'm starting with assembler under Linux. I have saved the following code as testasm.c
and compiled it with: gcc testasm.c -otestasm
The compiler replies: "impossible constraint in ‘asm’".

#include <stdio.h>
int main(void)
{
    int foo=10,bar=15;

    __asm__ __volatile__ ("addl %%ebx,%%eax"
        : "=eax"(foo) 
        : "eax"(foo), "ebx"(bar) 
        : "eax" 
    );

    printf("foo = %d", foo);

    return 0;
}

How can I resolve this problem? (I've copied the example from here.)

Debian Lenny, kernel 2.6.26-2-amd64
gcc version 4.3.2 (Debian 4.3.2-1.1)

Resolution:
See the accepted answer - it seems the 'modified' clause is not supported any more.

starblue
  • 53,481
  • 14
  • 94
  • 148
slashmais
  • 6,953
  • 9
  • 51
  • 77

3 Answers3

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

seems to work. I believe that the syntax for register constraints changed at some point, but it's not terribly well documented. I find it easier to write raw assembly and avoid the hassle.

Stephen Canon
  • 100,816
  • 18
  • 175
  • 263
  • That works, thanks. Seems it doesn't like the 'modified' clause anymore, so I guess I'll have to push & popl whatever I change. – slashmais Sep 25 '09 at 17:41
  • 3
    The modified clause still works; I think the problem is that "output" implicitly specifies "modified" as well, so having eax represented in both field was causing the issue. – Stephen Canon Sep 25 '09 at 17:45
7

The constraints are single letters (possibly with extra decorations), and you can specify several alternatives (i.e., an inmediate operand or register is "ir"). So the constraint "eax" means constraints "e" (signed 32-bit integer constant), "a" (register eax), or "x" (any SSE register). That is a bit different that what OP meant... and output to an "e" clearly doesn't make any sense. Also, if some operand (in this case an input and an output) must be the same as another, you refer to it by a number constraint. There is no need to say eax will be clobbered, it is an output. You can refer to the arguments in the inline code by %0, %1, ..., no need to use explicit register names. So the correct version for the code as intended by OP would be:

#include <stdio.h>

int main(void)
{
    int foo=10, bar=15;

    __asm__ __volatile__ (
        "addl %2, %0"
        : "=a" (foo)
        : "0" (foo), "b" (bar)
    );

    printf("foo = %d", foo);

    return 0;
}

A better solution would be to allow %2 to be anything, and %0 a register (as x86 allows, but you'd have to check your machine manual):

#include <stdio.h>

int main(void)
{
    int foo=10, bar=15;

    __asm__ __volatile__ (
        "addl %2, %0"
        : "=r" (foo)
        : "0" (foo), "g" (bar)
    );

    printf("foo = %d", foo);

    return 0;
}
vonbrand
  • 10,868
  • 8
  • 30
  • 50
0

If one wants to use multiline, then this will also work..

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

'\' should be added for the compiler to accept a multiline string (the instructions).

Rahul Sreeram
  • 349
  • 2
  • 8
  • 1
    This isn't very good advice. You're specifying the registers to be used in input and output lists, but still use hardcoded registers inside the actual assembly block. You should be using `%0` and `%1` instead. – Daniel Kamil Kozar Jul 16 '15 at 23:05
  • @DanielKamilKozar: The accepted answer had everything in a single line. So, I used the same/similar code to show how to do it in multiline. I didnt try to modify the hardcoded registers used in the original accepted answer as I thought it will be easier to understand when one compares the multi line to single. – Rahul Sreeram Jul 24 '15 at 08:51