libc如何在Linux中修改CS寄存器

时间:2015-10-17 11:14:40

标签: c linux

我试图在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机器上工作。这只是一个试图利用某些细分功能的小型研究项目。

1 个答案:

答案 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 libraryfree software部分的源代码(GNU libc),例如MUSL libcmodify_ldt(2)

在Linux 32位x86用户代码中,您可能不应该且不能(不使用x86 memory segmentation更改段寄存器。恕我直言他们只在上个世纪有用,对于16位MSDOS ...阅读enter image description here上的wikipage

IMHO当前处理器无法有效处理段寄存器更改。 不要在代码中使用段寄存器(超出预定义的用法)。段寄存器是上个世纪(或16位模式下的BIOS)。