// Copyright 2015 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 ARM64, Darwin // System calls are implemented in libSystem, this file contains // trampolines that convert from Go to C calling convention. #include "go_asm.h" #include "go_tls.h" #include "textflag.h" #include "cgo/abi_arm64.h" #define CLOCK_REALTIME 0 TEXT notok<>(SB),NOSPLIT,$0 MOVD $0, R8 MOVD R8, (R8) B 0(PC) TEXT runtime·open_trampoline(SB),NOSPLIT,$0 SUB $16, RSP MOVW 8(R0), R1 // arg 2 flags MOVW 12(R0), R2 // arg 3 mode MOVW R2, (RSP) // arg 3 is variadic, pass on stack MOVD 0(R0), R0 // arg 1 pathname BL libc_open(SB) ADD $16, RSP RET TEXT runtime·close_trampoline(SB),NOSPLIT,$0 MOVW 0(R0), R0 // arg 1 fd BL libc_close(SB) RET TEXT runtime·write_trampoline(SB),NOSPLIT,$0 MOVD 8(R0), R1 // arg 2 buf MOVW 16(R0), R2 // arg 3 count MOVW 0(R0), R0 // arg 1 fd BL libc_write(SB) MOVD $-1, R1 CMP R0, R1 BNE noerr BL libc_error(SB) MOVW (R0), R0 NEG R0, R0 // caller expects negative errno value noerr: RET TEXT runtime·read_trampoline(SB),NOSPLIT,$0 MOVD 8(R0), R1 // arg 2 buf MOVW 16(R0), R2 // arg 3 count MOVW 0(R0), R0 // arg 1 fd BL libc_read(SB) MOVD $-1, R1 CMP R0, R1 BNE noerr BL libc_error(SB) MOVW (R0), R0 NEG R0, R0 // caller expects negative errno value noerr: RET TEXT runtime·pipe_trampoline(SB),NOSPLIT,$0 BL libc_pipe(SB) // pointer already in R0 CMP $0, R0 BEQ 3(PC) BL libc_error(SB) // return negative errno value NEG R0, R0 RET TEXT runtime·exit_trampoline(SB),NOSPLIT|NOFRAME,$0 MOVW 0(R0), R0 BL libc_exit(SB) MOVD $1234, R0 MOVD $1002, R1 MOVD R0, (R1) // fail hard TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0 MOVD 0(R0), R19 // signal BL libc_getpid(SB) // arg 1 pid already in R0 from getpid MOVD R19, R1 // arg 2 signal BL libc_kill(SB) RET TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0 MOVD R0, R19 MOVD 0(R19), R0 // arg 1 addr MOVD 8(R19), R1 // arg 2 len MOVW 16(R19), R2 // arg 3 prot MOVW 20(R19), R3 // arg 4 flags MOVW 24(R19), R4 // arg 5 fd MOVW 28(R19), R5 // arg 6 off BL libc_mmap(SB) MOVD $0, R1 MOVD $-1, R2 CMP R0, R2 BNE ok BL libc_error(SB) MOVW (R0), R1 MOVD $0, R0 ok: MOVD R0, 32(R19) // ret 1 p MOVD R1, 40(R19) // ret 2 err RET TEXT runtime·munmap_trampoline(SB),NOSPLIT,$0 MOVD 8(R0), R1 // arg 2 len MOVD 0(R0), R0 // arg 1 addr BL libc_munmap(SB) CMP $0, R0 BEQ 2(PC) BL notok<>(SB) RET TEXT runtime·madvise_trampoline(SB),NOSPLIT,$0 MOVD 8(R0), R1 // arg 2 len MOVW 16(R0), R2 // arg 3 advice MOVD 0(R0), R0 // arg 1 addr BL libc_madvise(SB) RET TEXT runtime·mlock_trampoline(SB),NOSPLIT,$0 MOVD 8(R0), R1 // arg 2 len MOVD 0(R0), R0 // arg 1 addr BL libc_mlock(SB) RET TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0 MOVD 8(R0), R1 // arg 2 new MOVD 16(R0), R2 // arg 3 old MOVW 0(R0), R0 // arg 1 which BL libc_setitimer(SB) RET TEXT runtime·walltime_trampoline(SB),NOSPLIT,$0 MOVD R0, R1 // arg 2 timespec MOVW $CLOCK_REALTIME, R0 // arg 1 clock_id BL libc_clock_gettime(SB) RET GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size) TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$40 MOVD R0, R19 BL libc_mach_absolute_time(SB) MOVD R0, 0(R19) MOVW timebase<>+machTimebaseInfo_numer(SB), R20 MOVD $timebase<>+machTimebaseInfo_denom(SB), R21 LDARW (R21), R21 // atomic read CMP $0, R21 BNE initialized SUB $(machTimebaseInfo__size+15)/16*16, RSP MOVD RSP, R0 BL libc_mach_timebase_info(SB) MOVW machTimebaseInfo_numer(RSP), R20 MOVW machTimebaseInfo_denom(RSP), R21 ADD $(machTimebaseInfo__size+15)/16*16, RSP MOVW R20, timebase<>+machTimebaseInfo_numer(SB) MOVD $timebase<>+machTimebaseInfo_denom(SB), R22 STLRW R21, (R22) // atomic write initialized: MOVW R20, 8(R19) MOVW R21, 12(R19) RET TEXT runtime·sigfwd(SB),NOSPLIT,$0-32 MOVW sig+8(FP), R0 MOVD info+16(FP), R1 MOVD ctx+24(FP), R2 MOVD fn+0(FP), R11 BL (R11) RET TEXT runtime·sigtramp(SB),NOSPLIT|TOPFRAME,$176 // Save callee-save registers in the case of signal forwarding. // Please refer to https://golang.org/issue/31827 . SAVE_R19_TO_R28(8*4) SAVE_F8_TO_F15(8*14) // Save arguments. MOVW R0, (8*1)(RSP) // sig MOVD R1, (8*2)(RSP) // info MOVD R2, (8*3)(RSP) // ctx // this might be called in external code context, // where g is not set. BL runtime·load_g(SB) #ifdef GOOS_ios MOVD RSP, R6 CMP $0, g BEQ nog // iOS always use the main stack to run the signal handler. // We need to switch to gsignal ourselves. MOVD g_m(g), R11 MOVD m_gsignal(R11), R5 MOVD (g_stack+stack_hi)(R5), R6 nog: // Restore arguments. MOVW (8*1)(RSP), R0 MOVD (8*2)(RSP), R1 MOVD (8*3)(RSP), R2 // Reserve space for args and the stack pointer on the // gsignal stack. SUB $48, R6 // Save stack pointer. MOVD RSP, R4 MOVD R4, (8*4)(R6) // Switch to gsignal stack. MOVD R6, RSP // Save arguments. MOVW R0, (8*1)(RSP) MOVD R1, (8*2)(RSP) MOVD R2, (8*3)(RSP) #endif // Call sigtrampgo. MOVD $runtime·sigtrampgo(SB), R11 BL (R11) #ifdef GOOS_ios // Switch to old stack. MOVD (8*4)(RSP), R5 MOVD R5, RSP #endif // Restore callee-save registers. RESTORE_R19_TO_R28(8*4) RESTORE_F8_TO_F15(8*14) RET TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0 JMP runtime·sigtramp(SB) TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0 MOVD 8(R0), R1 // arg 2 new MOVD 16(R0), R2 // arg 3 old MOVW 0(R0), R0 // arg 1 how BL libc_pthread_sigmask(SB) CMP $0, R0 BEQ 2(PC) BL notok<>(SB) RET TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0 MOVD 8(R0), R1 // arg 2 new MOVD 16(R0), R2 // arg 3 old MOVW 0(R0), R0 // arg 1 how BL libc_sigaction(SB) CMP $0, R0 BEQ 2(PC) BL notok<>(SB) RET TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0 MOVW 0(R0), R0 // arg 1 usec BL libc_usleep(SB) RET TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0 MOVW 8(R0), R1 // arg 2 miblen MOVD 16(R0), R2 // arg 3 oldp MOVD 24(R0), R3 // arg 4 oldlenp MOVD 32(R0), R4 // arg 5 newp MOVD 40(R0), R5 // arg 6 newlen MOVD 0(R0), R0 // arg 1 mib BL libc_sysctl(SB) RET TEXT runtime·sysctlbyname_trampoline(SB),NOSPLIT,$0 MOVD 8(R0), R1 // arg 2 oldp MOVD 16(R0), R2 // arg 3 oldlenp MOVD 24(R0), R3 // arg 4 newp MOVD 32(R0), R4 // arg 5 newlen MOVD 0(R0), R0 // arg 1 name BL libc_sysctlbyname(SB) RET TEXT runtime·kqueue_trampoline(SB),NOSPLIT,$0 BL libc_kqueue(SB) RET TEXT runtime·kevent_trampoline(SB),NOSPLIT,$0 MOVD 8(R0), R1 // arg 2 keventt MOVW 16(R0), R2 // arg 3 nch MOVD 24(R0), R3 // arg 4 ev MOVW 32(R0), R4 // arg 5 nev MOVD 40(R0), R5 // arg 6 ts MOVW 0(R0), R0 // arg 1 kq BL libc_kevent(SB) MOVD $-1, R2 CMP R0, R2 BNE ok BL libc_error(SB) MOVW (R0), R0 // errno NEG R0, R0 // caller wants it as a negative error code ok: RET TEXT runtime·fcntl_trampoline(SB),NOSPLIT,$0 SUB $16, RSP MOVD R0, R19 MOVW 0(R19), R0 // arg 1 fd MOVW 4(R19), R1 // arg 2 cmd MOVW 8(R19), R2 // arg 3 arg MOVW R2, (RSP) // arg 3 is variadic, pass on stack BL libc_fcntl(SB) MOVD $0, R1 MOVD $-1, R2 CMP R0, R2 BNE noerr BL libc_error(SB) MOVW (R0), R1 MOVW $-1, R0 noerr: MOVW R0, 12(R19) MOVW R1, 16(R19) ADD $16, RSP RET TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0 #ifdef GOOS_ios // sigaltstack on iOS is not supported and will always // run the signal handler on the main stack, so our sigtramp has // to do the stack switch ourselves. MOVW $43, R0 BL libc_exit(SB) #else MOVD 8(R0), R1 // arg 2 old MOVD 0(R0), R0 // arg 1 new CALL libc_sigaltstack(SB) CBZ R0, 2(PC) BL notok<>(SB) #endif RET // Thread related functions // 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,$160 // R0 points to the m. // We are already on m's g0 stack. // Save callee-save registers. SAVE_R19_TO_R28(8) SAVE_F8_TO_F15(88) MOVD m_g0(R0), g BL ·save_g(SB) BL runtime·mstart(SB) // Restore callee-save registers. RESTORE_R19_TO_R28(8) RESTORE_F8_TO_F15(88) // 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). MOVD $0, R0 RET TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0 MOVD 0(R0), R0 // arg 1 attr BL libc_pthread_attr_init(SB) RET TEXT runtime·pthread_attr_getstacksize_trampoline(SB),NOSPLIT,$0 MOVD 8(R0), R1 // arg 2 size MOVD 0(R0), R0 // arg 1 attr BL libc_pthread_attr_getstacksize(SB) RET TEXT runtime·pthread_attr_setdetachstate_trampoline(SB),NOSPLIT,$0 MOVD 8(R0), R1 // arg 2 state MOVD 0(R0), R0 // arg 1 attr BL libc_pthread_attr_setdetachstate(SB) RET TEXT runtime·pthread_create_trampoline(SB),NOSPLIT,$0 SUB $16, RSP MOVD 0(R0), R1 // arg 2 state MOVD 8(R0), R2 // arg 3 start MOVD 16(R0), R3 // arg 4 arg MOVD RSP, R0 // arg 1 &threadid (which we throw away) BL libc_pthread_create(SB) ADD $16, RSP RET TEXT runtime·raise_trampoline(SB),NOSPLIT,$0 MOVW 0(R0), R0 // arg 1 sig BL libc_raise(SB) RET TEXT runtime·pthread_mutex_init_trampoline(SB),NOSPLIT,$0 MOVD 8(R0), R1 // arg 2 attr MOVD 0(R0), R0 // arg 1 mutex BL libc_pthread_mutex_init(SB) RET TEXT runtime·pthread_mutex_lock_trampoline(SB),NOSPLIT,$0 MOVD 0(R0), R0 // arg 1 mutex BL libc_pthread_mutex_lock(SB) RET TEXT runtime·pthread_mutex_unlock_trampoline(SB),NOSPLIT,$0 MOVD 0(R0), R0 // arg 1 mutex BL libc_pthread_mutex_unlock(SB) RET TEXT runtime·pthread_cond_init_trampoline(SB),NOSPLIT,$0 MOVD 8(R0), R1 // arg 2 attr MOVD 0(R0), R0 // arg 1 cond BL libc_pthread_cond_init(SB) RET TEXT runtime·pthread_cond_wait_trampoline(SB),NOSPLIT,$0 MOVD 8(R0), R1 // arg 2 mutex MOVD 0(R0), R0 // arg 1 cond BL libc_pthread_cond_wait(SB) RET TEXT runtime·pthread_cond_timedwait_relative_np_trampoline(SB),NOSPLIT,$0 MOVD 8(R0), R1 // arg 2 mutex MOVD 16(R0), R2 // arg 3 timeout MOVD 0(R0), R0 // arg 1 cond BL libc_pthread_cond_timedwait_relative_np(SB) RET TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0 MOVD 0(R0), R0 // arg 1 cond BL libc_pthread_cond_signal(SB) RET TEXT runtime·pthread_self_trampoline(SB),NOSPLIT,$0 MOVD R0, R19 // R19 is callee-save BL libc_pthread_self(SB) MOVD R0, 0(R19) // return value RET TEXT runtime·pthread_kill_trampoline(SB),NOSPLIT,$0 MOVD 8(R0), R1 // arg 2 sig MOVD 0(R0), R0 // arg 1 thread BL libc_pthread_kill(SB) RET TEXT runtime·pthread_key_create_trampoline(SB),NOSPLIT,$0 MOVD 8(R0), R1 // arg 2 destructor MOVD 0(R0), R0 // arg 1 *key BL libc_pthread_key_create(SB) RET TEXT runtime·pthread_setspecific_trampoline(SB),NOSPLIT,$0 MOVD 8(R0), R1 // arg 2 value MOVD 0(R0), R0 // arg 1 key BL libc_pthread_setspecific(SB) RET TEXT runtime·osinit_hack_trampoline(SB),NOSPLIT,$0 MOVD $0, R0 // arg 1 val BL libc_notify_is_valid_token(SB) BL libc_xpc_date_create_from_current(SB) 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). TEXT runtime·syscall(SB),NOSPLIT,$0 SUB $16, RSP // push structure pointer MOVD R0, 8(RSP) MOVD 0(R0), R12 // fn MOVD 16(R0), R1 // a2 MOVD 24(R0), R2 // a3 MOVD 8(R0), R0 // a1 // If fn is declared as vararg, we have to pass the vararg arguments on the stack. // (Because ios decided not to adhere to the standard arm64 calling convention, sigh...) // The only libSystem calls we support that are vararg are open, fcntl, and ioctl, // which are all of the form fn(x, y, ...). So we just need to put the 3rd arg // on the stack as well. // If we ever have other vararg libSystem calls, we might need to handle more cases. MOVD R2, (RSP) BL (R12) MOVD 8(RSP), R2 // pop structure pointer ADD $16, RSP MOVD R0, 32(R2) // save r1 MOVD R1, 40(R2) // save r2 CMPW $-1, R0 BNE ok SUB $16, RSP // push structure pointer MOVD R2, 8(RSP) BL libc_error(SB) MOVW (R0), R0 MOVD 8(RSP), R2 // pop structure pointer ADD $16, RSP MOVD R0, 48(R2) // save err ok: 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). TEXT runtime·syscallX(SB),NOSPLIT,$0 SUB $16, RSP // push structure pointer MOVD R0, (RSP) MOVD 0(R0), R12 // fn MOVD 16(R0), R1 // a2 MOVD 24(R0), R2 // a3 MOVD 8(R0), R0 // a1 BL (R12) MOVD (RSP), R2 // pop structure pointer ADD $16, RSP MOVD R0, 32(R2) // save r1 MOVD R1, 40(R2) // save r2 CMP $-1, R0 BNE ok SUB $16, RSP // push structure pointer MOVD R2, (RSP) BL libc_error(SB) MOVW (R0), R0 MOVD (RSP), R2 // pop structure pointer ADD $16, RSP MOVD R0, 48(R2) // save err ok: RET // syscallPtr is like syscallX except that the libc function reports an // error by returning NULL and setting errno. TEXT runtime·syscallPtr(SB),NOSPLIT,$0 SUB $16, RSP // push structure pointer MOVD R0, (RSP) MOVD 0(R0), R12 // fn MOVD 16(R0), R1 // a2 MOVD 24(R0), R2 // a3 MOVD 8(R0), R0 // a1 BL (R12) MOVD (RSP), R2 // pop structure pointer ADD $16, RSP MOVD R0, 32(R2) // save r1 MOVD R1, 40(R2) // save r2 CMP $0, R0 BNE ok SUB $16, RSP // push structure pointer MOVD R2, (RSP) BL libc_error(SB) MOVW (R0), R0 MOVD (RSP), R2 // pop structure pointer ADD $16, RSP MOVD R0, 48(R2) // save err ok: 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). TEXT runtime·syscall6(SB),NOSPLIT,$0 SUB $16, RSP // push structure pointer MOVD R0, 8(RSP) MOVD 0(R0), R12 // fn MOVD 16(R0), R1 // a2 MOVD 24(R0), R2 // a3 MOVD 32(R0), R3 // a4 MOVD 40(R0), R4 // a5 MOVD 48(R0), R5 // a6 MOVD 8(R0), R0 // a1 // If fn is declared as vararg, we have to pass the vararg arguments on the stack. // See syscall above. The only function this applies to is openat, for which the 4th // arg must be on the stack. MOVD R3, (RSP) BL (R12) MOVD 8(RSP), R2 // pop structure pointer ADD $16, RSP MOVD R0, 56(R2) // save r1 MOVD R1, 64(R2) // save r2 CMPW $-1, R0 BNE ok SUB $16, RSP // push structure pointer MOVD R2, 8(RSP) BL libc_error(SB) MOVW (R0), R0 MOVD 8(RSP), R2 // pop structure pointer ADD $16, RSP MOVD R0, 72(R2) // save err ok: 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). TEXT runtime·syscall6X(SB),NOSPLIT,$0 SUB $16, RSP // push structure pointer MOVD R0, (RSP) MOVD 0(R0), R12 // fn MOVD 16(R0), R1 // a2 MOVD 24(R0), R2 // a3 MOVD 32(R0), R3 // a4 MOVD 40(R0), R4 // a5 MOVD 48(R0), R5 // a6 MOVD 8(R0), R0 // a1 BL (R12) MOVD (RSP), R2 // pop structure pointer ADD $16, RSP MOVD R0, 56(R2) // save r1 MOVD R1, 64(R2) // save r2 CMP $-1, R0 BNE ok SUB $16, RSP // push structure pointer MOVD R2, (RSP) BL libc_error(SB) MOVW (R0), R0 MOVD (RSP), R2 // pop structure pointer ADD $16, RSP MOVD R0, 72(R2) // save err ok: RET // syscall9 calls a function in libc on behalf of the syscall package. // syscall9 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 // r1 uintptr // r2 uintptr // err uintptr // } // syscall9 must be called on the g0 stack with the // C calling convention (use libcCall). TEXT runtime·syscall9(SB),NOSPLIT,$0 SUB $16, RSP // push structure pointer MOVD R0, 8(RSP) MOVD 0(R0), R12 // fn MOVD 16(R0), R1 // a2 MOVD 24(R0), R2 // a3 MOVD 32(R0), R3 // a4 MOVD 40(R0), R4 // a5 MOVD 48(R0), R5 // a6 MOVD 56(R0), R6 // a7 MOVD 64(R0), R7 // a8 MOVD 72(R0), R8 // a9 MOVD 8(R0), R0 // a1 // If fn is declared as vararg, we have to pass the vararg arguments on the stack. // See syscall above. The only function this applies to is openat, for which the 4th // arg must be on the stack. MOVD R3, (RSP) BL (R12) MOVD 8(RSP), R2 // pop structure pointer ADD $16, RSP MOVD R0, 80(R2) // save r1 MOVD R1, 88(R2) // save r2 CMPW $-1, R0 BNE ok SUB $16, RSP // push structure pointer MOVD R2, 8(RSP) BL libc_error(SB) MOVW (R0), R0 MOVD 8(RSP), R2 // pop structure pointer ADD $16, RSP MOVD R0, 96(R2) // save err ok: RET // syscall_x509 is for crypto/x509. It is like syscall6 but does not check for errors, // takes 5 uintptrs and 1 float64, and only returns one value, // for use with standard C ABI functions. TEXT runtime·syscall_x509(SB),NOSPLIT,$0 SUB $16, RSP // push structure pointer MOVD R0, (RSP) MOVD 0(R0), R12 // fn MOVD 16(R0), R1 // a2 MOVD 24(R0), R2 // a3 MOVD 32(R0), R3 // a4 MOVD 40(R0), R4 // a5 FMOVD 48(R0), F0 // f1 MOVD 8(R0), R0 // a1 BL (R12) MOVD (RSP), R2 // pop structure pointer ADD $16, RSP MOVD R0, 56(R2) // save r1 RET TEXT runtime·issetugid_trampoline(SB),NOSPLIT,$0 BL libc_issetugid(SB) RET // mach_vm_region_trampoline calls mach_vm_region from libc. TEXT runtime·mach_vm_region_trampoline(SB),NOSPLIT,$0 MOVD 0(R0), R1 // address MOVD 8(R0), R2 // size MOVW 16(R0), R3 // flavor MOVD 24(R0), R4 // info MOVD 32(R0), R5 // count MOVD 40(R0), R6 // object_name MOVD $libc_mach_task_self_(SB), R0 MOVW 0(R0), R0 BL libc_mach_vm_region(SB) RET // proc_regionfilename_trampoline calls proc_regionfilename for // the current process. TEXT runtime·proc_regionfilename_trampoline(SB),NOSPLIT,$0 MOVD 8(R0), R1 // address MOVD 16(R0), R2 // buffer MOVD 24(R0), R3 // buffer_size MOVD 0(R0), R0 // pid BL libc_proc_regionfilename(SB) RET