The idtr
register must be loaded with two pieces of information: the pointer to the table of descriptors and the size, in bytes minus one, of the former.
So, as Tommylee2k pointed out, the only valid form is LGDT m16&32
, where m16&32
is a pointer to a memory location that holds a 16-bit size and a 32-bit base pointer.
Quoting Intel
The source operand specifies a 6-byte memory location that contains the base address and the limit of the interrupt descriptor
table.
Beware that the size comes before the base address.
If I were you I'd keep the assembly minimal with a suitable use of C.
For example use a structure to represent the IDT base and limit, then pass it by value to a function written in assembly.
This also one the rarest case where inline assembly is fine so you may consider it.
/* IDT descriptor */
struct desc_t;
/* IDT */
struct __attribute__ ((__packed__)) IDT
{
uint16_t size;
struct desc_t* table;
};
/* Declaration of assembly function */
void set_idt(struct IDT idt);
;Parameters in order of push
;
; struct IDT idt
;
_set_idt:
lidt [esp+4]
ret
Trivia
Technically lidt eax
is encodable, it suffices to use a ModR/M byte with value 0d8h (011b for the reg field as an extended opcode, 11b and 000b for the mod and r/m fields to use eax
) but lidt
generates #UD if a register source is used (and infact lidt eax
is reused for vmrun
of AMD-v).