Commit 0f86d1ed authored by Shinji Tanaka's avatar Shinji Tanaka Committed by Minux Ma

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/21190Reviewed-by: default avatarAustin Clements <austin@google.com>
Reviewed-by: default avatarMinux Ma <minux@golang.org>
parent 2326c24c
...@@ -406,9 +406,18 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$-8 ...@@ -406,9 +406,18 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
#define SEG_NOT_PRESENT 0x20 #define SEG_NOT_PRESENT 0x20
#define USEABLE 0x40 #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) // 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 TEXT runtime·setldt(SB),NOSPLIT,$32
MOVL entry+0(FP), BX // entry
MOVL address+4(FP), DX // base address MOVL address+4(FP), DX // base address
#ifdef GOOS_android #ifdef GOOS_android
...@@ -437,18 +446,19 @@ TEXT runtime·setldt(SB),NOSPLIT,$32 ...@@ -437,18 +446,19 @@ TEXT runtime·setldt(SB),NOSPLIT,$32
MOVL DX, 0(DX) MOVL DX, 0(DX)
#endif #endif
// get entry number
MOVL runtime·tls_entry_number(SB), CX
// set up user_desc // set up user_desc
LEAL 16(SP), AX // struct user_desc LEAL 16(SP), AX // struct user_desc
MOVL BX, 0(AX) MOVL CX, 0(AX) // unsigned int entry_number
MOVL DX, 4(AX) MOVL DX, 4(AX) // unsigned long base_addr
MOVL $0xfffff, 8(AX) MOVL $0xfffff, 8(AX) // unsigned int limit
MOVL $(SEG_32BIT|LIMIT_IN_PAGES|USEABLE|CONTENTS_DATA), 12(AX) // flag bits MOVL $(SEG_32BIT|LIMIT_IN_PAGES|USEABLE|CONTENTS_DATA), 12(AX) // flag bits
// call modify_ldt // call set_thread_area
MOVL $1, BX // func = 1 (write) MOVL AX, BX // user_desc
MOVL AX, CX // user_desc MOVL $243, AX // syscall - set_thread_area
MOVL $16, DX // sizeof(user_desc)
MOVL $123, AX // syscall - modify_ldt
// We can't call this via 0x10(GS) because this is called from setldt0 to set that up. // We can't call this via 0x10(GS) because this is called from setldt0 to set that up.
INT $0x80 INT $0x80
...@@ -457,10 +467,18 @@ TEXT runtime·setldt(SB),NOSPLIT,$32 ...@@ -457,10 +467,18 @@ TEXT runtime·setldt(SB),NOSPLIT,$32
JLS 2(PC) JLS 2(PC)
INT $3 INT $3
// compute segment selector - (entry*8+7) // read allocated entry number back out of user_desc
MOVL entry+0(FP), AX 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 SHLL $3, AX
ADDL $7, AX ADDL $3, AX
MOVW AX, GS MOVW AX, GS
RET RET
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment