Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why asm have impossible constraints when I name registers?

Tags:

c

assembly

I'm new to assembly in C, and i dont know how to fix this error. I'm making a function that means to write a file. What I have is:

ssize_t mywrite(int fd, const void *buf, size_t count) {
//  return write(fd, buf, count);
    ssize_t var;
    __asm__("movl $4,%%eax\n\t"  // Write
        "movl %1,%%ebx\n\t"
        "movl %2,%%ecx\n\t"
        "movl %3,%%edx\n\t"
        "int  $0x80\n\t"         // System call
        "movl %%eax,%0"
        :"=r"(var)
        :"r"(fd),"r"(buf),"r"(count)
        :"%eax","%ebx","%ecx","%edx"
    );
    return var;
}

My asm is supposed to do the same as write(fd,buf,count); When I compile it, I get "'asm' operand has impossible constraints". However, if don't name the variables and get the values directly from the stack, I get no error. Here's the code

    __asm__("movl $4,%%eax\n\t"
        "movl 8(%%ebp),%%ebx\n\t"
        "movl 12(%%ebp),%%ecx\n\t"
        "movl 16(%%ebp),%%edx\n\t"
        "int  $0x80\n\t"
        "movl %%eax,%0"
        :"=r"(var)
        :
        :"%eax","%ebx","%ecx","%edx"
    );

I could use the second code, ofc, but I need it compiled with optimization 2. Then %ebp won't point where I need it to. I tried using "a", "b", "c" and "d" instead of "r", but no success. Anyone could help? Thanks :D

like image 756
Behnken Avatar asked Jan 25 '16 23:01

Behnken


1 Answers

The problem is that the constraint r means register, but your CPU simply doesn't have so many registers!

You can use the memory constraint m:

:"m"(fd),"m"(buf),"m"(count)

That will generate instructions such as:

movl 8(%ebp),%ebx

But I would recommend to use the x86 constraints in all its glory:

ssize_t mywrite(int fd, const void *buf, size_t count) {
    ssize_t var;
    __asm__(
        "int  $0x80"
        :"=a"(var)
        :"0"(4), "b"(fd),"c"(buf),"d"(count)
    );
    return var;
}

That, with -Ofast gives:

push   %ebx
mov    $0x4,%eax
mov    0x10(%esp),%edx
mov    0xc(%esp),%ecx
mov    0x8(%esp),%ebx
int    $0x80
pop    %ebx
ret

And with -Os:

push   %ebp
mov    $0x4,%eax
mov    %esp,%ebp
push   %ebx
mov    0x10(%ebp),%edx
mov    0x8(%ebp),%ebx
mov    0xc(%ebp),%ecx
int    $0x80
pop    %ebx
pop    %ebp
ret    

Note how, thanks to the use of constraints instead of the registers by name, the compiler is able to optimize the code further.

like image 82
rodrigo Avatar answered Nov 08 '22 01:11

rodrigo