GNU assembler syntax for IN and OUT instructions

1.2k views Asked by At

I am writing an inline assembly code to read Real-Time clock. I am loading the register number(4) to be read to 'dl' and loading this to port 0x70. I am trying to read this register value(4) into al. For more information - RTC

asm(
"mov $4, %%dl;"
"out 0x70, %%dl;"
"in %%al, 0x71;"
:
:
:"%al","%dl"
);

I am getting the below error message on compiling the c file that contains this code.

Assembler messages:

Error: operand size mismatch for 'out'

Error: operand size mismatch for `in'

The assembler version : GNU assembler version 2.26.1 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.26.1

Can someone please point out the issue?

1

There are 1 answers

2
fuz On BEST ANSWER

There are a number of problems. First, both in and out can only operate on the A register (al, ax, eax, rax). Second, the operand order is wrong and third, immediates have to be prefixed with $ in AT&T syntax. In plain assembly, your code should look like this:

mov $4,%al
out %al,$0x70
in  $0x71,%al

So your corrected assembly would be

asm(
"movb $4, %%al;"
"outb %%al, $0x70;"
"inb $0x71, %%al;"
:
:
:"%al"
);

Note that I have added explicit size suffixes to help clang assemble this code. I recommend you to further alter this code to use correct extended inline assembly:

unsigned char result;
volatile asm("outb %1,$0x70; inb $0x71, %0" : "=a"(result) : "a"((char)4));

This could make gcc generate slightly better code. For example, it allows gcc to inline this code.

Furthermore, you could consider using the inb() and outb() macros from <sys/io.h> to avoid inline assembly altogether. This is typically a very good thing to do.