我试图在Linux中使用LDT(本地描述符表)。我为新代码段设置了LDT条目LDT [0]。然后我尝试用ljmp
更新%CS。我发现在ljmp
指令后更新了%CS,但是在printf
函数之后它又更改回原来的%CS值。所以我想知道libc
修改了%CS寄存器,但我不知道这是怎么发生的,我怎么能用自己指定的LDT?
以下是代码:
// allocate and setup an LDT entry
struct user_desc *def_seg = (struct user_desc *)malloc(sizeof(struct user_desc));
def_seg->entry_number = 0x0;
def_seg->base_addr = 0x0;
def_seg->limit = 0xfffff;
... ...
ret = modify_ldt(1, (void *)def_seg, sizeof(struct user_desc));
asm("movl %%cs, %0":"=r"(val)::); // get and print the %cs value
printf("val(cs) 0x%x\n", val); // val(cs) 0x73
// load the LDT into %cs, since x86 does not
// allow us to explicitly modify the %cs register
asm("ljmp $0x7, $reload_cs\n\t"
"reload_cs:\n\t");
asm("movl %%cs, %0":"=r"(val)::); // get and print the %cs value
printf("val(cs) 0x%x\n", val); // val(cs) 0x7
asm("movl %%cs, %0":"=r"(val)::); // after a printf. get and print the %cs value again.
printf("val(cs) 0x%x\n", val); // val(cs) 0x73
我使用自己分配的LDT只是想为一个小型研究项目测试一些x86分割功能。
我正在使用Ubuntu 14.04(内核版本4.1.9)在i386机器上工作。这只是一个试图利用某些细分功能的小型研究项目。
答案 0 :(得分:4)
Linux / x86-64并不真正使用段寄存器,期望线程本地存储(它们可能由内核管理,而不仅仅是libc)。它主要是设置它们的内核。请阅读Linux x86-64 ABI以获取详细信息(或Linux ia32 ABI获取32位x86);请参阅32位的其他参考here和64位的here。
详细了解syscalls(2)& execve(2)& set_thread_area(2)& modify_ldt(2)
我想线程创建可能会设置一些段寄存器(参见clone(2) ...)。研究NPTL C standard library的free software部分的源代码(GNU libc),例如MUSL libc或modify_ldt(2)
在Linux 32位x86用户代码中,您可能不应该且不能(不使用x86 memory segmentation)更改段寄存器。恕我直言他们只在上个世纪有用,对于16位MSDOS ...阅读上的wikipage
IMHO当前处理器无法有效处理段寄存器更改。 不要在代码中使用段寄存器(超出预定义的用法)。段寄存器是上个世纪(或16位模式下的BIOS)。