github.com/filosottile/go@v0.0.0-20170906193555-dbed9972d994/src/runtime/sys_linux_386.s (about) 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 runtime·exit(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 runtime·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 TEXT runtime·open(SB),NOSPLIT,$0 78 MOVL $SYS_open, AX 79 MOVL name+0(FP), BX 80 MOVL mode+4(FP), CX 81 MOVL perm+8(FP), DX 82 INVOKE_SYSCALL 83 CMPL AX, $0xfffff001 84 JLS 2(PC) 85 MOVL $-1, AX 86 MOVL AX, ret+12(FP) 87 RET 88 89 TEXT runtime·closefd(SB),NOSPLIT,$0 90 MOVL $SYS_close, AX 91 MOVL fd+0(FP), BX 92 INVOKE_SYSCALL 93 CMPL AX, $0xfffff001 94 JLS 2(PC) 95 MOVL $-1, AX 96 MOVL AX, ret+4(FP) 97 RET 98 99 TEXT runtime·write(SB),NOSPLIT,$0 100 MOVL $SYS_write, AX 101 MOVL fd+0(FP), BX 102 MOVL p+4(FP), CX 103 MOVL n+8(FP), DX 104 INVOKE_SYSCALL 105 CMPL AX, $0xfffff001 106 JLS 2(PC) 107 MOVL $-1, AX 108 MOVL AX, ret+12(FP) 109 RET 110 111 TEXT runtime·read(SB),NOSPLIT,$0 112 MOVL $SYS_read, 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 runtime·getrlimit(SB),NOSPLIT,$0 124 MOVL $SYS_ugetrlimit, AX 125 MOVL kind+0(FP), BX 126 MOVL limit+4(FP), CX 127 INVOKE_SYSCALL 128 MOVL AX, ret+8(FP) 129 RET 130 131 TEXT runtime·usleep(SB),NOSPLIT,$8 132 MOVL $0, DX 133 MOVL usec+0(FP), AX 134 MOVL $1000000, CX 135 DIVL CX 136 MOVL AX, 0(SP) 137 MOVL $1000, AX // usec to nsec 138 MULL DX 139 MOVL AX, 4(SP) 140 141 // pselect6(0, 0, 0, 0, &ts, 0) 142 MOVL $SYS_pselect6, AX 143 MOVL $0, BX 144 MOVL $0, CX 145 MOVL $0, DX 146 MOVL $0, SI 147 LEAL 0(SP), DI 148 MOVL $0, BP 149 INVOKE_SYSCALL 150 RET 151 152 TEXT runtime·gettid(SB),NOSPLIT,$0-4 153 MOVL $SYS_gettid, AX 154 INVOKE_SYSCALL 155 MOVL AX, ret+0(FP) 156 RET 157 158 TEXT runtime·raise(SB),NOSPLIT,$12 159 MOVL $SYS_gettid, AX 160 INVOKE_SYSCALL 161 MOVL AX, BX // arg 1 tid 162 MOVL sig+0(FP), CX // arg 2 signal 163 MOVL $SYS_tkill, AX 164 INVOKE_SYSCALL 165 RET 166 167 TEXT runtime·raiseproc(SB),NOSPLIT,$12 168 MOVL $SYS_getpid, AX 169 INVOKE_SYSCALL 170 MOVL AX, BX // arg 1 pid 171 MOVL sig+0(FP), CX // arg 2 signal 172 MOVL $SYS_kill, AX 173 INVOKE_SYSCALL 174 RET 175 176 TEXT runtime·setitimer(SB),NOSPLIT,$0-12 177 MOVL $SYS_setittimer, AX 178 MOVL mode+0(FP), BX 179 MOVL new+4(FP), CX 180 MOVL old+8(FP), DX 181 INVOKE_SYSCALL 182 RET 183 184 TEXT runtime·mincore(SB),NOSPLIT,$0-16 185 MOVL $SYS_mincore, AX 186 MOVL addr+0(FP), BX 187 MOVL n+4(FP), CX 188 MOVL dst+8(FP), DX 189 INVOKE_SYSCALL 190 MOVL AX, ret+12(FP) 191 RET 192 193 // func walltime() (sec int64, nsec int32) 194 TEXT runtime·walltime(SB), NOSPLIT, $32 195 MOVL $SYS_clock_gettime, AX 196 MOVL $0, BX // CLOCK_REALTIME 197 LEAL 8(SP), CX 198 MOVL $0, DX 199 INVOKE_SYSCALL 200 MOVL 8(SP), AX // sec 201 MOVL 12(SP), BX // nsec 202 203 // sec is in AX, nsec in BX 204 MOVL AX, sec_lo+0(FP) 205 MOVL $0, sec_hi+4(FP) 206 MOVL BX, nsec+8(FP) 207 RET 208 209 // int64 nanotime(void) so really 210 // void nanotime(int64 *nsec) 211 TEXT runtime·nanotime(SB), NOSPLIT, $32 212 MOVL $SYS_clock_gettime, AX 213 MOVL $1, BX // CLOCK_MONOTONIC 214 LEAL 8(SP), CX 215 MOVL $0, DX 216 INVOKE_SYSCALL 217 MOVL 8(SP), AX // sec 218 MOVL 12(SP), BX // nsec 219 220 // sec is in AX, nsec in BX 221 // convert to DX:AX nsec 222 MOVL $1000000000, CX 223 MULL CX 224 ADDL BX, AX 225 ADCL $0, DX 226 227 MOVL AX, ret_lo+0(FP) 228 MOVL DX, ret_hi+4(FP) 229 RET 230 231 TEXT runtime·rtsigprocmask(SB),NOSPLIT,$0 232 MOVL $SYS_rt_sigprocmask, AX 233 MOVL how+0(FP), BX 234 MOVL new+4(FP), CX 235 MOVL old+8(FP), DX 236 MOVL size+12(FP), SI 237 INVOKE_SYSCALL 238 CMPL AX, $0xfffff001 239 JLS 2(PC) 240 INT $3 241 RET 242 243 TEXT runtime·rt_sigaction(SB),NOSPLIT,$0 244 MOVL $SYS_rt_sigaction, AX 245 MOVL sig+0(FP), BX 246 MOVL new+4(FP), CX 247 MOVL old+8(FP), DX 248 MOVL size+12(FP), SI 249 INVOKE_SYSCALL 250 MOVL AX, ret+16(FP) 251 RET 252 253 TEXT runtime·sigfwd(SB),NOSPLIT,$12-16 254 MOVL fn+0(FP), AX 255 MOVL sig+4(FP), BX 256 MOVL info+8(FP), CX 257 MOVL ctx+12(FP), DX 258 MOVL SP, SI 259 SUBL $32, SP 260 ANDL $-15, SP // align stack: handler might be a C function 261 MOVL BX, 0(SP) 262 MOVL CX, 4(SP) 263 MOVL DX, 8(SP) 264 MOVL SI, 12(SP) // save SI: handler might be a Go function 265 CALL AX 266 MOVL 12(SP), AX 267 MOVL AX, SP 268 RET 269 270 TEXT runtime·sigtramp(SB),NOSPLIT,$28 271 // Save callee-saved C registers, since the caller may be a C signal handler. 272 MOVL BX, bx-4(SP) 273 MOVL BP, bp-8(SP) 274 MOVL SI, si-12(SP) 275 MOVL DI, di-16(SP) 276 // We don't save mxcsr or the x87 control word because sigtrampgo doesn't 277 // modify them. 278 279 MOVL sig+0(FP), BX 280 MOVL BX, 0(SP) 281 MOVL info+4(FP), BX 282 MOVL BX, 4(SP) 283 MOVL ctx+8(FP), BX 284 MOVL BX, 8(SP) 285 CALL runtime·sigtrampgo(SB) 286 287 MOVL di-16(SP), DI 288 MOVL si-12(SP), SI 289 MOVL bp-8(SP), BP 290 MOVL bx-4(SP), BX 291 RET 292 293 TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0 294 JMP runtime·sigtramp(SB) 295 296 TEXT runtime·sigreturn(SB),NOSPLIT,$0 297 MOVL $SYS_rt_sigreturn, AX 298 // Sigreturn expects same SP as signal handler, 299 // so cannot CALL 0x10(GS) here. 300 INT $0x80 301 INT $3 // not reached 302 RET 303 304 TEXT runtime·mmap(SB),NOSPLIT,$0 305 MOVL $SYS_mmap2, AX 306 MOVL addr+0(FP), BX 307 MOVL n+4(FP), CX 308 MOVL prot+8(FP), DX 309 MOVL flags+12(FP), SI 310 MOVL fd+16(FP), DI 311 MOVL off+20(FP), BP 312 SHRL $12, BP 313 INVOKE_SYSCALL 314 CMPL AX, $0xfffff001 315 JLS 3(PC) 316 NOTL AX 317 INCL AX 318 MOVL AX, ret+24(FP) 319 RET 320 321 TEXT runtime·munmap(SB),NOSPLIT,$0 322 MOVL $SYS_munmap, AX 323 MOVL addr+0(FP), BX 324 MOVL n+4(FP), CX 325 INVOKE_SYSCALL 326 CMPL AX, $0xfffff001 327 JLS 2(PC) 328 INT $3 329 RET 330 331 TEXT runtime·madvise(SB),NOSPLIT,$0 332 MOVL $SYS_madvise, AX 333 MOVL addr+0(FP), BX 334 MOVL n+4(FP), CX 335 MOVL flags+8(FP), DX 336 INVOKE_SYSCALL 337 // ignore failure - maybe pages are locked 338 RET 339 340 // int32 futex(int32 *uaddr, int32 op, int32 val, 341 // struct timespec *timeout, int32 *uaddr2, int32 val2); 342 TEXT runtime·futex(SB),NOSPLIT,$0 343 MOVL $SYS_futex, AX 344 MOVL addr+0(FP), BX 345 MOVL op+4(FP), CX 346 MOVL val+8(FP), DX 347 MOVL ts+12(FP), SI 348 MOVL addr2+16(FP), DI 349 MOVL val3+20(FP), BP 350 INVOKE_SYSCALL 351 MOVL AX, ret+24(FP) 352 RET 353 354 // int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void)); 355 TEXT runtime·clone(SB),NOSPLIT,$0 356 MOVL $SYS_clone, AX 357 MOVL flags+0(FP), BX 358 MOVL stk+4(FP), CX 359 MOVL $0, DX // parent tid ptr 360 MOVL $0, DI // child tid ptr 361 362 // Copy mp, gp, fn off parent stack for use by child. 363 SUBL $16, CX 364 MOVL mp+8(FP), SI 365 MOVL SI, 0(CX) 366 MOVL gp+12(FP), SI 367 MOVL SI, 4(CX) 368 MOVL fn+16(FP), SI 369 MOVL SI, 8(CX) 370 MOVL $1234, 12(CX) 371 372 // cannot use CALL 0x10(GS) here, because the stack changes during the 373 // system call (after CALL 0x10(GS), the child is still using the 374 // parent's stack when executing its RET instruction). 375 INT $0x80 376 377 // In parent, return. 378 CMPL AX, $0 379 JEQ 3(PC) 380 MOVL AX, ret+20(FP) 381 RET 382 383 // Paranoia: check that SP is as we expect. 384 MOVL 12(SP), BP 385 CMPL BP, $1234 386 JEQ 2(PC) 387 INT $3 388 389 // Initialize AX to Linux tid 390 MOVL $SYS_gettid, AX 391 INVOKE_SYSCALL 392 393 MOVL 0(SP), BX // m 394 MOVL 4(SP), DX // g 395 MOVL 8(SP), SI // fn 396 397 CMPL BX, $0 398 JEQ nog 399 CMPL DX, $0 400 JEQ nog 401 402 MOVL AX, m_procid(BX) // save tid as m->procid 403 404 // set up ldt 7+id to point at m->tls. 405 LEAL m_tls(BX), BP 406 MOVL m_id(BX), DI 407 ADDL $7, DI // m0 is LDT#7. count up. 408 // setldt(tls#, &tls, sizeof tls) 409 PUSHAL // save registers 410 PUSHL $32 // sizeof tls 411 PUSHL BP // &tls 412 PUSHL DI // tls # 413 CALL runtime·setldt(SB) 414 POPL AX 415 POPL AX 416 POPL AX 417 POPAL 418 419 // Now segment is established. Initialize m, g. 420 get_tls(AX) 421 MOVL DX, g(AX) 422 MOVL BX, g_m(DX) 423 424 CALL runtime·stackcheck(SB) // smashes AX, CX 425 MOVL 0(DX), DX // paranoia; check they are not nil 426 MOVL 0(BX), BX 427 428 // more paranoia; check that stack splitting code works 429 PUSHAL 430 CALL runtime·emptyfunc(SB) 431 POPAL 432 433 nog: 434 CALL SI // fn() 435 CALL runtime·exit1(SB) 436 MOVL $0x1234, 0x1005 437 438 TEXT runtime·sigaltstack(SB),NOSPLIT,$-8 439 MOVL $SYS_sigaltstack, AX 440 MOVL new+0(FP), BX 441 MOVL old+4(FP), CX 442 INVOKE_SYSCALL 443 CMPL AX, $0xfffff001 444 JLS 2(PC) 445 INT $3 446 RET 447 448 // <asm-i386/ldt.h> 449 // struct user_desc { 450 // unsigned int entry_number; 451 // unsigned long base_addr; 452 // unsigned int limit; 453 // unsigned int seg_32bit:1; 454 // unsigned int contents:2; 455 // unsigned int read_exec_only:1; 456 // unsigned int limit_in_pages:1; 457 // unsigned int seg_not_present:1; 458 // unsigned int useable:1; 459 // }; 460 #define SEG_32BIT 0x01 461 // contents are the 2 bits 0x02 and 0x04. 462 #define CONTENTS_DATA 0x00 463 #define CONTENTS_STACK 0x02 464 #define CONTENTS_CODE 0x04 465 #define READ_EXEC_ONLY 0x08 466 #define LIMIT_IN_PAGES 0x10 467 #define SEG_NOT_PRESENT 0x20 468 #define USEABLE 0x40 469 470 // `-1` means the kernel will pick a TLS entry on the first setldt call, 471 // which happens during runtime init, and that we'll store back the saved 472 // entry and reuse that on subsequent calls when creating new threads. 473 DATA runtime·tls_entry_number+0(SB)/4, $-1 474 GLOBL runtime·tls_entry_number(SB), NOPTR, $4 475 476 // setldt(int entry, int address, int limit) 477 // We use set_thread_area, which mucks with the GDT, instead of modify_ldt, 478 // which would modify the LDT, but is disabled on some kernels. 479 // The name, setldt, is a misnomer, although we leave this name as it is for 480 // the compatibility with other platforms. 481 TEXT runtime·setldt(SB),NOSPLIT,$32 482 MOVL address+4(FP), DX // base address 483 484 #ifdef GOOS_android 485 /* 486 * Same as in sys_darwin_386.s:/ugliness, different constant. 487 * address currently holds m->tls, which must be %gs:0xf8. 488 * See cgo/gcc_android_386.c for the derivation of the constant. 489 */ 490 SUBL $0xf8, DX 491 MOVL DX, 0(DX) 492 #else 493 /* 494 * When linking against the system libraries, 495 * we use its pthread_create and let it set up %gs 496 * for us. When we do that, the private storage 497 * we get is not at 0(GS), but -4(GS). 498 * To insulate the rest of the tool chain from this 499 * ugliness, 8l rewrites 0(TLS) into -4(GS) for us. 500 * To accommodate that rewrite, we translate 501 * the address here and bump the limit to 0xffffffff (no limit) 502 * so that -4(GS) maps to 0(address). 503 * Also, the final 0(GS) (current 4(DX)) has to point 504 * to itself, to mimic ELF. 505 */ 506 ADDL $0x4, DX // address 507 MOVL DX, 0(DX) 508 #endif 509 510 // get entry number 511 MOVL runtime·tls_entry_number(SB), CX 512 513 // set up user_desc 514 LEAL 16(SP), AX // struct user_desc 515 MOVL CX, 0(AX) // unsigned int entry_number 516 MOVL DX, 4(AX) // unsigned long base_addr 517 MOVL $0xfffff, 8(AX) // unsigned int limit 518 MOVL $(SEG_32BIT|LIMIT_IN_PAGES|USEABLE|CONTENTS_DATA), 12(AX) // flag bits 519 520 // call set_thread_area 521 MOVL AX, BX // user_desc 522 MOVL $SYS_set_thread_area, AX 523 // We can't call this via 0x10(GS) because this is called from setldt0 to set that up. 524 INT $0x80 525 526 // breakpoint on error 527 CMPL AX, $0xfffff001 528 JLS 2(PC) 529 INT $3 530 531 // read allocated entry number back out of user_desc 532 LEAL 16(SP), AX // get our user_desc back 533 MOVL 0(AX), AX 534 535 // store entry number if the kernel allocated it 536 CMPL CX, $-1 537 JNE 2(PC) 538 MOVL AX, runtime·tls_entry_number(SB) 539 540 // compute segment selector - (entry*8+3) 541 SHLL $3, AX 542 ADDL $3, AX 543 MOVW AX, GS 544 545 RET 546 547 TEXT runtime·osyield(SB),NOSPLIT,$0 548 MOVL $SYS_sched_yield, AX 549 INVOKE_SYSCALL 550 RET 551 552 TEXT runtime·sched_getaffinity(SB),NOSPLIT,$0 553 MOVL $SYS_sched_getaffinity, AX 554 MOVL pid+0(FP), BX 555 MOVL len+4(FP), CX 556 MOVL buf+8(FP), DX 557 INVOKE_SYSCALL 558 MOVL AX, ret+12(FP) 559 RET 560 561 // int32 runtime·epollcreate(int32 size); 562 TEXT runtime·epollcreate(SB),NOSPLIT,$0 563 MOVL $SYS_epoll_create, AX 564 MOVL size+0(FP), BX 565 INVOKE_SYSCALL 566 MOVL AX, ret+4(FP) 567 RET 568 569 // int32 runtime·epollcreate1(int32 flags); 570 TEXT runtime·epollcreate1(SB),NOSPLIT,$0 571 MOVL $SYS_epoll_create1, AX 572 MOVL flags+0(FP), BX 573 INVOKE_SYSCALL 574 MOVL AX, ret+4(FP) 575 RET 576 577 // func epollctl(epfd, op, fd int32, ev *epollEvent) int 578 TEXT runtime·epollctl(SB),NOSPLIT,$0 579 MOVL $SYS_epoll_ctl, AX 580 MOVL epfd+0(FP), BX 581 MOVL op+4(FP), CX 582 MOVL fd+8(FP), DX 583 MOVL ev+12(FP), SI 584 INVOKE_SYSCALL 585 MOVL AX, ret+16(FP) 586 RET 587 588 // int32 runtime·epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout); 589 TEXT runtime·epollwait(SB),NOSPLIT,$0 590 MOVL $SYS_epoll_wait, AX 591 MOVL epfd+0(FP), BX 592 MOVL ev+4(FP), CX 593 MOVL nev+8(FP), DX 594 MOVL timeout+12(FP), SI 595 INVOKE_SYSCALL 596 MOVL AX, ret+16(FP) 597 RET 598 599 // void runtime·closeonexec(int32 fd); 600 TEXT runtime·closeonexec(SB),NOSPLIT,$0 601 MOVL $SYS_fcntl, AX 602 MOVL fd+0(FP), BX // fd 603 MOVL $2, CX // F_SETFD 604 MOVL $1, DX // FD_CLOEXEC 605 INVOKE_SYSCALL 606 RET 607 608 // int access(const char *name, int mode) 609 TEXT runtime·access(SB),NOSPLIT,$0 610 MOVL $SYS_access, AX 611 MOVL name+0(FP), BX 612 MOVL mode+4(FP), CX 613 INVOKE_SYSCALL 614 MOVL AX, ret+8(FP) 615 RET 616 617 // int connect(int fd, const struct sockaddr *addr, socklen_t addrlen) 618 TEXT runtime·connect(SB),NOSPLIT,$0-16 619 // connect is implemented as socketcall(NR_socket, 3, *(rest of args)) 620 // stack already should have fd, addr, addrlen. 621 MOVL $SYS_socketcall, AX 622 MOVL $3, BX // connect 623 LEAL fd+0(FP), CX 624 INVOKE_SYSCALL 625 MOVL AX, ret+12(FP) 626 RET 627 628 // int socket(int domain, int type, int protocol) 629 TEXT runtime·socket(SB),NOSPLIT,$0-16 630 // socket is implemented as socketcall(NR_socket, 1, *(rest of args)) 631 // stack already should have domain, type, protocol. 632 MOVL $SYS_socketcall, AX 633 MOVL $1, BX // socket 634 LEAL domain+0(FP), CX 635 INVOKE_SYSCALL 636 MOVL AX, ret+12(FP) 637 RET 638 639 // func sbrk0() uintptr 640 TEXT runtime·sbrk0(SB),NOSPLIT,$0-4 641 // Implemented as brk(NULL). 642 MOVL $SYS_brk, AX 643 MOVL $0, BX // NULL 644 INVOKE_SYSCALL 645 MOVL AX, ret+0(FP) 646 RET