Inline asm: operand type mismatch for `in'

2k views Asked by At

I got the error

Error: operand type mismatch for `in'

The line generating this is:

inb %%eax, %%edx 

I tried these: inb %%eax, $0x00000064 and inb %%eax, $0x64.

But neither of them did change the output. I also tried with in instead of inb, but I'm taking shots in the dark at this point.

Any ideas?

3

There are 3 answers

2
Precious Biplelo On

Intel gave very little information about The i/o instruction set .. Nevertheless you are to deal with a port address or a register then extract the input from that address.

in dest, source

Note your destination is a physical address

So you must point to that address

in $0x8, %al ;

Note Intel warns about 0FH to 0FFH not to be used

This puts the ax lower 8-bits into the physical address 0x8

0
Peter Cordes On

AT&T syntax is in src, dst, where src is a port number and the destination is AL, AX, EAX, according to the size of I/O access you want to make. (inb/inw/inl). 64-bit IO size is not available, even in 64-bit mode.

The port number can be an immediate like inb $0x64, %al, but has to be DX if it's a register.
(I/O addresses are 16-bit, separate from physical or virtual address-space).

https://www.felixcloutier.com/x86/in - Intel's manual uses Intel syntax, so the AT&T equivalent is

asm volatile("inb %%dx, %%al" : "=a"(byte) : "d"(portnum));

Or better, let the compiler pick immediate vs. register for you by using an "Nd"((uint16_t)port) constraint, and use the %1 operand instead of hard-coding %%dx.

See Porting AT&T inline-asm inb / outb wrappers to work with gcc -masm=intel for working AT&T-syntax wrappers, and also working Intel-syntax wrapper functions.

To also make it work with gcc -masm=intel, you can use dialect alternatives as shown in Michael Petch's answer:

uint8_t inb(uint16_t port)
{
    uint8_t ret;  // 8-bit type will get "=a" to pick AL
    asm volatile ( "inb {%[port], %[retreg] | %[retreg], %[port]}"
                   : [retreg]"=a"(ret)
                   : [port]"Nd"(port) );
    return ret;
}

Letting the compiler expand %0 to %al or al according to syntax mode saves us the trouble.

2
NeoSer On

"inb" means that you execute a mnemonic command "in" on the operands of size byte (8-bit). inw is for words (16-bit), inl is for long words (32-bit) and inq is for quad (on 64 bit machines). The %eax register is 32-bit, which consists of %ax (16-bit). The %ax register, in its turn, consists of high 8 bits (%ah) and low 8 bits (%al). Thus, if you are to use "inb", you should use %al or %ah, e.g.,

inb %%al, %%dl # from source %%al 8-bit to destination %%dl 8-bit.

To use "in" with %eax, you need to append "l" to the command (or to omit the letter as some compilers can infer the type). That is,

inl %%eax, %%edx

should do fine.