linux - SIDT 指令在 Linux 用户空间进程中返回错误的基地址
问题描述
我制作了以下 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%X\n", idt_data.limit);
printf("IDT Base : 0x%lX\n", 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 或其他东西。操作系统可能会谎报答案而不是抛出异常,但我不知道。
推荐阅读
- migration - 对于 Oracle 报表,如何从表单菜单中检索报表
- mysql - MySql 选择具有日期差异的多条记录的行
- c# - 无需订阅密钥即可访问 JSON 数据
- ruby-on-rails - Rspec:如何测试在控制器操作创建中调用的服务对象方法“调用”?
- c - 运行 ps 以查找具有多个用户的 PID 时出现问题
- java - 在这个例子中 lambdas 和引用方法是如何工作的?
- angular - 如何使用 Angular 9 中的 @ViewChild 引用通过字符串标记定义的提供者,使用字符串标记作为选择器?
- python - 根据 Python 中字典列表中的值进行排名
- c++ - 球体边界体积碰撞OpenGL
- python - 试图在 django 中使评论可编辑