wingerse
wingerse

Reputation: 3796

Inline assembly addressing mode

I'm trying to write a lidt instruction in inline assembly in gcc with -masm=intel and 32 bits (-m32). So I have defined the following structures:

typedef struct {
    uint16_t length;
    uint32_t base;
} idt_desc;

static idt_desc desc = {
    sizeof(idt)-1,
    (uint32_t)(uintptr_t)idt,
};

If I were using nasm, I would be done with lidt [desc]. But I'm using inline assembly and have this inside a function:

asm volatile("lidt %0"::"m"(desc):);

This gives me "Error: unsupported instruction `lidt'". The assembly generated looks like this:

    lidt QWORD PTR desc

As far as I know, braces are optional in gas intel syntax. So the problem here is the qword ptr which is not acceptable in lidt instruction as it expects a m16&32 operand. How can I tell gcc to use that? i.e., drop qword ptr and just use desc.

Upvotes: 2

Views: 253

Answers (1)

Michael Petch
Michael Petch

Reputation: 47573

You need pack the idt_desc structure as the compiler will add padding between the 16-bit length and the 32-bit base structure members. Even if the compiler had managed to generate the code for this the structure would have been invalid and LIDT would have almost certainly loaded an incorrect IDT record leading to an eventual crash/triple fault at runtime. It should be:

typedef struct {
    uint16_t length;
    uint32_t base;
} __attribute__((packed)) idt_desc;

The -masm=intel option seems to have caused the compiler to see the unpacked version of the structure as a padded 8 byte structure and then treated it as a 64-bit QWORD. In 32-bit code an LIDT doesn't take a pointer to a QWORD it takes a pointer to a 48-bit value (aka FWORD in some Intel dialects) which is the source of the error. By packing the structure the compiler is no longer generating QWORD since the packed version is 6 bytes in size.

Upvotes: 2

Related Questions