Home | History | Annotate | Download | only in runtime
      1 // Copyright 2009 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 //
      6 // System calls and other sys.stuff for 386, Linux
      7 //
      8 
      9 #include "go_asm.h"
     10 #include "go_tls.h"
     11 #include "textflag.h"
     12 
     13 // Most linux systems use glibc's dynamic linker, which puts the
     14 // __kernel_vsyscall vdso helper at 0x10(GS) for easy access from position
     15 // independent code and setldt in runtime does the same in the statically
     16 // linked case. However, systems that use alternative libc such as Android's
     17 // bionic and musl, do not save the helper anywhere, and so the only way to
     18 // invoke a syscall from position independent code is boring old int $0x80
     19 // (which is also what syscall wrappers in bionic/musl use).
     20 //
     21 // The benchmarks also showed that using int $0x80 is as fast as calling
     22 // *%gs:0x10 except on AMD Opteron. See https://golang.org/cl/19833
     23 // for the benchmark program and raw data.
     24 //#define INVOKE_SYSCALL	CALL	0x10(GS) // non-portable
     25 #define INVOKE_SYSCALL	INT	$0x80
     26 
     27 #define SYS_exit		1
     28 #define SYS_read		3
     29 #define SYS_write		4
     30 #define SYS_open		5
     31 #define SYS_close		6
     32 #define SYS_getpid		20
     33 #define SYS_access		33
     34 #define SYS_kill		37
     35 #define SYS_brk 		45
     36 #define SYS_fcntl		55
     37 #define SYS_munmap		91
     38 #define SYS_socketcall		102
     39 #define SYS_setittimer		104
     40 #define SYS_clone		120
     41 #define SYS_sched_yield 	158
     42 #define SYS_rt_sigreturn	173
     43 #define SYS_rt_sigaction	174
     44 #define SYS_rt_sigprocmask	175
     45 #define SYS_sigaltstack 	186
     46 #define SYS_ugetrlimit		191
     47 #define SYS_mmap2		192
     48 #define SYS_mincore		218
     49 #define SYS_madvise		219
     50 #define SYS_gettid		224
     51 #define SYS_tkill		238
     52 #define SYS_futex		240
     53 #define SYS_sched_getaffinity	242
     54 #define SYS_set_thread_area	243
     55 #define SYS_exit_group		252
     56 #define SYS_epoll_create	254
     57 #define SYS_epoll_ctl		255
     58 #define SYS_epoll_wait		256
     59 #define SYS_clock_gettime	265
     60 #define SYS_pselect6		308
     61 #define SYS_epoll_create1	329
     62 
     63 TEXT runtimeexit(SB),NOSPLIT,$0
     64 	MOVL	$SYS_exit_group, AX
     65 	MOVL	code+0(FP), BX
     66 	INVOKE_SYSCALL
     67 	INT $3	// not reached
     68 	RET
     69 
     70 TEXT exit1<>(SB),NOSPLIT,$0
     71 	MOVL	$SYS_exit, AX
     72 	MOVL	code+0(FP), BX
     73 	INVOKE_SYSCALL
     74 	INT $3	// not reached
     75 	RET
     76 
     77 // func exitThread(wait *uint32)
     78 TEXT runtimeexitThread(SB),NOSPLIT,$0-4
     79 	MOVL	wait+0(FP), AX
     80 	// We're done using the stack.
     81 	MOVL	$0, (AX)
     82 	MOVL	$1, AX	// exit (just this thread)
     83 	MOVL	$0, BX	// exit code
     84 	INT	$0x80	// no stack; must not use CALL
     85 	// We may not even have a stack any more.
     86 	INT	$3
     87 	JMP	0(PC)
     88 
     89 TEXT runtimeopen(SB),NOSPLIT,$0
     90 	MOVL	$SYS_open, AX
     91 	MOVL	name+0(FP), BX
     92 	MOVL	mode+4(FP), CX
     93 	MOVL	perm+8(FP), DX
     94 	INVOKE_SYSCALL
     95 	CMPL	AX, $0xfffff001
     96 	JLS	2(PC)
     97 	MOVL	$-1, AX
     98 	MOVL	AX, ret+12(FP)
     99 	RET
    100 
    101 TEXT runtimeclosefd(SB),NOSPLIT,$0
    102 	MOVL	$SYS_close, AX
    103 	MOVL	fd+0(FP), BX
    104 	INVOKE_SYSCALL
    105 	CMPL	AX, $0xfffff001
    106 	JLS	2(PC)
    107 	MOVL	$-1, AX
    108 	MOVL	AX, ret+4(FP)
    109 	RET
    110 
    111 TEXT runtimewrite(SB),NOSPLIT,$0
    112 	MOVL	$SYS_write, AX
    113 	MOVL	fd+0(FP), BX
    114 	MOVL	p+4(FP), CX
    115 	MOVL	n+8(FP), DX
    116 	INVOKE_SYSCALL
    117 	CMPL	AX, $0xfffff001
    118 	JLS	2(PC)
    119 	MOVL	$-1, AX
    120 	MOVL	AX, ret+12(FP)
    121 	RET
    122 
    123 TEXT runtimeread(SB),NOSPLIT,$0
    124 	MOVL	$SYS_read, AX
    125 	MOVL	fd+0(FP), BX
    126 	MOVL	p+4(FP), CX
    127 	MOVL	n+8(FP), DX
    128 	INVOKE_SYSCALL
    129 	CMPL	AX, $0xfffff001
    130 	JLS	2(PC)
    131 	MOVL	$-1, AX
    132 	MOVL	AX, ret+12(FP)
    133 	RET
    134 
    135 TEXT runtimegetrlimit(SB),NOSPLIT,$0
    136 	MOVL	$SYS_ugetrlimit, AX
    137 	MOVL	kind+0(FP), BX
    138 	MOVL	limit+4(FP), CX
    139 	INVOKE_SYSCALL
    140 	MOVL	AX, ret+8(FP)
    141 	RET
    142 
    143 TEXT runtimeusleep(SB),NOSPLIT,$8
    144 	MOVL	$0, DX
    145 	MOVL	usec+0(FP), AX
    146 	MOVL	$1000000, CX
    147 	DIVL	CX
    148 	MOVL	AX, 0(SP)
    149 	MOVL	$1000, AX	// usec to nsec
    150 	MULL	DX
    151 	MOVL	AX, 4(SP)
    152 
    153 	// pselect6(0, 0, 0, 0, &ts, 0)
    154 	MOVL	$SYS_pselect6, AX
    155 	MOVL	$0, BX
    156 	MOVL	$0, CX
    157 	MOVL	$0, DX
    158 	MOVL	$0, SI
    159 	LEAL	0(SP), DI
    160 	MOVL	$0, BP
    161 	INVOKE_SYSCALL
    162 	RET
    163 
    164 TEXT runtimegettid(SB),NOSPLIT,$0-4
    165 	MOVL	$SYS_gettid, AX
    166 	INVOKE_SYSCALL
    167 	MOVL	AX, ret+0(FP)
    168 	RET
    169 
    170 TEXT runtimeraise(SB),NOSPLIT,$12
    171 	MOVL	$SYS_gettid, AX
    172 	INVOKE_SYSCALL
    173 	MOVL	AX, BX	// arg 1 tid
    174 	MOVL	sig+0(FP), CX	// arg 2 signal
    175 	MOVL	$SYS_tkill, AX
    176 	INVOKE_SYSCALL
    177 	RET
    178 
    179 TEXT runtimeraiseproc(SB),NOSPLIT,$12
    180 	MOVL	$SYS_getpid, AX
    181 	INVOKE_SYSCALL
    182 	MOVL	AX, BX	// arg 1 pid
    183 	MOVL	sig+0(FP), CX	// arg 2 signal
    184 	MOVL	$SYS_kill, AX
    185 	INVOKE_SYSCALL
    186 	RET
    187 
    188 TEXT runtimesetitimer(SB),NOSPLIT,$0-12
    189 	MOVL	$SYS_setittimer, AX
    190 	MOVL	mode+0(FP), BX
    191 	MOVL	new+4(FP), CX
    192 	MOVL	old+8(FP), DX
    193 	INVOKE_SYSCALL
    194 	RET
    195 
    196 TEXT runtimemincore(SB),NOSPLIT,$0-16
    197 	MOVL	$SYS_mincore, AX
    198 	MOVL	addr+0(FP), BX
    199 	MOVL	n+4(FP), CX
    200 	MOVL	dst+8(FP), DX
    201 	INVOKE_SYSCALL
    202 	MOVL	AX, ret+12(FP)
    203 	RET
    204 
    205 // func walltime() (sec int64, nsec int32)
    206 TEXT runtimewalltime(SB), NOSPLIT, $0-12
    207 	// We don't know how much stack space the VDSO code will need,
    208 	// so switch to g0.
    209 
    210 	MOVL	SP, BP	// Save old SP; BP unchanged by C code.
    211 
    212 	get_tls(CX)
    213 	MOVL	g(CX), AX
    214 	MOVL	g_m(AX), CX
    215 	MOVL	m_curg(CX), DX
    216 
    217 	CMPL	AX, DX		// Only switch if on curg.
    218 	JNE	noswitch
    219 
    220 	MOVL	m_g0(CX), DX
    221 	MOVL	(g_sched+gobuf_sp)(DX), SP	// Set SP to g0 stack
    222 
    223 noswitch:
    224 	SUBL	$16, SP		// Space for results
    225 	ANDL	$~15, SP	// Align for C code
    226 
    227 	// Stack layout, depending on call path:
    228 	//  x(SP)   vDSO            INVOKE_SYSCALL
    229 	//    12    ts.tv_nsec      ts.tv_nsec
    230 	//     8    ts.tv_sec       ts.tv_sec
    231 	//     4    &ts             -
    232 	//     0    CLOCK_<id>      -
    233 
    234 	MOVL	runtime__vdso_clock_gettime_sym(SB), AX
    235 	CMPL	AX, $0
    236 	JEQ	fallback
    237 
    238 	LEAL	8(SP), BX	// &ts (struct timespec)
    239 	MOVL	BX, 4(SP)
    240 	MOVL	$0, 0(SP)	// CLOCK_REALTIME
    241 	CALL	AX
    242 	JMP finish
    243 
    244 fallback:
    245 	MOVL	$SYS_clock_gettime, AX
    246 	MOVL	$0, BX		// CLOCK_REALTIME
    247 	LEAL	8(SP), CX
    248 	INVOKE_SYSCALL
    249 
    250 finish:
    251 	MOVL	8(SP), AX	// sec
    252 	MOVL	12(SP), BX	// nsec
    253 
    254 	MOVL	BP, SP		// Restore real SP
    255 
    256 	// sec is in AX, nsec in BX
    257 	MOVL	AX, sec_lo+0(FP)
    258 	MOVL	$0, sec_hi+4(FP)
    259 	MOVL	BX, nsec+8(FP)
    260 	RET
    261 
    262 // int64 nanotime(void) so really
    263 // void nanotime(int64 *nsec)
    264 TEXT runtimenanotime(SB), NOSPLIT, $0-8
    265 	// Switch to g0 stack. See comment above in runtimewalltime.
    266 
    267 	MOVL	SP, BP	// Save old SP; BP unchanged by C code.
    268 
    269 	get_tls(CX)
    270 	MOVL	g(CX), AX
    271 	MOVL	g_m(AX), CX
    272 	MOVL	m_curg(CX), DX
    273 
    274 	CMPL	AX, DX		// Only switch if on curg.
    275 	JNE	noswitch
    276 
    277 	MOVL	m_g0(CX), DX
    278 	MOVL	(g_sched+gobuf_sp)(DX), SP	// Set SP to g0 stack
    279 
    280 noswitch:
    281 	SUBL	$16, SP		// Space for results
    282 	ANDL	$~15, SP	// Align for C code
    283 
    284 	MOVL	runtime__vdso_clock_gettime_sym(SB), AX
    285 	CMPL	AX, $0
    286 	JEQ	fallback
    287 
    288 	LEAL	8(SP), BX	// &ts (struct timespec)
    289 	MOVL	BX, 4(SP)
    290 	MOVL	$1, 0(SP)	// CLOCK_MONOTONIC
    291 	CALL	AX
    292 	JMP finish
    293 
    294 fallback:
    295 	MOVL	$SYS_clock_gettime, AX
    296 	MOVL	$1, BX		// CLOCK_MONOTONIC
    297 	LEAL	8(SP), CX
    298 	INVOKE_SYSCALL
    299 
    300 finish:
    301 	MOVL	8(SP), AX	// sec
    302 	MOVL	12(SP), BX	// nsec
    303 
    304 	MOVL	BP, SP		// Restore real SP
    305 
    306 	// sec is in AX, nsec in BX
    307 	// convert to DX:AX nsec
    308 	MOVL	$1000000000, CX
    309 	MULL	CX
    310 	ADDL	BX, AX
    311 	ADCL	$0, DX
    312 
    313 	MOVL	AX, ret_lo+0(FP)
    314 	MOVL	DX, ret_hi+4(FP)
    315 	RET
    316 
    317 TEXT runtimertsigprocmask(SB),NOSPLIT,$0
    318 	MOVL	$SYS_rt_sigprocmask, AX
    319 	MOVL	how+0(FP), BX
    320 	MOVL	new+4(FP), CX
    321 	MOVL	old+8(FP), DX
    322 	MOVL	size+12(FP), SI
    323 	INVOKE_SYSCALL
    324 	CMPL	AX, $0xfffff001
    325 	JLS	2(PC)
    326 	INT $3
    327 	RET
    328 
    329 TEXT runtimert_sigaction(SB),NOSPLIT,$0
    330 	MOVL	$SYS_rt_sigaction, AX
    331 	MOVL	sig+0(FP), BX
    332 	MOVL	new+4(FP), CX
    333 	MOVL	old+8(FP), DX
    334 	MOVL	size+12(FP), SI
    335 	INVOKE_SYSCALL
    336 	MOVL	AX, ret+16(FP)
    337 	RET
    338 
    339 TEXT runtimesigfwd(SB),NOSPLIT,$12-16
    340 	MOVL	fn+0(FP), AX
    341 	MOVL	sig+4(FP), BX
    342 	MOVL	info+8(FP), CX
    343 	MOVL	ctx+12(FP), DX
    344 	MOVL	SP, SI
    345 	SUBL	$32, SP
    346 	ANDL	$-15, SP	// align stack: handler might be a C function
    347 	MOVL	BX, 0(SP)
    348 	MOVL	CX, 4(SP)
    349 	MOVL	DX, 8(SP)
    350 	MOVL	SI, 12(SP)	// save SI: handler might be a Go function
    351 	CALL	AX
    352 	MOVL	12(SP), AX
    353 	MOVL	AX, SP
    354 	RET
    355 
    356 TEXT runtimesigtramp(SB),NOSPLIT,$28
    357 	// Save callee-saved C registers, since the caller may be a C signal handler.
    358 	MOVL	BX, bx-4(SP)
    359 	MOVL	BP, bp-8(SP)
    360 	MOVL	SI, si-12(SP)
    361 	MOVL	DI, di-16(SP)
    362 	// We don't save mxcsr or the x87 control word because sigtrampgo doesn't
    363 	// modify them.
    364 
    365 	MOVL	sig+0(FP), BX
    366 	MOVL	BX, 0(SP)
    367 	MOVL	info+4(FP), BX
    368 	MOVL	BX, 4(SP)
    369 	MOVL	ctx+8(FP), BX
    370 	MOVL	BX, 8(SP)
    371 	CALL	runtimesigtrampgo(SB)
    372 
    373 	MOVL	di-16(SP), DI
    374 	MOVL	si-12(SP), SI
    375 	MOVL	bp-8(SP),  BP
    376 	MOVL	bx-4(SP),  BX
    377 	RET
    378 
    379 TEXT runtimecgoSigtramp(SB),NOSPLIT,$0
    380 	JMP	runtimesigtramp(SB)
    381 
    382 TEXT runtimesigreturn(SB),NOSPLIT,$0
    383 	MOVL	$SYS_rt_sigreturn, AX
    384 	// Sigreturn expects same SP as signal handler,
    385 	// so cannot CALL 0x10(GS) here.
    386 	INT	$0x80
    387 	INT	$3	// not reached
    388 	RET
    389 
    390 TEXT runtimemmap(SB),NOSPLIT,$0
    391 	MOVL	$SYS_mmap2, AX
    392 	MOVL	addr+0(FP), BX
    393 	MOVL	n+4(FP), CX
    394 	MOVL	prot+8(FP), DX
    395 	MOVL	flags+12(FP), SI
    396 	MOVL	fd+16(FP), DI
    397 	MOVL	off+20(FP), BP
    398 	SHRL	$12, BP
    399 	INVOKE_SYSCALL
    400 	CMPL	AX, $0xfffff001
    401 	JLS	ok
    402 	NOTL	AX
    403 	INCL	AX
    404 	MOVL	$0, p+24(FP)
    405 	MOVL	AX, err+28(FP)
    406 	RET
    407 ok:
    408 	MOVL	AX, p+24(FP)
    409 	MOVL	$0, err+28(FP)
    410 	RET
    411 
    412 TEXT runtimemunmap(SB),NOSPLIT,$0
    413 	MOVL	$SYS_munmap, AX
    414 	MOVL	addr+0(FP), BX
    415 	MOVL	n+4(FP), CX
    416 	INVOKE_SYSCALL
    417 	CMPL	AX, $0xfffff001
    418 	JLS	2(PC)
    419 	INT $3
    420 	RET
    421 
    422 TEXT runtimemadvise(SB),NOSPLIT,$0
    423 	MOVL	$SYS_madvise, AX
    424 	MOVL	addr+0(FP), BX
    425 	MOVL	n+4(FP), CX
    426 	MOVL	flags+8(FP), DX
    427 	INVOKE_SYSCALL
    428 	// ignore failure - maybe pages are locked
    429 	RET
    430 
    431 // int32 futex(int32 *uaddr, int32 op, int32 val,
    432 //	struct timespec *timeout, int32 *uaddr2, int32 val2);
    433 TEXT runtimefutex(SB),NOSPLIT,$0
    434 	MOVL	$SYS_futex, AX
    435 	MOVL	addr+0(FP), BX
    436 	MOVL	op+4(FP), CX
    437 	MOVL	val+8(FP), DX
    438 	MOVL	ts+12(FP), SI
    439 	MOVL	addr2+16(FP), DI
    440 	MOVL	val3+20(FP), BP
    441 	INVOKE_SYSCALL
    442 	MOVL	AX, ret+24(FP)
    443 	RET
    444 
    445 // int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void));
    446 TEXT runtimeclone(SB),NOSPLIT,$0
    447 	MOVL	$SYS_clone, AX
    448 	MOVL	flags+0(FP), BX
    449 	MOVL	stk+4(FP), CX
    450 	MOVL	$0, DX	// parent tid ptr
    451 	MOVL	$0, DI	// child tid ptr
    452 
    453 	// Copy mp, gp, fn off parent stack for use by child.
    454 	SUBL	$16, CX
    455 	MOVL	mp+8(FP), SI
    456 	MOVL	SI, 0(CX)
    457 	MOVL	gp+12(FP), SI
    458 	MOVL	SI, 4(CX)
    459 	MOVL	fn+16(FP), SI
    460 	MOVL	SI, 8(CX)
    461 	MOVL	$1234, 12(CX)
    462 
    463 	// cannot use CALL 0x10(GS) here, because the stack changes during the
    464 	// system call (after CALL 0x10(GS), the child is still using the
    465 	// parent's stack when executing its RET instruction).
    466 	INT	$0x80
    467 
    468 	// In parent, return.
    469 	CMPL	AX, $0
    470 	JEQ	3(PC)
    471 	MOVL	AX, ret+20(FP)
    472 	RET
    473 
    474 	// Paranoia: check that SP is as we expect.
    475 	MOVL	12(SP), BP
    476 	CMPL	BP, $1234
    477 	JEQ	2(PC)
    478 	INT	$3
    479 
    480 	// Initialize AX to Linux tid
    481 	MOVL	$SYS_gettid, AX
    482 	INVOKE_SYSCALL
    483 
    484 	MOVL	0(SP), BX	    // m
    485 	MOVL	4(SP), DX	    // g
    486 	MOVL	8(SP), SI	    // fn
    487 
    488 	CMPL	BX, $0
    489 	JEQ	nog
    490 	CMPL	DX, $0
    491 	JEQ	nog
    492 
    493 	MOVL	AX, m_procid(BX)	// save tid as m->procid
    494 
    495 	// set up ldt 7+id to point at m->tls.
    496 	LEAL	m_tls(BX), BP
    497 	MOVL	m_id(BX), DI
    498 	ADDL	$7, DI	// m0 is LDT#7. count up.
    499 	// setldt(tls#, &tls, sizeof tls)
    500 	PUSHAL	// save registers
    501 	PUSHL	$32	// sizeof tls
    502 	PUSHL	BP	// &tls
    503 	PUSHL	DI	// tls #
    504 	CALL	runtimesetldt(SB)
    505 	POPL	AX
    506 	POPL	AX
    507 	POPL	AX
    508 	POPAL
    509 
    510 	// Now segment is established. Initialize m, g.
    511 	get_tls(AX)
    512 	MOVL	DX, g(AX)
    513 	MOVL	BX, g_m(DX)
    514 
    515 	CALL	runtimestackcheck(SB)	// smashes AX, CX
    516 	MOVL	0(DX), DX	// paranoia; check they are not nil
    517 	MOVL	0(BX), BX
    518 
    519 	// more paranoia; check that stack splitting code works
    520 	PUSHAL
    521 	CALL	runtimeemptyfunc(SB)
    522 	POPAL
    523 
    524 nog:
    525 	CALL	SI	// fn()
    526 	CALL	exit1<>(SB)
    527 	MOVL	$0x1234, 0x1005
    528 
    529 TEXT runtimesigaltstack(SB),NOSPLIT,$-8
    530 	MOVL	$SYS_sigaltstack, AX
    531 	MOVL	new+0(FP), BX
    532 	MOVL	old+4(FP), CX
    533 	INVOKE_SYSCALL
    534 	CMPL	AX, $0xfffff001
    535 	JLS	2(PC)
    536 	INT	$3
    537 	RET
    538 
    539 // <asm-i386/ldt.h>
    540 // struct user_desc {
    541 //	unsigned int  entry_number;
    542 //	unsigned long base_addr;
    543 //	unsigned int  limit;
    544 //	unsigned int  seg_32bit:1;
    545 //	unsigned int  contents:2;
    546 //	unsigned int  read_exec_only:1;
    547 //	unsigned int  limit_in_pages:1;
    548 //	unsigned int  seg_not_present:1;
    549 //	unsigned int  useable:1;
    550 // };
    551 #define SEG_32BIT 0x01
    552 // contents are the 2 bits 0x02 and 0x04.
    553 #define CONTENTS_DATA 0x00
    554 #define CONTENTS_STACK 0x02
    555 #define CONTENTS_CODE 0x04
    556 #define READ_EXEC_ONLY 0x08
    557 #define LIMIT_IN_PAGES 0x10
    558 #define SEG_NOT_PRESENT 0x20
    559 #define USEABLE 0x40
    560 
    561 // `-1` means the kernel will pick a TLS entry on the first setldt call,
    562 // which happens during runtime init, and that we'll store back the saved
    563 // entry and reuse that on subsequent calls when creating new threads.
    564 DATA  runtimetls_entry_number+0(SB)/4, $-1
    565 GLOBL runtimetls_entry_number(SB), NOPTR, $4
    566 
    567 // setldt(int entry, int address, int limit)
    568 // We use set_thread_area, which mucks with the GDT, instead of modify_ldt,
    569 // which would modify the LDT, but is disabled on some kernels.
    570 // The name, setldt, is a misnomer, although we leave this name as it is for
    571 // the compatibility with other platforms.
    572 TEXT runtimesetldt(SB),NOSPLIT,$32
    573 	MOVL	address+4(FP), DX	// base address
    574 
    575 #ifdef GOOS_android
    576 	/*
    577 	 * Same as in sys_darwin_386.s:/ugliness, different constant.
    578 	 * address currently holds m->tls, which must be %gs:0xf8.
    579 	 * See cgo/gcc_android_386.c for the derivation of the constant.
    580 	 */
    581 	SUBL	$0xf8, DX
    582 	MOVL	DX, 0(DX)
    583 #else
    584 	/*
    585 	 * When linking against the system libraries,
    586 	 * we use its pthread_create and let it set up %gs
    587 	 * for us.  When we do that, the private storage
    588 	 * we get is not at 0(GS), but -4(GS).
    589 	 * To insulate the rest of the tool chain from this
    590 	 * ugliness, 8l rewrites 0(TLS) into -4(GS) for us.
    591 	 * To accommodate that rewrite, we translate
    592 	 * the address here and bump the limit to 0xffffffff (no limit)
    593 	 * so that -4(GS) maps to 0(address).
    594 	 * Also, the final 0(GS) (current 4(DX)) has to point
    595 	 * to itself, to mimic ELF.
    596 	 */
    597 	ADDL	$0x4, DX	// address
    598 	MOVL	DX, 0(DX)
    599 #endif
    600 
    601 	// get entry number
    602 	MOVL	runtimetls_entry_number(SB), CX
    603 
    604 	// set up user_desc
    605 	LEAL	16(SP), AX	// struct user_desc
    606 	MOVL	CX, 0(AX)	// unsigned int entry_number
    607 	MOVL	DX, 4(AX)	// unsigned long base_addr
    608 	MOVL	$0xfffff, 8(AX)	// unsigned int limit
    609 	MOVL	$(SEG_32BIT|LIMIT_IN_PAGES|USEABLE|CONTENTS_DATA), 12(AX)	// flag bits
    610 
    611 	// call set_thread_area
    612 	MOVL	AX, BX	// user_desc
    613 	MOVL	$SYS_set_thread_area, AX
    614 	// We can't call this via 0x10(GS) because this is called from setldt0 to set that up.
    615 	INT     $0x80
    616 
    617 	// breakpoint on error
    618 	CMPL AX, $0xfffff001
    619 	JLS 2(PC)
    620 	INT $3
    621 
    622 	// read allocated entry number back out of user_desc
    623 	LEAL	16(SP), AX	// get our user_desc back
    624 	MOVL	0(AX), AX
    625 
    626 	// store entry number if the kernel allocated it
    627 	CMPL	CX, $-1
    628 	JNE	2(PC)
    629 	MOVL	AX, runtimetls_entry_number(SB)
    630 
    631 	// compute segment selector - (entry*8+3)
    632 	SHLL	$3, AX
    633 	ADDL	$3, AX
    634 	MOVW	AX, GS
    635 
    636 	RET
    637 
    638 TEXT runtimeosyield(SB),NOSPLIT,$0
    639 	MOVL	$SYS_sched_yield, AX
    640 	INVOKE_SYSCALL
    641 	RET
    642 
    643 TEXT runtimesched_getaffinity(SB),NOSPLIT,$0
    644 	MOVL	$SYS_sched_getaffinity, AX
    645 	MOVL	pid+0(FP), BX
    646 	MOVL	len+4(FP), CX
    647 	MOVL	buf+8(FP), DX
    648 	INVOKE_SYSCALL
    649 	MOVL	AX, ret+12(FP)
    650 	RET
    651 
    652 // int32 runtimeepollcreate(int32 size);
    653 TEXT runtimeepollcreate(SB),NOSPLIT,$0
    654 	MOVL    $SYS_epoll_create, AX
    655 	MOVL	size+0(FP), BX
    656 	INVOKE_SYSCALL
    657 	MOVL	AX, ret+4(FP)
    658 	RET
    659 
    660 // int32 runtimeepollcreate1(int32 flags);
    661 TEXT runtimeepollcreate1(SB),NOSPLIT,$0
    662 	MOVL    $SYS_epoll_create1, AX
    663 	MOVL	flags+0(FP), BX
    664 	INVOKE_SYSCALL
    665 	MOVL	AX, ret+4(FP)
    666 	RET
    667 
    668 // func epollctl(epfd, op, fd int32, ev *epollEvent) int
    669 TEXT runtimeepollctl(SB),NOSPLIT,$0
    670 	MOVL	$SYS_epoll_ctl, AX
    671 	MOVL	epfd+0(FP), BX
    672 	MOVL	op+4(FP), CX
    673 	MOVL	fd+8(FP), DX
    674 	MOVL	ev+12(FP), SI
    675 	INVOKE_SYSCALL
    676 	MOVL	AX, ret+16(FP)
    677 	RET
    678 
    679 // int32 runtimeepollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout);
    680 TEXT runtimeepollwait(SB),NOSPLIT,$0
    681 	MOVL	$SYS_epoll_wait, AX
    682 	MOVL	epfd+0(FP), BX
    683 	MOVL	ev+4(FP), CX
    684 	MOVL	nev+8(FP), DX
    685 	MOVL	timeout+12(FP), SI
    686 	INVOKE_SYSCALL
    687 	MOVL	AX, ret+16(FP)
    688 	RET
    689 
    690 // void runtimecloseonexec(int32 fd);
    691 TEXT runtimecloseonexec(SB),NOSPLIT,$0
    692 	MOVL	$SYS_fcntl, AX
    693 	MOVL	fd+0(FP), BX  // fd
    694 	MOVL	$2, CX  // F_SETFD
    695 	MOVL	$1, DX  // FD_CLOEXEC
    696 	INVOKE_SYSCALL
    697 	RET
    698 
    699 // int access(const char *name, int mode)
    700 TEXT runtimeaccess(SB),NOSPLIT,$0
    701 	MOVL	$SYS_access, AX
    702 	MOVL	name+0(FP), BX
    703 	MOVL	mode+4(FP), CX
    704 	INVOKE_SYSCALL
    705 	MOVL	AX, ret+8(FP)
    706 	RET
    707 
    708 // int connect(int fd, const struct sockaddr *addr, socklen_t addrlen)
    709 TEXT runtimeconnect(SB),NOSPLIT,$0-16
    710 	// connect is implemented as socketcall(NR_socket, 3, *(rest of args))
    711 	// stack already should have fd, addr, addrlen.
    712 	MOVL	$SYS_socketcall, AX
    713 	MOVL	$3, BX  // connect
    714 	LEAL	fd+0(FP), CX
    715 	INVOKE_SYSCALL
    716 	MOVL	AX, ret+12(FP)
    717 	RET
    718 
    719 // int socket(int domain, int type, int protocol)
    720 TEXT runtimesocket(SB),NOSPLIT,$0-16
    721 	// socket is implemented as socketcall(NR_socket, 1, *(rest of args))
    722 	// stack already should have domain, type, protocol.
    723 	MOVL	$SYS_socketcall, AX
    724 	MOVL	$1, BX  // socket
    725 	LEAL	domain+0(FP), CX
    726 	INVOKE_SYSCALL
    727 	MOVL	AX, ret+12(FP)
    728 	RET
    729 
    730 // func sbrk0() uintptr
    731 TEXT runtimesbrk0(SB),NOSPLIT,$0-4
    732 	// Implemented as brk(NULL).
    733 	MOVL	$SYS_brk, AX
    734 	MOVL	$0, BX  // NULL
    735 	INVOKE_SYSCALL
    736 	MOVL	AX, ret+0(FP)
    737 	RET
    738