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