2017-01-13 48 views
0

我正在创建一个小例程,用lidt指令加载idtr寄存器。 我创造了这个代码 -错误:操作码和操作数的组合无效 - nasm

global load_idt 

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

但是,当我编译这个使用NASM,我得到一个错误 -

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

我的编译命令是 -

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

任何人都可以指出这个程序中的错误?

+1

助记符是'LIDT m16&32' ...你的意思是'lidt [eax]'? – Tommylee2k

+0

我想用'load_idt()'调用C中的函数'。我必须使用'[eax]'吗?它不是指向idtr的价值而不是它的地址? @ Tommylee2k –

回答

1

idtr寄存器必须加载两条信息:指向描述符表的指针和大小,以字节减去前者的一个字节。

因此,与Tommylee2k pointed out一样,唯一有效的格式是LGDT m16&32,其中m16&32是指向保存16位大小和32位基址指针的内存位置的指针。

引述英特尔

The source operand specifies a 6-byte memory location that contains the base address and the limit of the interrupt descriptor table.

谨防大小而来的基址之前。

如果我是你,我会保持组件最小与合适的使用C.
的例如使用一个结构来表示IDT基本和限制,然后通过值传递到汇编语言编写的函数。
这也是一个最罕见的情况,所以你可能会考虑它inline assembly is fine

/* 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 

琐事

技术上lidt eax是可编码的,只要使用具有值0d8h一个MODR/M字节(011B为REG域作为一个扩展操作码,11b和000B mod and r/m使用字段eax)但是lidt生成#UD如果使用了注册源(实际上lidt eax被重新用于AMD-v的vmrun)。

+0

我打算从C调用汇编程序。虽然我使用的是描述符表的数组而不是指针。这会产生什么区别或更好的功能? –

+0

你不应该通过set_idt按值传递一个IDT,而不是一个描述符?可能我错过了翻译中的某些内容,或者假设要使用这些内容。 –

+0

是@MichaelPetch,我写了错误的结构,谢谢指出。 –