Linux assembler error "impossible constraint in ‘asm’"

33,902

Solution 1

__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.

Solution 2

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;
}
Share:
33,902
slashmais
Author by

slashmais

Updated on February 01, 2020

Comments

  • slashmais
    slashmais over 4 years

    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.

  • slashmais
    slashmais over 14 years
    That works, thanks. Seems it doesn't like the 'modified' clause anymore, so I guess I'll have to push & popl whatever I change.
  • Stephen Canon
    Stephen Canon over 14 years
    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.
  • Daniel Kamil Kozar
    Daniel Kamil Kozar almost 9 years
    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.
  • Rahul Sreeram
    Rahul Sreeram almost 9 years
    @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.