aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/sys_linux_386.s
diff options
context:
space:
mode:
authorShinji Tanaka <shinji.tanaka@gmail.com>2016-03-26 07:14:15 -0400
committerMinux Ma <minux@golang.org>2016-03-28 16:56:38 +0000
commit0f86d1edfb87fddb2c7f50d177b67f48219151f3 (patch)
treecf761056b5ec2fa10b07a6c76c3e5de797b0b19a /src/runtime/sys_linux_386.s
parent2326c24cc722f5093f40ea0964c93addd155ada0 (diff)
downloadgo-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.s42
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