Text file
src/runtime/sys_linux_386.s
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_munmap 91
37 #define SYS_socketcall 102
38 #define SYS_setittimer 104
39 #define SYS_clone 120
40 #define SYS_sched_yield 158
41 #define SYS_nanosleep 162
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_mmap2 192
47 #define SYS_mincore 218
48 #define SYS_madvise 219
49 #define SYS_gettid 224
50 #define SYS_futex 240
51 #define SYS_sched_getaffinity 242
52 #define SYS_set_thread_area 243
53 #define SYS_exit_group 252
54 #define SYS_timer_create 259
55 #define SYS_timer_settime 260
56 #define SYS_timer_delete 263
57 #define SYS_clock_gettime 265
58 #define SYS_tgkill 270
59 #define SYS_pipe2 331
60
61 TEXT runtime·exit(SB),NOSPLIT,$0
62 MOVL $SYS_exit_group, AX
63 MOVL code+0(FP), BX
64 INVOKE_SYSCALL
65 INT $3 // not reached
66 RET
67
68 TEXT exit1<>(SB),NOSPLIT,$0
69 MOVL $SYS_exit, AX
70 MOVL code+0(FP), BX
71 INVOKE_SYSCALL
72 INT $3 // not reached
73 RET
74
75 // func exitThread(wait *atomic.Uint32)
76 TEXT runtime·exitThread(SB),NOSPLIT,$0-4
77 MOVL wait+0(FP), AX
78 // We're done using the stack.
79 MOVL $0, (AX)
80 MOVL $1, AX // exit (just this thread)
81 MOVL $0, BX // exit code
82 INT $0x80 // no stack; must not use CALL
83 // We may not even have a stack any more.
84 INT $3
85 JMP 0(PC)
86
87 TEXT runtime·open(SB),NOSPLIT,$0
88 MOVL $SYS_open, AX
89 MOVL name+0(FP), BX
90 MOVL mode+4(FP), CX
91 MOVL perm+8(FP), DX
92 INVOKE_SYSCALL
93 CMPL AX, $0xfffff001
94 JLS 2(PC)
95 MOVL $-1, AX
96 MOVL AX, ret+12(FP)
97 RET
98
99 TEXT runtime·closefd(SB),NOSPLIT,$0
100 MOVL $SYS_close, AX
101 MOVL fd+0(FP), BX
102 INVOKE_SYSCALL
103 CMPL AX, $0xfffff001
104 JLS 2(PC)
105 MOVL $-1, AX
106 MOVL AX, ret+4(FP)
107 RET
108
109 TEXT runtime·write1(SB),NOSPLIT,$0
110 MOVL $SYS_write, AX
111 MOVL fd+0(FP), BX
112 MOVL p+4(FP), CX
113 MOVL n+8(FP), DX
114 INVOKE_SYSCALL
115 MOVL AX, ret+12(FP)
116 RET
117
118 TEXT runtime·read(SB),NOSPLIT,$0
119 MOVL $SYS_read, AX
120 MOVL fd+0(FP), BX
121 MOVL p+4(FP), CX
122 MOVL n+8(FP), DX
123 INVOKE_SYSCALL
124 MOVL AX, ret+12(FP)
125 RET
126
127 // func pipe2(flags int32) (r, w int32, errno int32)
128 TEXT runtime·pipe2(SB),NOSPLIT,$0-16
129 MOVL $SYS_pipe2, AX
130 LEAL r+4(FP), BX
131 MOVL flags+0(FP), CX
132 INVOKE_SYSCALL
133 MOVL AX, errno+12(FP)
134 RET
135
136 TEXT runtime·usleep(SB),NOSPLIT,$8
137 MOVL $0, DX
138 MOVL usec+0(FP), AX
139 MOVL $1000000, CX
140 DIVL CX
141 MOVL AX, 0(SP)
142 MOVL $1000, AX // usec to nsec
143 MULL DX
144 MOVL AX, 4(SP)
145
146 // nanosleep(&ts, 0)
147 MOVL $SYS_nanosleep, AX
148 LEAL 0(SP), BX
149 MOVL $0, CX
150 INVOKE_SYSCALL
151 RET
152
153 TEXT runtime·gettid(SB),NOSPLIT,$0-4
154 MOVL $SYS_gettid, AX
155 INVOKE_SYSCALL
156 MOVL AX, ret+0(FP)
157 RET
158
159 TEXT runtime·raise(SB),NOSPLIT,$12
160 MOVL $SYS_getpid, AX
161 INVOKE_SYSCALL
162 MOVL AX, BX // arg 1 pid
163 MOVL $SYS_gettid, AX
164 INVOKE_SYSCALL
165 MOVL AX, CX // arg 2 tid
166 MOVL sig+0(FP), DX // arg 3 signal
167 MOVL $SYS_tgkill, AX
168 INVOKE_SYSCALL
169 RET
170
171 TEXT runtime·raiseproc(SB),NOSPLIT,$12
172 MOVL $SYS_getpid, AX
173 INVOKE_SYSCALL
174 MOVL AX, BX // arg 1 pid
175 MOVL sig+0(FP), CX // arg 2 signal
176 MOVL $SYS_kill, AX
177 INVOKE_SYSCALL
178 RET
179
180 TEXT ·getpid(SB),NOSPLIT,$0-4
181 MOVL $SYS_getpid, AX
182 INVOKE_SYSCALL
183 MOVL AX, ret+0(FP)
184 RET
185
186 TEXT ·tgkill(SB),NOSPLIT,$0
187 MOVL $SYS_tgkill, AX
188 MOVL tgid+0(FP), BX
189 MOVL tid+4(FP), CX
190 MOVL sig+8(FP), DX
191 INVOKE_SYSCALL
192 RET
193
194 TEXT runtime·setitimer(SB),NOSPLIT,$0-12
195 MOVL $SYS_setittimer, AX
196 MOVL mode+0(FP), BX
197 MOVL new+4(FP), CX
198 MOVL old+8(FP), DX
199 INVOKE_SYSCALL
200 RET
201
202 TEXT runtime·timer_create(SB),NOSPLIT,$0-16
203 MOVL $SYS_timer_create, AX
204 MOVL clockid+0(FP), BX
205 MOVL sevp+4(FP), CX
206 MOVL timerid+8(FP), DX
207 INVOKE_SYSCALL
208 MOVL AX, ret+12(FP)
209 RET
210
211 TEXT runtime·timer_settime(SB),NOSPLIT,$0-20
212 MOVL $SYS_timer_settime, AX
213 MOVL timerid+0(FP), BX
214 MOVL flags+4(FP), CX
215 MOVL new+8(FP), DX
216 MOVL old+12(FP), SI
217 INVOKE_SYSCALL
218 MOVL AX, ret+16(FP)
219 RET
220
221 TEXT runtime·timer_delete(SB),NOSPLIT,$0-8
222 MOVL $SYS_timer_delete, AX
223 MOVL timerid+0(FP), BX
224 INVOKE_SYSCALL
225 MOVL AX, ret+4(FP)
226 RET
227
228 TEXT runtime·mincore(SB),NOSPLIT,$0-16
229 MOVL $SYS_mincore, AX
230 MOVL addr+0(FP), BX
231 MOVL n+4(FP), CX
232 MOVL dst+8(FP), DX
233 INVOKE_SYSCALL
234 MOVL AX, ret+12(FP)
235 RET
236
237 // func walltime() (sec int64, nsec int32)
238 TEXT runtime·walltime(SB), NOSPLIT, $8-12
239 // We don't know how much stack space the VDSO code will need,
240 // so switch to g0.
241
242 MOVL SP, BP // Save old SP; BP unchanged by C code.
243
244 get_tls(CX)
245 MOVL g(CX), AX
246 MOVL g_m(AX), SI // SI unchanged by C code.
247
248 // Set vdsoPC and vdsoSP for SIGPROF traceback.
249 // Save the old values on stack and restore them on exit,
250 // so this function is reentrant.
251 MOVL m_vdsoPC(SI), CX
252 MOVL m_vdsoSP(SI), DX
253 MOVL CX, 0(SP)
254 MOVL DX, 4(SP)
255
256 LEAL sec+0(FP), DX
257 MOVL -4(DX), CX
258 MOVL CX, m_vdsoPC(SI)
259 MOVL DX, m_vdsoSP(SI)
260
261 CMPL AX, m_curg(SI) // Only switch if on curg.
262 JNE noswitch
263
264 MOVL m_g0(SI), DX
265 MOVL (g_sched+gobuf_sp)(DX), SP // Set SP to g0 stack
266
267 noswitch:
268 SUBL $16, SP // Space for results
269 ANDL $~15, SP // Align for C code
270
271 // Stack layout, depending on call path:
272 // x(SP) vDSO INVOKE_SYSCALL
273 // 12 ts.tv_nsec ts.tv_nsec
274 // 8 ts.tv_sec ts.tv_sec
275 // 4 &ts -
276 // 0 CLOCK_<id> -
277
278 MOVL runtime·vdsoClockgettimeSym(SB), AX
279 CMPL AX, $0
280 JEQ fallback
281
282 LEAL 8(SP), BX // &ts (struct timespec)
283 MOVL BX, 4(SP)
284 MOVL $0, 0(SP) // CLOCK_REALTIME
285 CALL AX
286 JMP finish
287
288 fallback:
289 MOVL $SYS_clock_gettime, AX
290 MOVL $0, BX // CLOCK_REALTIME
291 LEAL 8(SP), CX
292 INVOKE_SYSCALL
293
294 finish:
295 MOVL 8(SP), AX // sec
296 MOVL 12(SP), BX // nsec
297
298 MOVL BP, SP // Restore real SP
299 // Restore vdsoPC, vdsoSP
300 // We don't worry about being signaled between the two stores.
301 // If we are not in a signal handler, we'll restore vdsoSP to 0,
302 // and no one will care about vdsoPC. If we are in a signal handler,
303 // we cannot receive another signal.
304 MOVL 4(SP), CX
305 MOVL CX, m_vdsoSP(SI)
306 MOVL 0(SP), CX
307 MOVL CX, m_vdsoPC(SI)
308
309 // sec is in AX, nsec in BX
310 MOVL AX, sec_lo+0(FP)
311 MOVL $0, sec_hi+4(FP)
312 MOVL BX, nsec+8(FP)
313 RET
314
315 // int64 nanotime(void) so really
316 // void nanotime(int64 *nsec)
317 TEXT runtime·nanotime1(SB), NOSPLIT, $8-8
318 // Switch to g0 stack. See comment above in runtime·walltime.
319
320 MOVL SP, BP // Save old SP; BP unchanged by C code.
321
322 get_tls(CX)
323 MOVL g(CX), AX
324 MOVL g_m(AX), SI // SI unchanged by C code.
325
326 // Set vdsoPC and vdsoSP for SIGPROF traceback.
327 // Save the old values on stack and restore them on exit,
328 // so this function is reentrant.
329 MOVL m_vdsoPC(SI), CX
330 MOVL m_vdsoSP(SI), DX
331 MOVL CX, 0(SP)
332 MOVL DX, 4(SP)
333
334 LEAL ret+0(FP), DX
335 MOVL -4(DX), CX
336 MOVL CX, m_vdsoPC(SI)
337 MOVL DX, m_vdsoSP(SI)
338
339 CMPL AX, m_curg(SI) // Only switch if on curg.
340 JNE noswitch
341
342 MOVL m_g0(SI), DX
343 MOVL (g_sched+gobuf_sp)(DX), SP // Set SP to g0 stack
344
345 noswitch:
346 SUBL $16, SP // Space for results
347 ANDL $~15, SP // Align for C code
348
349 MOVL runtime·vdsoClockgettimeSym(SB), AX
350 CMPL AX, $0
351 JEQ fallback
352
353 LEAL 8(SP), BX // &ts (struct timespec)
354 MOVL BX, 4(SP)
355 MOVL $1, 0(SP) // CLOCK_MONOTONIC
356 CALL AX
357 JMP finish
358
359 fallback:
360 MOVL $SYS_clock_gettime, AX
361 MOVL $1, BX // CLOCK_MONOTONIC
362 LEAL 8(SP), CX
363 INVOKE_SYSCALL
364
365 finish:
366 MOVL 8(SP), AX // sec
367 MOVL 12(SP), BX // nsec
368
369 MOVL BP, SP // Restore real SP
370 // Restore vdsoPC, vdsoSP
371 // We don't worry about being signaled between the two stores.
372 // If we are not in a signal handler, we'll restore vdsoSP to 0,
373 // and no one will care about vdsoPC. If we are in a signal handler,
374 // we cannot receive another signal.
375 MOVL 4(SP), CX
376 MOVL CX, m_vdsoSP(SI)
377 MOVL 0(SP), CX
378 MOVL CX, m_vdsoPC(SI)
379
380 // sec is in AX, nsec in BX
381 // convert to DX:AX nsec
382 MOVL $1000000000, CX
383 MULL CX
384 ADDL BX, AX
385 ADCL $0, DX
386
387 MOVL AX, ret_lo+0(FP)
388 MOVL DX, ret_hi+4(FP)
389 RET
390
391 TEXT runtime·rtsigprocmask(SB),NOSPLIT,$0
392 MOVL $SYS_rt_sigprocmask, AX
393 MOVL how+0(FP), BX
394 MOVL new+4(FP), CX
395 MOVL old+8(FP), DX
396 MOVL size+12(FP), SI
397 INVOKE_SYSCALL
398 CMPL AX, $0xfffff001
399 JLS 2(PC)
400 INT $3
401 RET
402
403 TEXT runtime·rt_sigaction(SB),NOSPLIT,$0
404 MOVL $SYS_rt_sigaction, AX
405 MOVL sig+0(FP), BX
406 MOVL new+4(FP), CX
407 MOVL old+8(FP), DX
408 MOVL size+12(FP), SI
409 INVOKE_SYSCALL
410 MOVL AX, ret+16(FP)
411 RET
412
413 // Call the function stored in _cgo_sigaction using the GCC calling convention.
414 TEXT runtime·callCgoSigaction(SB),NOSPLIT,$0-16
415 MOVL _cgo_sigaction(SB), AX
416 MOVL sig+0(FP), BX
417 MOVL new+4(FP), CX
418 MOVL old+8(FP), DX
419 MOVL SP, SI // align stack to call C function
420 SUBL $32, SP
421 ANDL $~15, SP
422 MOVL BX, 0(SP)
423 MOVL CX, 4(SP)
424 MOVL DX, 8(SP)
425 MOVL SI, 12(SP)
426 CALL AX
427 MOVL 12(SP), BX
428 MOVL BX, SP
429 MOVL AX, ret+12(FP)
430 RET
431
432 TEXT runtime·sigfwd(SB),NOSPLIT,$12-16
433 MOVL fn+0(FP), AX
434 MOVL sig+4(FP), BX
435 MOVL info+8(FP), CX
436 MOVL ctx+12(FP), DX
437 MOVL SP, SI
438 SUBL $32, SP
439 ANDL $-15, SP // align stack: handler might be a C function
440 MOVL BX, 0(SP)
441 MOVL CX, 4(SP)
442 MOVL DX, 8(SP)
443 MOVL SI, 12(SP) // save SI: handler might be a Go function
444 CALL AX
445 MOVL 12(SP), AX
446 MOVL AX, SP
447 RET
448
449 // Called using C ABI.
450 TEXT runtime·sigtramp(SB),NOSPLIT|TOPFRAME,$28
451 // Save callee-saved C registers, since the caller may be a C signal handler.
452 MOVL BX, bx-4(SP)
453 MOVL BP, bp-8(SP)
454 MOVL SI, si-12(SP)
455 MOVL DI, di-16(SP)
456 // We don't save mxcsr or the x87 control word because sigtrampgo doesn't
457 // modify them.
458
459 MOVL (28+4)(SP), BX
460 MOVL BX, 0(SP)
461 MOVL (28+8)(SP), BX
462 MOVL BX, 4(SP)
463 MOVL (28+12)(SP), BX
464 MOVL BX, 8(SP)
465 CALL runtime·sigtrampgo(SB)
466
467 MOVL di-16(SP), DI
468 MOVL si-12(SP), SI
469 MOVL bp-8(SP), BP
470 MOVL bx-4(SP), BX
471 RET
472
473 TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
474 JMP runtime·sigtramp(SB)
475
476 // For cgo unwinding to work, this function must look precisely like
477 // the one in glibc. The glibc source code is:
478 // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/i386/libc_sigaction.c;h=0665b41bbcd0986f0b33bf19a7ecbcedf9961d0a#l59
479 // The code that cares about the precise instructions used is:
480 // https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libgcc/config/i386/linux-unwind.h;h=5486223d60272c73d5103b29ae592d2ee998e1cf#l136
481 //
482 // For gdb unwinding to work, this function must look precisely like the one in
483 // glibc and must be named "__restore_rt" or contain the string "sigaction" in
484 // the name. The gdb source code is:
485 // https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gdb/i386-linux-tdep.c;h=a6adeca1b97416f7194341151a8ce30723a786a3#l168
486 TEXT runtime·sigreturn__sigaction(SB),NOSPLIT,$0
487 MOVL $SYS_rt_sigreturn, AX
488 // Sigreturn expects same SP as signal handler,
489 // so cannot CALL 0x10(GS) here.
490 INT $0x80
491 INT $3 // not reached
492 RET
493
494 TEXT runtime·mmap(SB),NOSPLIT,$0
495 MOVL $SYS_mmap2, AX
496 MOVL addr+0(FP), BX
497 MOVL n+4(FP), CX
498 MOVL prot+8(FP), DX
499 MOVL flags+12(FP), SI
500 MOVL fd+16(FP), DI
501 MOVL off+20(FP), BP
502 SHRL $12, BP
503 INVOKE_SYSCALL
504 CMPL AX, $0xfffff001
505 JLS ok
506 NOTL AX
507 INCL AX
508 MOVL $0, p+24(FP)
509 MOVL AX, err+28(FP)
510 RET
511 ok:
512 MOVL AX, p+24(FP)
513 MOVL $0, err+28(FP)
514 RET
515
516 TEXT runtime·munmap(SB),NOSPLIT,$0
517 MOVL $SYS_munmap, AX
518 MOVL addr+0(FP), BX
519 MOVL n+4(FP), CX
520 INVOKE_SYSCALL
521 CMPL AX, $0xfffff001
522 JLS 2(PC)
523 INT $3
524 RET
525
526 TEXT runtime·madvise(SB),NOSPLIT,$0
527 MOVL $SYS_madvise, AX
528 MOVL addr+0(FP), BX
529 MOVL n+4(FP), CX
530 MOVL flags+8(FP), DX
531 INVOKE_SYSCALL
532 MOVL AX, ret+12(FP)
533 RET
534
535 // int32 futex(int32 *uaddr, int32 op, int32 val,
536 // struct timespec *timeout, int32 *uaddr2, int32 val2);
537 TEXT runtime·futex(SB),NOSPLIT,$0
538 MOVL $SYS_futex, AX
539 MOVL addr+0(FP), BX
540 MOVL op+4(FP), CX
541 MOVL val+8(FP), DX
542 MOVL ts+12(FP), SI
543 MOVL addr2+16(FP), DI
544 MOVL val3+20(FP), BP
545 INVOKE_SYSCALL
546 MOVL AX, ret+24(FP)
547 RET
548
549 // int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void));
550 TEXT runtime·clone(SB),NOSPLIT,$0
551 MOVL $SYS_clone, AX
552 MOVL flags+0(FP), BX
553 MOVL stk+4(FP), CX
554 MOVL $0, DX // parent tid ptr
555 MOVL $0, DI // child tid ptr
556
557 // Copy mp, gp, fn off parent stack for use by child.
558 SUBL $16, CX
559 MOVL mp+8(FP), SI
560 MOVL SI, 0(CX)
561 MOVL gp+12(FP), SI
562 MOVL SI, 4(CX)
563 MOVL fn+16(FP), SI
564 MOVL SI, 8(CX)
565 MOVL $1234, 12(CX)
566
567 // cannot use CALL 0x10(GS) here, because the stack changes during the
568 // system call (after CALL 0x10(GS), the child is still using the
569 // parent's stack when executing its RET instruction).
570 INT $0x80
571
572 // In parent, return.
573 CMPL AX, $0
574 JEQ 3(PC)
575 MOVL AX, ret+20(FP)
576 RET
577
578 // Paranoia: check that SP is as we expect.
579 NOP SP // tell vet SP changed - stop checking offsets
580 MOVL 12(SP), BP
581 CMPL BP, $1234
582 JEQ 2(PC)
583 INT $3
584
585 // Initialize AX to Linux tid
586 MOVL $SYS_gettid, AX
587 INVOKE_SYSCALL
588
589 MOVL 0(SP), BX // m
590 MOVL 4(SP), DX // g
591 MOVL 8(SP), SI // fn
592
593 CMPL BX, $0
594 JEQ nog
595 CMPL DX, $0
596 JEQ nog
597
598 MOVL AX, m_procid(BX) // save tid as m->procid
599
600 // set up ldt 7+id to point at m->tls.
601 LEAL m_tls(BX), BP
602 MOVL m_id(BX), DI
603 ADDL $7, DI // m0 is LDT#7. count up.
604 // setldt(tls#, &tls, sizeof tls)
605 PUSHAL // save registers
606 PUSHL $32 // sizeof tls
607 PUSHL BP // &tls
608 PUSHL DI // tls #
609 CALL runtime·setldt(SB)
610 POPL AX
611 POPL AX
612 POPL AX
613 POPAL
614
615 // Now segment is established. Initialize m, g.
616 get_tls(AX)
617 MOVL DX, g(AX)
618 MOVL BX, g_m(DX)
619
620 CALL runtime·stackcheck(SB) // smashes AX, CX
621 MOVL 0(DX), DX // paranoia; check they are not nil
622 MOVL 0(BX), BX
623
624 // more paranoia; check that stack splitting code works
625 PUSHAL
626 CALL runtime·emptyfunc(SB)
627 POPAL
628
629 nog:
630 CALL SI // fn()
631 CALL exit1<>(SB)
632 MOVL $0x1234, 0x1005
633
634 TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
635 MOVL $SYS_sigaltstack, AX
636 MOVL new+0(FP), BX
637 MOVL old+4(FP), CX
638 INVOKE_SYSCALL
639 CMPL AX, $0xfffff001
640 JLS 2(PC)
641 INT $3
642 RET
643
644 // <asm-i386/ldt.h>
645 // struct user_desc {
646 // unsigned int entry_number;
647 // unsigned long base_addr;
648 // unsigned int limit;
649 // unsigned int seg_32bit:1;
650 // unsigned int contents:2;
651 // unsigned int read_exec_only:1;
652 // unsigned int limit_in_pages:1;
653 // unsigned int seg_not_present:1;
654 // unsigned int useable:1;
655 // };
656 #define SEG_32BIT 0x01
657 // contents are the 2 bits 0x02 and 0x04.
658 #define CONTENTS_DATA 0x00
659 #define CONTENTS_STACK 0x02
660 #define CONTENTS_CODE 0x04
661 #define READ_EXEC_ONLY 0x08
662 #define LIMIT_IN_PAGES 0x10
663 #define SEG_NOT_PRESENT 0x20
664 #define USEABLE 0x40
665
666 // `-1` means the kernel will pick a TLS entry on the first setldt call,
667 // which happens during runtime init, and that we'll store back the saved
668 // entry and reuse that on subsequent calls when creating new threads.
669 DATA runtime·tls_entry_number+0(SB)/4, $-1
670 GLOBL runtime·tls_entry_number(SB), NOPTR, $4
671
672 // setldt(int entry, int address, int limit)
673 // We use set_thread_area, which mucks with the GDT, instead of modify_ldt,
674 // which would modify the LDT, but is disabled on some kernels.
675 // The name, setldt, is a misnomer, although we leave this name as it is for
676 // the compatibility with other platforms.
677 TEXT runtime·setldt(SB),NOSPLIT,$32
678 MOVL base+4(FP), DX
679
680 #ifdef GOOS_android
681 // Android stores the TLS offset in runtime·tls_g.
682 SUBL runtime·tls_g(SB), DX
683 MOVL DX, 0(DX)
684 #else
685 /*
686 * When linking against the system libraries,
687 * we use its pthread_create and let it set up %gs
688 * for us. When we do that, the private storage
689 * we get is not at 0(GS), but -4(GS).
690 * To insulate the rest of the tool chain from this
691 * ugliness, 8l rewrites 0(TLS) into -4(GS) for us.
692 * To accommodate that rewrite, we translate
693 * the address here and bump the limit to 0xffffffff (no limit)
694 * so that -4(GS) maps to 0(address).
695 * Also, the final 0(GS) (current 4(DX)) has to point
696 * to itself, to mimic ELF.
697 */
698 ADDL $0x4, DX // address
699 MOVL DX, 0(DX)
700 #endif
701
702 // get entry number
703 MOVL runtime·tls_entry_number(SB), CX
704
705 // set up user_desc
706 LEAL 16(SP), AX // struct user_desc
707 MOVL CX, 0(AX) // unsigned int entry_number
708 MOVL DX, 4(AX) // unsigned long base_addr
709 MOVL $0xfffff, 8(AX) // unsigned int limit
710 MOVL $(SEG_32BIT|LIMIT_IN_PAGES|USEABLE|CONTENTS_DATA), 12(AX) // flag bits
711
712 // call set_thread_area
713 MOVL AX, BX // user_desc
714 MOVL $SYS_set_thread_area, AX
715 // We can't call this via 0x10(GS) because this is called from setldt0 to set that up.
716 INT $0x80
717
718 // breakpoint on error
719 CMPL AX, $0xfffff001
720 JLS 2(PC)
721 INT $3
722
723 // read allocated entry number back out of user_desc
724 LEAL 16(SP), AX // get our user_desc back
725 MOVL 0(AX), AX
726
727 // store entry number if the kernel allocated it
728 CMPL CX, $-1
729 JNE 2(PC)
730 MOVL AX, runtime·tls_entry_number(SB)
731
732 // compute segment selector - (entry*8+3)
733 SHLL $3, AX
734 ADDL $3, AX
735 MOVW AX, GS
736
737 RET
738
739 TEXT runtime·osyield(SB),NOSPLIT,$0
740 MOVL $SYS_sched_yield, AX
741 INVOKE_SYSCALL
742 RET
743
744 TEXT runtime·sched_getaffinity(SB),NOSPLIT,$0
745 MOVL $SYS_sched_getaffinity, AX
746 MOVL pid+0(FP), BX
747 MOVL len+4(FP), CX
748 MOVL buf+8(FP), DX
749 INVOKE_SYSCALL
750 MOVL AX, ret+12(FP)
751 RET
752
753 // int access(const char *name, int mode)
754 TEXT runtime·access(SB),NOSPLIT,$0
755 MOVL $SYS_access, AX
756 MOVL name+0(FP), BX
757 MOVL mode+4(FP), CX
758 INVOKE_SYSCALL
759 MOVL AX, ret+8(FP)
760 RET
761
762 // int connect(int fd, const struct sockaddr *addr, socklen_t addrlen)
763 TEXT runtime·connect(SB),NOSPLIT,$0-16
764 // connect is implemented as socketcall(NR_socket, 3, *(rest of args))
765 // stack already should have fd, addr, addrlen.
766 MOVL $SYS_socketcall, AX
767 MOVL $3, BX // connect
768 LEAL fd+0(FP), CX
769 INVOKE_SYSCALL
770 MOVL AX, ret+12(FP)
771 RET
772
773 // int socket(int domain, int type, int protocol)
774 TEXT runtime·socket(SB),NOSPLIT,$0-16
775 // socket is implemented as socketcall(NR_socket, 1, *(rest of args))
776 // stack already should have domain, type, protocol.
777 MOVL $SYS_socketcall, AX
778 MOVL $1, BX // socket
779 LEAL domain+0(FP), CX
780 INVOKE_SYSCALL
781 MOVL AX, ret+12(FP)
782 RET
783
784 // func sbrk0() uintptr
785 TEXT runtime·sbrk0(SB),NOSPLIT,$0-4
786 // Implemented as brk(NULL).
787 MOVL $SYS_brk, AX
788 MOVL $0, BX // NULL
789 INVOKE_SYSCALL
790 MOVL AX, ret+0(FP)
791 RET
792
View as plain text