Skip to content

Commit 7358423

Browse files
josharianwheatman
authored andcommitted
runtime: use set_thread_area instead of modify_ldt on linux/386
This is a cherry-pick of https://go-review.googlesource.com/21190 to release-branch-go1.4. Diff prepared by Ian Lance Taylor. 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 golang#14795. Change-Id: I22a67d6119e5d24afaa01e2c2b8174991a8a9bf4 Reviewed-on: https://go-review.googlesource.com/31753 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
1 parent 0d6764e commit 7358423

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
@@ -379,9 +379,18 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
379379
#define SEG_NOT_PRESENT 0x20
380380
#define USEABLE 0x40
381381

382+
// `-1` means the kernel will pick a TLS entry on the first setldt call,
383+
// which happens during runtime init, and that we'll store back the saved
384+
// entry and reuse that on subsequent calls when creating new threads.
385+
DATA runtime·tls_entry_number+0(SB)/4, $-1
386+
GLOBL runtime·tls_entry_number(SB), NOPTR, $4
387+
382388
// setldt(int entry, int address, int limit)
389+
// We use set_thread_area, which mucks with the GDT, instead of modify_ldt,
390+
// which would modify the LDT, but is disabled on some kernels.
391+
// The name, setldt, is a misnomer, although we leave this name as it is for
392+
// the compatibility with other platforms.
383393
TEXT runtime·setldt(SB),NOSPLIT,$32
384-
MOVL entry+0(FP), BX // entry
385394
MOVL address+4(FP), CX // base address
386395

387396
/*
@@ -400,29 +409,38 @@ TEXT runtime·setldt(SB),NOSPLIT,$32
400409
ADDL $0x8, CX // address
401410
MOVL CX, 0(CX)
402411

412+
// get entry number
413+
MOVL runtime·tls_entry_number(SB), DX
414+
403415
// set up user_desc
404416
LEAL 16(SP), AX // struct user_desc
405-
MOVL BX, 0(AX)
406-
MOVL CX, 4(AX)
407-
MOVL $0xfffff, 8(AX)
417+
MOVL DX, 0(AX) // unsigned int entry_number
418+
MOVL CX, 4(AX) // unsigned long base_addr
419+
MOVL $0xfffff, 8(AX) // unsigned int limit
408420
MOVL $(SEG_32BIT|LIMIT_IN_PAGES|USEABLE|CONTENTS_DATA), 12(AX) // flag bits
409421

410-
// call modify_ldt
411-
MOVL $1, BX // func = 1 (write)
412-
MOVL AX, CX // user_desc
413-
MOVL $16, DX // sizeof(user_desc)
414-
MOVL $123, AX // syscall - modify_ldt
422+
// call set_thread_area
423+
MOVL AX, BX // user_desc
424+
MOVL $243, AX // syscall - set_thread_area
415425
CALL *runtime·_vdso(SB)
416426

417427
// breakpoint on error
418428
CMPL AX, $0xfffff001
419429
JLS 2(PC)
420430
INT $3
421431

422-
// compute segment selector - (entry*8+7)
423-
MOVL entry+0(FP), AX
432+
// read allocated entry number back out of user_desc
433+
LEAL 16(SP), AX // get our user_desc back
434+
MOVL 0(AX), AX
435+
436+
// store entry number if the kernel allocated it
437+
CMPL DX, $-1
438+
JNE 2(PC)
439+
MOVL AX, runtime·tls_entry_number(SB)
440+
441+
// compute segment selector - (entry*8+3)
424442
SHLL $3, AX
425-
ADDL $7, AX
443+
ADDL $3, AX
426444
MOVW AX, GS
427445

428446
RET

0 commit comments

Comments
 (0)