diff options
author | Shinji Tanaka <shinji.tanaka@gmail.com> | 2016-03-26 07:14:15 -0400 |
---|---|---|
committer | Minux Ma <minux@golang.org> | 2016-03-28 16:56:38 +0000 |
commit | 0f86d1edfb87fddb2c7f50d177b67f48219151f3 (patch) | |
tree | cf761056b5ec2fa10b07a6c76c3e5de797b0b19a /src/runtime/sys_linux_386.s | |
parent | 2326c24cc722f5093f40ea0964c93addd155ada0 (diff) | |
download | go-0f86d1edfb87fddb2c7f50d177b67f48219151f3.tar.gz go-0f86d1edfb87fddb2c7f50d177b67f48219151f3.zip |
runtime: use set_thread_area instead of modify_ldt on linux/386
linux/386 depends on modify_ldt system call, but recent Linux kernels
can disable this system call. Any Go programs built as linux/386
crash with the message 'Trace/breakpoint trap'.
The kernel config CONFIG_MODIFY_LDT_SYSCALL, which control
enable/disable modify_ldt, is disabled on Amazon Linux 2016.03.
This fixes this problem by using set_thread_area instead of modify_ldt
on linux/386.
Fixes #14795.
Change-Id: I0cc5139e40e9e5591945164156a77b6bdff2c7f1
Reviewed-on: https://go-review.googlesource.com/21190
Reviewed-by: Austin Clements <austin@google.com>
Reviewed-by: Minux Ma <minux@golang.org>
Diffstat (limited to 'src/runtime/sys_linux_386.s')
-rw-r--r-- | src/runtime/sys_linux_386.s | 42 |
1 files changed, 30 insertions, 12 deletions
diff --git a/src/runtime/sys_linux_386.s b/src/runtime/sys_linux_386.s index 3c7b17f927..3bf5eb0df4 100644 --- a/src/runtime/sys_linux_386.s +++ b/src/runtime/sys_linux_386.s @@ -406,9 +406,18 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$-8 #define SEG_NOT_PRESENT 0x20 #define USEABLE 0x40 +// `-1` means the kernel will pick a TLS entry on the first setldt call, +// which happens during runtime init, and that we'll store back the saved +// entry and reuse that on subsequent calls when creating new threads. +DATA runtime·tls_entry_number+0(SB)/4, $-1 +GLOBL runtime·tls_entry_number(SB), NOPTR, $4 + // setldt(int entry, int address, int limit) +// We use set_thread_area, which mucks with the GDT, instead of modify_ldt, +// which would modify the LDT, but is disabled on some kernels. +// The name, setldt, is a misnomer, although we leave this name as it is for +// the compatibility with other platforms. TEXT runtime·setldt(SB),NOSPLIT,$32 - MOVL entry+0(FP), BX // entry MOVL address+4(FP), DX // base address #ifdef GOOS_android @@ -437,18 +446,19 @@ TEXT runtime·setldt(SB),NOSPLIT,$32 MOVL DX, 0(DX) #endif + // get entry number + MOVL runtime·tls_entry_number(SB), CX + // set up user_desc LEAL 16(SP), AX // struct user_desc - MOVL BX, 0(AX) - MOVL DX, 4(AX) - MOVL $0xfffff, 8(AX) + MOVL CX, 0(AX) // unsigned int entry_number + MOVL DX, 4(AX) // unsigned long base_addr + MOVL $0xfffff, 8(AX) // unsigned int limit MOVL $(SEG_32BIT|LIMIT_IN_PAGES|USEABLE|CONTENTS_DATA), 12(AX) // flag bits - // call modify_ldt - MOVL $1, BX // func = 1 (write) - MOVL AX, CX // user_desc - MOVL $16, DX // sizeof(user_desc) - MOVL $123, AX // syscall - modify_ldt + // call set_thread_area + MOVL AX, BX // user_desc + MOVL $243, AX // syscall - set_thread_area // We can't call this via 0x10(GS) because this is called from setldt0 to set that up. INT $0x80 @@ -457,10 +467,18 @@ TEXT runtime·setldt(SB),NOSPLIT,$32 JLS 2(PC) INT $3 - // compute segment selector - (entry*8+7) - MOVL entry+0(FP), AX + // read allocated entry number back out of user_desc + LEAL 16(SP), AX // get our user_desc back + MOVL 0(AX), AX + + // store entry number if the kernel allocated it + CMPL CX, $-1 + JNE 2(PC) + MOVL AX, runtime·tls_entry_number(SB) + + // compute segment selector - (entry*8+3) SHLL $3, AX - ADDL $7, AX + ADDL $3, AX MOVW AX, GS RET |