gcc 读取GDTR的值

7kjnsjlb  于 2022-11-13  发布在  其他
关注(0)|答案(2)|浏览(152)

我发现有可能通过SGDT汇编命令读取GDTR,将这段汇编插入到我的C代码中,得到Error: operand type mismatch for 'sgdt'

unsigned long j;
asm("sgdt %0" : "=r"(j));
smtd7mpg

smtd7mpg1#

sgdt只能接受内存操作数,而不能接受寄存器,因此它必须是"=m"。操作数大小为2+8字节(对于x86-64;限制然后按顺序寻址),所以需要一个结构体;使用long将导致在对象外部存储。
请阅读手册!https://www.felixcloutier.com/x86/sgdt
其他注意事项:

  • UMIP(用户模式指令阻止)允许内核阻止用户空间(特权级别3)运行此指令,因为它只帮助用户空间挫败内核ASLR或其他漏洞;用户空间没有合法的使用这个地址。在Linux这样的普通内核下,用户空间不能取消引用它从这个地址得到的虚拟地址。所以Linux does enable UMIP如果硬件支持的话(Zen 2,Cannon Lake,Goldmont Plus)。
  • Linux内核有一个宏用于此目的:store_gdt(dtr),它使用

asm volatile("sgdt %0":"=m" (*dtr));struct desc_ptr *dtr进行比较。
在我的Linux 5.18系统上,使用Skylake CPU(不支持UMIP),我将sgdt [rsp](NASM语法)放入一个静态可执行文件中,这样我就可以使用GDB(starti/stepi)单步执行它。

  • x /1hx $rsp显示限制为0x007f(存储在2个字节中,GDB称之为半字,Intel称之为字)。
  • x /1gx $rsp+2显示qword地址恰好是0xfffffe00000ed000,这是一个有效的内核地址(48位符号扩展,但离地址空间规范范围的上半部分的最顶端相当远。)根据docs/x86/x86-64/mm.txt,从fffffe0000000000开始的0.5TB保存cpu_entry_areaMap,因此在那里找到GDT并不奇怪,沿着其他内核内容,它们的地址暴露于用户空间(在没有UMIP的CPU上),并且必须一直Map,即使在有Meltdown的CPU上。
um6iljoc

um6iljoc2#

顺便说一句,在Linux内核中,也可以通过已经定义的宏store_gdt(dtr)执行相同的操作。它内部包含相同的内联汇编代码。宏的头部是asm/desc.h

相关问题