0

I am creating a small routine to load the idtr register with lidt instruction. I have created this code -

global load_idt

load_idt:
    mov eax, esp
    add eax, 4
    lidt eax    ;<-----------------LINE 9
    ret

But when I compile this using Nasm, I get an error -

kernel/kernel_start.asm:9: error: invalid combination of opcode and operands

My compilation command is-

nasm kernel/kernel_start.asm -f elf32 -o kernel/kernel_start.o

Can anyone point out the error in this program?

Anish Sharma
  • 314
  • 3
  • 18

1 Answers1

2

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

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
Margaret Bloom
  • 41,768
  • 5
  • 78
  • 124
  • I do plan to call the assembly routine from C. Though I am using an array for the descriptor table not a pointer. Would this make any difference or some better functionality? – Anish Sharma Jan 13 '17 at 16:01
  • Shouldn't you be passing an IDT by value and not a single descriptor through set_idt? Possible I'm missing something in the translation or how that is suppose to be used. – Michael Petch Jan 13 '17 at 18:04
  • Yes @MichaelPetch, I've written the wrong struct, thanks for pointing that out. – Margaret Bloom Jan 13 '17 at 19:57
  • If you meant to describe desc_t as an opaque type for the example (given the `struct desc_t;`) I think you might want to change `desc_t* table;` to `struct desc_t* table;` – Michael Petch Jan 13 '17 at 19:59
  • @AneeshSharma An array is an optimal choice for the descriptor table. You still need an equivalent of the `struct IDT` of above as that's what `lidt` is expecting. – Margaret Bloom Jan 13 '17 at 20:07