Skip to content

Commit 0f86d1e

Browse files
stanakaminux
authored andcommitted
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>
1 parent 2326c24 commit 0f86d1e

File tree

1 file changed

+30
-12
lines changed

1 file changed

+30
-12
lines changed

src/runtime/sys_linux_386.s

+30-12
Original file line numberDiff line numberDiff line change
@@ -406,9 +406,18 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
406406
#define SEG_NOT_PRESENT 0x20
407407
#define USEABLE 0x40
408408

409+
// `-1` means the kernel will pick a TLS entry on the first setldt call,
410+
// which happens during runtime init, and that we'll store back the saved
411+
// entry and reuse that on subsequent calls when creating new threads.
412+
DATA runtime·tls_entry_number+0(SB)/4, $-1
413+
GLOBL runtime·tls_entry_number(SB), NOPTR, $4
414+
409415
// setldt(int entry, int address, int limit)
416+
// We use set_thread_area, which mucks with the GDT, instead of modify_ldt,
417+
// which would modify the LDT, but is disabled on some kernels.
418+
// The name, setldt, is a misnomer, although we leave this name as it is for
419+
// the compatibility with other platforms.
410420
TEXT runtime·setldt(SB),NOSPLIT,$32
411-
MOVL entry+0(FP), BX // entry
412421
MOVL address+4(FP), DX // base address
413422

414423
#ifdef GOOS_android
@@ -437,18 +446,19 @@ TEXT runtime·setldt(SB),NOSPLIT,$32
437446
MOVL DX, 0(DX)
438447
#endif
439448

449+
// get entry number
450+
MOVL runtime·tls_entry_number(SB), CX
451+
440452
// set up user_desc
441453
LEAL 16(SP), AX // struct user_desc
442-
MOVL BX, 0(AX)
443-
MOVL DX, 4(AX)
444-
MOVL $0xfffff, 8(AX)
454+
MOVL CX, 0(AX) // unsigned int entry_number
455+
MOVL DX, 4(AX) // unsigned long base_addr
456+
MOVL $0xfffff, 8(AX) // unsigned int limit
445457
MOVL $(SEG_32BIT|LIMIT_IN_PAGES|USEABLE|CONTENTS_DATA), 12(AX) // flag bits
446458

447-
// call modify_ldt
448-
MOVL $1, BX // func = 1 (write)
449-
MOVL AX, CX // user_desc
450-
MOVL $16, DX // sizeof(user_desc)
451-
MOVL $123, AX // syscall - modify_ldt
459+
// call set_thread_area
460+
MOVL AX, BX // user_desc
461+
MOVL $243, AX // syscall - set_thread_area
452462
// We can't call this via 0x10(GS) because this is called from setldt0 to set that up.
453463
INT $0x80
454464

@@ -457,10 +467,18 @@ TEXT runtime·setldt(SB),NOSPLIT,$32
457467
JLS 2(PC)
458468
INT $3
459469

460-
// compute segment selector - (entry*8+7)
461-
MOVL entry+0(FP), AX
470+
// read allocated entry number back out of user_desc
471+
LEAL 16(SP), AX // get our user_desc back
472+
MOVL 0(AX), AX
473+
474+
// store entry number if the kernel allocated it
475+
CMPL CX, $-1
476+
JNE 2(PC)
477+
MOVL AX, runtime·tls_entry_number(SB)
478+
479+
// compute segment selector - (entry*8+3)
462480
SHLL $3, AX
463-
ADDL $7, AX
481+
ADDL $3, AX
464482
MOVW AX, GS
465483

466484
RET

0 commit comments

Comments
 (0)