我制作了以下x86-64程序来查看中断描述符表的基址起始位置:
#include <stdio.h>
#include <inttypes.h>
typedef struct __attribute__((packed)) {
uint16_t limit;
uint64_t base;
}idt_data_t;
static inline void store_idt(idt_data_t *idt_data)
{
asm volatile("sidt %0":"=m" (*idt_data));
}
int main(void)
{
idt_data_t idt_data;
store_idt(&idt_data);
printf("IDT Limit : 0x%Xn", idt_data.limit);
printf("IDT Base : 0x%lXn", idt_data.base);
return 0;
}
它打印以下内容:
IDT Limit : 0xFFF
IDT Base : 0xFFFFFE0000000000
基本地址似乎不正确,因为地址应该始终是物理地址,对吗?
此外,我也不确定,但这个限制似乎太高了。我做错了什么?
这是一个线性地址,不一定是物理地址。换句话说,它和大多数其他地址一样受页面表的约束。它必须位于从未被分页到磁盘的页面中——如果没有,它将无法处理页面错误——但它可以位于物理上与虚拟上不同的地址中。
在x86-64上,IDT的每个条目都有16个字节长。有256个中断矢量。256*16=4096=0x1000。IDTR极限是一个";小于或等于";检查,因此通常使用0xFFF。
如果操作系统启用某个功能,SIDT
是较新CPU上的特权指令,因此建议不要在用户模式下使用它,除非您正在编写漏洞PoC或其他东西。操作系统可能在答案上撒谎,而不是抛出异常,但我不知道。