当设置为TLS选择器时,为什么ES和DS最终在64位内核上归零?

时间:2015-10-04 19:49:07

标签: linux x86 x86-64 gdt

下面的32位程序调用{​​{3}}在GDT中创建一个条目,用于TLS。通常,生成的选择器将放入FSGS并成功使用。但是如果它被放入DSES,在64位内核上运行,最终(在我猜测上下文切换之后),这个选择器会清零。

但是,如果我改为使用set_thread_area(2)并将生成的LDT条目的选择器放入这些段寄存器中,它们似乎保持其值!

另外,如果我把64位代码段(0x33)或32位代码段(0x23)的选择器,两者都引用GDT,进入DSES,不会被淘汰。

这是源代码(用modify_ldt(2)编译),展示了奇怪的行为:

format ELF executable
segment readable executable

SYS_WRITE=4
STDERR=2
SYS_SET_THREAD_AREA=243
SYS_EXIT=1

entry $
start:
    mov eax, SYS_SET_THREAD_AREA
    mov ebx, user_desc_TLS1
    int 0x80
    mov ecx,[entry_number_TLS1]
    lea ecx,[ecx*8+3]
    mov ds,cx
; let's wait until DS spontaneously zeroes...
    xor eax,eax
checkDsZero:
    mov ax,ds
    test eax,eax
    jnz checkDsZero

    mov eax, SYS_WRITE
    mov ebx, STDERR
    mov ecx, dsZeroedMsg
    mov edx, dsZeroedMsgLen
    int 0x80

    xor ebx, ebx
    mov eax, SYS_EXIT
    int 0x80

segment readable writable
dsZeroedMsg:
    db "DS zeroed. Exiting",0xa
dsZeroedMsgLen=$-dsZeroedMsg

SEGMENT_32BIT=1
CONTENTS_DATA=0*2
CONTENTS_STACK=1*2
CONTENTS_CODE=2*2
READ_EXEC_ONLY=0x8
LIMIT_IN_PAGES=0x10
NOT_PRESENT=0x20
USABLE_BIT=0x40
LONG_MODE=0x80
user_desc_TLS1:
entry_number_TLS1:
    dd -1
base_addr_TLS1:
    dd start+0x345
limit_TLS1:
    dd 0x123
properties_TLS1:
    dd SEGMENT_32BIT+CONTENTS_DATA

这似乎与某些事实有关,即默认情况下64位进程在这两个段寄存器中都有NULL选择器。

这种情况发生在Linux 3.16.0及更早版本上,但不适用于4.2.0及更高版本。

这里发生了什么?为什么ESDS在其中包含TLS选择器时会归零,但不与其他任何选择器一起使用?

0 个答案:

没有答案