Rafael Rafael - 2 months ago 23
Linux Question

inline asm type mismatch

I am trying to make my own read system call for a 64bit linux system. but it keeps telling me I have a bad type. Is the compiler trying to indirectly address buf? I have a feeling I messed up in my input constraints. I just need the address of buf at

%2
.

error:

test.c: Assembler messages:
test.c:28: Error: operand type mismatch for `movq'


static int myread(int fd, char *buf, int size) {
register int bytes;

asm(
"movq $0, %%rax\n"

"movq %1, %%rdi\n"
"movq %2, %%rsi\n"
"movq %3, %%rdx\n"
"syscall\n"

"movq %%rax, %0"

: "=r" (bytes)
: "m" (fd), "m" (buf), "m" (size)
: "%rax", "%rdi", "%rsi", "%rdx"
);

return bytes;
}

Answer

As Mystical said, the mismatch error comes from the fact that you are using movq (which is for 64bit values) on 32bit integers (like fd and size).

But beyond that, this code is really inefficient and subtly (but dangerously) flawed. Maybe something more like this:

static int myread(int fd, char *buf, int size) {
    register int bytes;

    asm(
       "syscall"

    : "=a" (bytes)
    : "D" (fd), "S" (buf), "d" (size), "0" (0)
    : "rcx", "r11", "memory", "cc"
    );

    return bytes;
}

To understand this, check out the machine constraints for i386.

Note that syscalls clobber the rcx and r11 registers. Failing to advise the compiler that you are changing these values can lead to very strange problems. And the problems won't happen on the syscall, but a hundred lines downstream.

I'm also going to make a pitch for NOT using inline asm. I'm not sure why you don't want to just use the system calls, but you are just setting yourself up for grief.