| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| // |
| // System calls and other sys.stuff for AMD64, OpenBSD. |
| // System calls are implemented in libc/libpthread, this file |
| // contains trampolines that convert from Go to C calling convention. |
| // Some direct system call implementations currently remain. |
| // |
| |
| #include "go_asm.h" |
| #include "go_tls.h" |
| #include "textflag.h" |
| #include "cgo/abi_amd64.h" |
| |
| #define CLOCK_MONOTONIC $3 |
| |
| TEXT runtime·settls(SB),NOSPLIT,$0 |
| // Nothing to do, pthread already set thread-local storage up. |
| RET |
| |
| // mstart_stub is the first function executed on a new thread started by pthread_create. |
| // It just does some low-level setup and then calls mstart. |
| // Note: called with the C calling convention. |
| TEXT runtime·mstart_stub(SB),NOSPLIT,$0 |
| // DI points to the m. |
| // We are already on m's g0 stack. |
| |
| // Transition from C ABI to Go ABI. |
| PUSH_REGS_HOST_TO_ABI0() |
| |
| // Load g and save to TLS entry. |
| // See cmd/link/internal/ld/sym.go:computeTLSOffset. |
| MOVQ m_g0(DI), DX // g |
| MOVQ DX, -8(FS) |
| |
| CALL runtime·mstart(SB) |
| |
| POP_REGS_HOST_TO_ABI0() |
| |
| // Go is all done with this OS thread. |
| // Tell pthread everything is ok (we never join with this thread, so |
| // the value here doesn't really matter). |
| XORL AX, AX |
| RET |
| |
| TEXT runtime·sigfwd(SB),NOSPLIT,$0-32 |
| MOVQ fn+0(FP), AX |
| MOVL sig+8(FP), DI |
| MOVQ info+16(FP), SI |
| MOVQ ctx+24(FP), DX |
| PUSHQ BP |
| MOVQ SP, BP |
| ANDQ $~15, SP // alignment for x86_64 ABI |
| CALL AX |
| MOVQ BP, SP |
| POPQ BP |
| RET |
| |
| // Called using C ABI. |
| TEXT runtime·sigtramp(SB),NOSPLIT|TOPFRAME,$0 |
| // Transition from C ABI to Go ABI. |
| PUSH_REGS_HOST_TO_ABI0() |
| |
| // Set up ABIInternal environment: g in R14, cleared X15. |
| get_tls(R12) |
| MOVQ g(R12), R14 |
| PXOR X15, X15 |
| |
| // Reserve space for spill slots. |
| NOP SP // disable vet stack checking |
| ADJSP $24 |
| |
| // Call into the Go signal handler |
| MOVQ DI, AX // sig |
| MOVQ SI, BX // info |
| MOVQ DX, CX // ctx |
| CALL ·sigtrampgo<ABIInternal>(SB) |
| |
| ADJSP $-24 |
| |
| POP_REGS_HOST_TO_ABI0() |
| RET |
| |
| // |
| // These trampolines help convert from Go calling convention to C calling convention. |
| // They should be called with asmcgocall. |
| // A pointer to the arguments is passed in DI. |
| // A single int32 result is returned in AX. |
| // (For more results, make an args/results structure.) |
| TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVQ 0(DI), DI // arg 1 - attr |
| CALL libc_pthread_attr_init(SB) |
| POPQ BP |
| RET |
| |
| TEXT runtime·pthread_attr_destroy_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVQ 0(DI), DI // arg 1 - attr |
| CALL libc_pthread_attr_destroy(SB) |
| POPQ BP |
| RET |
| |
| TEXT runtime·pthread_attr_getstacksize_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVQ 8(DI), SI // arg 2 - stacksize |
| MOVQ 0(DI), DI // arg 1 - attr |
| CALL libc_pthread_attr_getstacksize(SB) |
| POPQ BP |
| RET |
| |
| TEXT runtime·pthread_attr_setdetachstate_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVQ 8(DI), SI // arg 2 - detachstate |
| MOVQ 0(DI), DI // arg 1 - attr |
| CALL libc_pthread_attr_setdetachstate(SB) |
| POPQ BP |
| RET |
| |
| TEXT runtime·pthread_create_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| SUBQ $16, SP |
| MOVQ 0(DI), SI // arg 2 - attr |
| MOVQ 8(DI), DX // arg 3 - start |
| MOVQ 16(DI), CX // arg 4 - arg |
| MOVQ SP, DI // arg 1 - &thread (discarded) |
| CALL libc_pthread_create(SB) |
| MOVQ BP, SP |
| POPQ BP |
| RET |
| |
| TEXT runtime·thrkill_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVL 8(DI), SI // arg 2 - signal |
| MOVQ $0, DX // arg 3 - tcb |
| MOVL 0(DI), DI // arg 1 - tid |
| CALL libc_thrkill(SB) |
| POPQ BP |
| RET |
| |
| TEXT runtime·thrsleep_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVL 8(DI), SI // arg 2 - clock_id |
| MOVQ 16(DI), DX // arg 3 - abstime |
| MOVQ 24(DI), CX // arg 4 - lock |
| MOVQ 32(DI), R8 // arg 5 - abort |
| MOVQ 0(DI), DI // arg 1 - id |
| CALL libc_thrsleep(SB) |
| POPQ BP |
| RET |
| |
| TEXT runtime·thrwakeup_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVL 8(DI), SI // arg 2 - count |
| MOVQ 0(DI), DI // arg 1 - id |
| CALL libc_thrwakeup(SB) |
| POPQ BP |
| RET |
| |
| TEXT runtime·exit_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVL 0(DI), DI // arg 1 exit status |
| CALL libc_exit(SB) |
| MOVL $0xf1, 0xf1 // crash |
| POPQ BP |
| RET |
| |
| TEXT runtime·getthrid_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVQ DI, BX // BX is caller-save |
| CALL libc_getthrid(SB) |
| MOVL AX, 0(BX) // return value |
| POPQ BP |
| RET |
| |
| TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVL 0(DI), BX // signal |
| CALL libc_getpid(SB) |
| MOVL AX, DI // arg 1 pid |
| MOVL BX, SI // arg 2 signal |
| CALL libc_kill(SB) |
| POPQ BP |
| RET |
| |
| TEXT runtime·sched_yield_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| CALL libc_sched_yield(SB) |
| POPQ BP |
| RET |
| |
| TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP // make a frame; keep stack aligned |
| MOVQ SP, BP |
| MOVQ DI, BX |
| MOVQ 0(BX), DI // arg 1 addr |
| MOVQ 8(BX), SI // arg 2 len |
| MOVL 16(BX), DX // arg 3 prot |
| MOVL 20(BX), CX // arg 4 flags |
| MOVL 24(BX), R8 // arg 5 fid |
| MOVL 28(BX), R9 // arg 6 offset |
| CALL libc_mmap(SB) |
| XORL DX, DX |
| CMPQ AX, $-1 |
| JNE ok |
| CALL libc_errno(SB) |
| MOVLQSX (AX), DX // errno |
| XORQ AX, AX |
| ok: |
| MOVQ AX, 32(BX) |
| MOVQ DX, 40(BX) |
| POPQ BP |
| RET |
| |
| TEXT runtime·munmap_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVQ 8(DI), SI // arg 2 len |
| MOVQ 0(DI), DI // arg 1 addr |
| CALL libc_munmap(SB) |
| TESTQ AX, AX |
| JEQ 2(PC) |
| MOVL $0xf1, 0xf1 // crash |
| POPQ BP |
| RET |
| |
| TEXT runtime·madvise_trampoline(SB), NOSPLIT, $0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVQ 8(DI), SI // arg 2 len |
| MOVL 16(DI), DX // arg 3 advice |
| MOVQ 0(DI), DI // arg 1 addr |
| CALL libc_madvise(SB) |
| // ignore failure - maybe pages are locked |
| POPQ BP |
| RET |
| |
| TEXT runtime·open_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVL 8(DI), SI // arg 2 - flags |
| MOVL 12(DI), DX // arg 3 - mode |
| MOVQ 0(DI), DI // arg 1 - path |
| XORL AX, AX // vararg: say "no float args" |
| CALL libc_open(SB) |
| POPQ BP |
| RET |
| |
| TEXT runtime·close_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVL 0(DI), DI // arg 1 - fd |
| CALL libc_close(SB) |
| POPQ BP |
| RET |
| |
| TEXT runtime·read_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVQ 8(DI), SI // arg 2 - buf |
| MOVL 16(DI), DX // arg 3 - count |
| MOVL 0(DI), DI // arg 1 - fd |
| CALL libc_read(SB) |
| TESTL AX, AX |
| JGE noerr |
| CALL libc_errno(SB) |
| MOVL (AX), AX // errno |
| NEGL AX // caller expects negative errno value |
| noerr: |
| POPQ BP |
| RET |
| |
| TEXT runtime·write_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVQ 8(DI), SI // arg 2 buf |
| MOVL 16(DI), DX // arg 3 count |
| MOVL 0(DI), DI // arg 1 fd |
| CALL libc_write(SB) |
| TESTL AX, AX |
| JGE noerr |
| CALL libc_errno(SB) |
| MOVL (AX), AX // errno |
| NEGL AX // caller expects negative errno value |
| noerr: |
| POPQ BP |
| RET |
| |
| TEXT runtime·pipe2_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVL 8(DI), SI // arg 2 flags |
| MOVQ 0(DI), DI // arg 1 filedes |
| CALL libc_pipe2(SB) |
| TESTL AX, AX |
| JEQ 3(PC) |
| CALL libc_errno(SB) |
| MOVL (AX), AX // errno |
| NEGL AX // caller expects negative errno value |
| POPQ BP |
| RET |
| |
| TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVQ 8(DI), SI // arg 2 new |
| MOVQ 16(DI), DX // arg 3 old |
| MOVL 0(DI), DI // arg 1 which |
| CALL libc_setitimer(SB) |
| POPQ BP |
| RET |
| |
| TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVL 0(DI), DI // arg 1 usec |
| CALL libc_usleep(SB) |
| POPQ BP |
| RET |
| |
| TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVL 8(DI), SI // arg 2 miblen |
| MOVQ 16(DI), DX // arg 3 out |
| MOVQ 24(DI), CX // arg 4 size |
| MOVQ 32(DI), R8 // arg 5 dst |
| MOVQ 40(DI), R9 // arg 6 ndst |
| MOVQ 0(DI), DI // arg 1 mib |
| CALL libc_sysctl(SB) |
| POPQ BP |
| RET |
| |
| TEXT runtime·kqueue_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| CALL libc_kqueue(SB) |
| POPQ BP |
| RET |
| |
| TEXT runtime·kevent_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVQ 8(DI), SI // arg 2 keventt |
| MOVL 16(DI), DX // arg 3 nch |
| MOVQ 24(DI), CX // arg 4 ev |
| MOVL 32(DI), R8 // arg 5 nev |
| MOVQ 40(DI), R9 // arg 6 ts |
| MOVL 0(DI), DI // arg 1 kq |
| CALL libc_kevent(SB) |
| CMPL AX, $-1 |
| JNE ok |
| CALL libc_errno(SB) |
| MOVL (AX), AX // errno |
| NEGL AX // caller expects negative errno value |
| ok: |
| POPQ BP |
| RET |
| |
| TEXT runtime·clock_gettime_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP // make a frame; keep stack aligned |
| MOVQ SP, BP |
| MOVQ 8(DI), SI // arg 2 tp |
| MOVL 0(DI), DI // arg 1 clock_id |
| CALL libc_clock_gettime(SB) |
| TESTL AX, AX |
| JEQ noerr |
| CALL libc_errno(SB) |
| MOVL (AX), AX // errno |
| NEGL AX // caller expects negative errno value |
| noerr: |
| POPQ BP |
| RET |
| |
| TEXT runtime·fcntl_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVL 4(DI), SI // arg 2 cmd |
| MOVL 8(DI), DX // arg 3 arg |
| MOVL 0(DI), DI // arg 1 fd |
| XORL AX, AX // vararg: say "no float args" |
| CALL libc_fcntl(SB) |
| POPQ BP |
| RET |
| |
| TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVQ 8(DI), SI // arg 2 new |
| MOVQ 16(DI), DX // arg 3 old |
| MOVL 0(DI), DI // arg 1 sig |
| CALL libc_sigaction(SB) |
| TESTL AX, AX |
| JEQ 2(PC) |
| MOVL $0xf1, 0xf1 // crash |
| POPQ BP |
| RET |
| |
| TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVQ 8(DI), SI // arg 2 new |
| MOVQ 16(DI), DX // arg 3 old |
| MOVL 0(DI), DI // arg 1 how |
| CALL libc_pthread_sigmask(SB) |
| TESTL AX, AX |
| JEQ 2(PC) |
| MOVL $0xf1, 0xf1 // crash |
| POPQ BP |
| RET |
| |
| TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| MOVQ 8(DI), SI // arg 2 old |
| MOVQ 0(DI), DI // arg 1 new |
| CALL libc_sigaltstack(SB) |
| TESTQ AX, AX |
| JEQ 2(PC) |
| MOVL $0xf1, 0xf1 // crash |
| POPQ BP |
| RET |
| |
| // syscall calls a function in libc on behalf of the syscall package. |
| // syscall takes a pointer to a struct like: |
| // struct { |
| // fn uintptr |
| // a1 uintptr |
| // a2 uintptr |
| // a3 uintptr |
| // r1 uintptr |
| // r2 uintptr |
| // err uintptr |
| // } |
| // syscall must be called on the g0 stack with the |
| // C calling convention (use libcCall). |
| // |
| // syscall expects a 32-bit result and tests for 32-bit -1 |
| // to decide there was an error. |
| TEXT runtime·syscall(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| SUBQ $16, SP |
| MOVQ (0*8)(DI), CX // fn |
| MOVQ (2*8)(DI), SI // a2 |
| MOVQ (3*8)(DI), DX // a3 |
| MOVQ DI, (SP) |
| MOVQ (1*8)(DI), DI // a1 |
| XORL AX, AX // vararg: say "no float args" |
| |
| CALL CX |
| |
| MOVQ (SP), DI |
| MOVQ AX, (4*8)(DI) // r1 |
| MOVQ DX, (5*8)(DI) // r2 |
| |
| // Standard libc functions return -1 on error |
| // and set errno. |
| CMPL AX, $-1 // Note: high 32 bits are junk |
| JNE ok |
| |
| // Get error code from libc. |
| CALL libc_errno(SB) |
| MOVLQSX (AX), AX |
| MOVQ (SP), DI |
| MOVQ AX, (6*8)(DI) // err |
| |
| ok: |
| XORL AX, AX // no error (it's ignored anyway) |
| MOVQ BP, SP |
| POPQ BP |
| RET |
| |
| // syscallX calls a function in libc on behalf of the syscall package. |
| // syscallX takes a pointer to a struct like: |
| // struct { |
| // fn uintptr |
| // a1 uintptr |
| // a2 uintptr |
| // a3 uintptr |
| // r1 uintptr |
| // r2 uintptr |
| // err uintptr |
| // } |
| // syscallX must be called on the g0 stack with the |
| // C calling convention (use libcCall). |
| // |
| // syscallX is like syscall but expects a 64-bit result |
| // and tests for 64-bit -1 to decide there was an error. |
| TEXT runtime·syscallX(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| SUBQ $16, SP |
| MOVQ (0*8)(DI), CX // fn |
| MOVQ (2*8)(DI), SI // a2 |
| MOVQ (3*8)(DI), DX // a3 |
| MOVQ DI, (SP) |
| MOVQ (1*8)(DI), DI // a1 |
| XORL AX, AX // vararg: say "no float args" |
| |
| CALL CX |
| |
| MOVQ (SP), DI |
| MOVQ AX, (4*8)(DI) // r1 |
| MOVQ DX, (5*8)(DI) // r2 |
| |
| // Standard libc functions return -1 on error |
| // and set errno. |
| CMPQ AX, $-1 |
| JNE ok |
| |
| // Get error code from libc. |
| CALL libc_errno(SB) |
| MOVLQSX (AX), AX |
| MOVQ (SP), DI |
| MOVQ AX, (6*8)(DI) // err |
| |
| ok: |
| XORL AX, AX // no error (it's ignored anyway) |
| MOVQ BP, SP |
| POPQ BP |
| RET |
| |
| // syscall6 calls a function in libc on behalf of the syscall package. |
| // syscall6 takes a pointer to a struct like: |
| // struct { |
| // fn uintptr |
| // a1 uintptr |
| // a2 uintptr |
| // a3 uintptr |
| // a4 uintptr |
| // a5 uintptr |
| // a6 uintptr |
| // r1 uintptr |
| // r2 uintptr |
| // err uintptr |
| // } |
| // syscall6 must be called on the g0 stack with the |
| // C calling convention (use libcCall). |
| // |
| // syscall6 expects a 32-bit result and tests for 32-bit -1 |
| // to decide there was an error. |
| TEXT runtime·syscall6(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| SUBQ $16, SP |
| MOVQ (0*8)(DI), R11// fn |
| MOVQ (2*8)(DI), SI // a2 |
| MOVQ (3*8)(DI), DX // a3 |
| MOVQ (4*8)(DI), CX // a4 |
| MOVQ (5*8)(DI), R8 // a5 |
| MOVQ (6*8)(DI), R9 // a6 |
| MOVQ DI, (SP) |
| MOVQ (1*8)(DI), DI // a1 |
| XORL AX, AX // vararg: say "no float args" |
| |
| CALL R11 |
| |
| MOVQ (SP), DI |
| MOVQ AX, (7*8)(DI) // r1 |
| MOVQ DX, (8*8)(DI) // r2 |
| |
| CMPL AX, $-1 |
| JNE ok |
| |
| CALL libc_errno(SB) |
| MOVLQSX (AX), AX |
| MOVQ (SP), DI |
| MOVQ AX, (9*8)(DI) // err |
| |
| ok: |
| XORL AX, AX // no error (it's ignored anyway) |
| MOVQ BP, SP |
| POPQ BP |
| RET |
| |
| // syscall6X calls a function in libc on behalf of the syscall package. |
| // syscall6X takes a pointer to a struct like: |
| // struct { |
| // fn uintptr |
| // a1 uintptr |
| // a2 uintptr |
| // a3 uintptr |
| // a4 uintptr |
| // a5 uintptr |
| // a6 uintptr |
| // r1 uintptr |
| // r2 uintptr |
| // err uintptr |
| // } |
| // syscall6X must be called on the g0 stack with the |
| // C calling convention (use libcCall). |
| // |
| // syscall6X is like syscall6 but expects a 64-bit result |
| // and tests for 64-bit -1 to decide there was an error. |
| TEXT runtime·syscall6X(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| SUBQ $16, SP |
| MOVQ (0*8)(DI), R11// fn |
| MOVQ (2*8)(DI), SI // a2 |
| MOVQ (3*8)(DI), DX // a3 |
| MOVQ (4*8)(DI), CX // a4 |
| MOVQ (5*8)(DI), R8 // a5 |
| MOVQ (6*8)(DI), R9 // a6 |
| MOVQ DI, (SP) |
| MOVQ (1*8)(DI), DI // a1 |
| XORL AX, AX // vararg: say "no float args" |
| |
| CALL R11 |
| |
| MOVQ (SP), DI |
| MOVQ AX, (7*8)(DI) // r1 |
| MOVQ DX, (8*8)(DI) // r2 |
| |
| CMPQ AX, $-1 |
| JNE ok |
| |
| CALL libc_errno(SB) |
| MOVLQSX (AX), AX |
| MOVQ (SP), DI |
| MOVQ AX, (9*8)(DI) // err |
| |
| ok: |
| XORL AX, AX // no error (it's ignored anyway) |
| MOVQ BP, SP |
| POPQ BP |
| RET |
| |
| // syscall10 calls a function in libc on behalf of the syscall package. |
| // syscall10 takes a pointer to a struct like: |
| // struct { |
| // fn uintptr |
| // a1 uintptr |
| // a2 uintptr |
| // a3 uintptr |
| // a4 uintptr |
| // a5 uintptr |
| // a6 uintptr |
| // a7 uintptr |
| // a8 uintptr |
| // a9 uintptr |
| // a10 uintptr |
| // r1 uintptr |
| // r2 uintptr |
| // err uintptr |
| // } |
| // syscall10 must be called on the g0 stack with the |
| // C calling convention (use libcCall). |
| TEXT runtime·syscall10(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| SUBQ $48, SP |
| |
| // Arguments a1 to a6 get passed in registers, with a7 onwards being |
| // passed via the stack per the x86-64 System V ABI |
| // (https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf). |
| MOVQ (7*8)(DI), R10 // a7 |
| MOVQ (8*8)(DI), R11 // a8 |
| MOVQ (9*8)(DI), R12 // a9 |
| MOVQ (10*8)(DI), R13 // a10 |
| MOVQ R10, (0*8)(SP) // a7 |
| MOVQ R11, (1*8)(SP) // a8 |
| MOVQ R12, (2*8)(SP) // a9 |
| MOVQ R13, (3*8)(SP) // a10 |
| MOVQ (0*8)(DI), R11 // fn |
| MOVQ (2*8)(DI), SI // a2 |
| MOVQ (3*8)(DI), DX // a3 |
| MOVQ (4*8)(DI), CX // a4 |
| MOVQ (5*8)(DI), R8 // a5 |
| MOVQ (6*8)(DI), R9 // a6 |
| MOVQ DI, (4*8)(SP) |
| MOVQ (1*8)(DI), DI // a1 |
| XORL AX, AX // vararg: say "no float args" |
| |
| CALL R11 |
| |
| MOVQ (4*8)(SP), DI |
| MOVQ AX, (11*8)(DI) // r1 |
| MOVQ DX, (12*8)(DI) // r2 |
| |
| CMPL AX, $-1 |
| JNE ok |
| |
| CALL libc_errno(SB) |
| MOVLQSX (AX), AX |
| MOVQ (4*8)(SP), DI |
| MOVQ AX, (13*8)(DI) // err |
| |
| ok: |
| XORL AX, AX // no error (it's ignored anyway) |
| MOVQ BP, SP |
| POPQ BP |
| RET |
| |
| // syscall10X calls a function in libc on behalf of the syscall package. |
| // syscall10X takes a pointer to a struct like: |
| // struct { |
| // fn uintptr |
| // a1 uintptr |
| // a2 uintptr |
| // a3 uintptr |
| // a4 uintptr |
| // a5 uintptr |
| // a6 uintptr |
| // a7 uintptr |
| // a8 uintptr |
| // a9 uintptr |
| // a10 uintptr |
| // r1 uintptr |
| // r2 uintptr |
| // err uintptr |
| // } |
| // syscall10X must be called on the g0 stack with the |
| // C calling convention (use libcCall). |
| // |
| // syscall10X is like syscall10 but expects a 64-bit result |
| // and tests for 64-bit -1 to decide there was an error. |
| TEXT runtime·syscall10X(SB),NOSPLIT,$0 |
| PUSHQ BP |
| MOVQ SP, BP |
| SUBQ $48, SP |
| |
| // Arguments a1 to a6 get passed in registers, with a7 onwards being |
| // passed via the stack per the x86-64 System V ABI |
| // (https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf). |
| MOVQ (7*8)(DI), R10 // a7 |
| MOVQ (8*8)(DI), R11 // a8 |
| MOVQ (9*8)(DI), R12 // a9 |
| MOVQ (10*8)(DI), R13 // a10 |
| MOVQ R10, (0*8)(SP) // a7 |
| MOVQ R11, (1*8)(SP) // a8 |
| MOVQ R12, (2*8)(SP) // a9 |
| MOVQ R13, (3*8)(SP) // a10 |
| MOVQ (0*8)(DI), R11 // fn |
| MOVQ (2*8)(DI), SI // a2 |
| MOVQ (3*8)(DI), DX // a3 |
| MOVQ (4*8)(DI), CX // a4 |
| MOVQ (5*8)(DI), R8 // a5 |
| MOVQ (6*8)(DI), R9 // a6 |
| MOVQ DI, (4*8)(SP) |
| MOVQ (1*8)(DI), DI // a1 |
| XORL AX, AX // vararg: say "no float args" |
| |
| CALL R11 |
| |
| MOVQ (4*8)(SP), DI |
| MOVQ AX, (11*8)(DI) // r1 |
| MOVQ DX, (12*8)(DI) // r2 |
| |
| CMPQ AX, $-1 |
| JNE ok |
| |
| CALL libc_errno(SB) |
| MOVLQSX (AX), AX |
| MOVQ (4*8)(SP), DI |
| MOVQ AX, (13*8)(DI) // err |
| |
| ok: |
| XORL AX, AX // no error (it's ignored anyway) |
| MOVQ BP, SP |
| POPQ BP |
| RET |