github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/runtime/sys_darwin_arm64.s (about)

     1  // Copyright 2015 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  // System calls and other sys.stuff for ARM64, Darwin
     6  // System calls are implemented in libSystem, this file contains
     7  // trampolines that convert from Go to C calling convention.
     8  
     9  #include "go_asm.h"
    10  #include "go_tls.h"
    11  #include "textflag.h"
    12  
    13  TEXT notok<>(SB),NOSPLIT,$0
    14  	MOVD	$0, R8
    15  	MOVD	R8, (R8)
    16  	B	0(PC)
    17  
    18  TEXT runtime·open_trampoline(SB),NOSPLIT,$0
    19  	SUB	$16, RSP
    20  	MOVW	8(R0), R1	// arg 2 flags
    21  	MOVW	12(R0), R2	// arg 3 mode
    22  	MOVW	R2, (RSP)	// arg 3 is variadic, pass on stack
    23  	MOVD	0(R0), R0	// arg 1 pathname
    24  	BL	libc_open(SB)
    25  	ADD	$16, RSP
    26  	RET
    27  
    28  TEXT runtime·close_trampoline(SB),NOSPLIT,$0
    29  	MOVW	0(R0), R0	// arg 1 fd
    30  	BL	libc_close(SB)
    31  	RET
    32  
    33  TEXT runtime·write_trampoline(SB),NOSPLIT,$0
    34  	MOVD	8(R0), R1	// arg 2 buf
    35  	MOVW	16(R0), R2	// arg 3 count
    36  	MOVW	0(R0), R0	// arg 1 fd
    37  	BL	libc_write(SB)
    38  	RET
    39  
    40  TEXT runtime·read_trampoline(SB),NOSPLIT,$0
    41  	MOVD	8(R0), R1	// arg 2 buf
    42  	MOVW	16(R0), R2	// arg 3 count
    43  	MOVW	0(R0), R0	// arg 1 fd
    44  	BL libc_read(SB)
    45  	RET
    46  
    47  TEXT runtime·exit_trampoline(SB),NOSPLIT|NOFRAME,$0
    48  	MOVW	0(R0), R0
    49  	BL	libc_exit(SB)
    50  	MOVD	$1234, R0
    51  	MOVD	$1002, R1
    52  	MOVD	R0, (R1)	// fail hard
    53  
    54  TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0
    55  	MOVD	0(R0), R19	// signal
    56  	BL	libc_getpid(SB)
    57  	// arg 1 pid already in R0 from getpid
    58  	MOVD	R19, R1	// arg 2 signal
    59  	BL	libc_kill(SB)
    60  	RET
    61  
    62  TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0
    63  	MOVD	R0, R19
    64  	MOVD	0(R19), R0	// arg 1 addr
    65  	MOVD	8(R19), R1	// arg 2 len
    66  	MOVW	16(R19), R2	// arg 3 prot
    67  	MOVW	20(R19), R3	// arg 4 flags
    68  	MOVW	24(R19), R4	// arg 5 fd
    69  	MOVW	28(R19), R5	// arg 6 off
    70  	BL	libc_mmap(SB)
    71  	MOVD	$0, R1
    72  	MOVD	$-1, R2
    73  	CMP	R0, R2
    74  	BNE	ok
    75  	BL libc_error(SB)
    76  	MOVW	(R0), R1
    77  	MOVD	$0, R0
    78  ok:
    79  	MOVD	R0, 32(R19) // ret 1 p
    80  	MOVD	R1, 40(R19)	// ret 2 err
    81  	RET
    82  
    83  TEXT runtime·munmap_trampoline(SB),NOSPLIT,$0
    84  	MOVD	8(R0), R1	// arg 2 len
    85  	MOVD	0(R0), R0	// arg 1 addr
    86  	BL	libc_munmap(SB)
    87  	CMP $0, R0
    88  	BEQ 2(PC)
    89  	BL	notok<>(SB)
    90  	RET
    91  
    92  TEXT runtime·madvise_trampoline(SB),NOSPLIT,$0
    93  	MOVD	8(R0), R1	// arg 2 len
    94  	MOVW	16(R0), R2	// arg 3 advice
    95  	MOVD	0(R0), R0	// arg 1 addr
    96  	BL	libc_madvise(SB)
    97  	RET
    98  
    99  TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0
   100  	MOVD	8(R0), R1	// arg 2 new
   101  	MOVD	16(R0), R2	// arg 3 old
   102  	MOVW	0(R0), R0	// arg 1 which
   103  	BL	libc_setitimer(SB)
   104  	RET
   105  
   106  TEXT runtime·walltime_trampoline(SB),NOSPLIT,$0
   107  	// R0 already has *timeval
   108  	MOVD	$0, R1 // no timezone needed
   109  	BL	libc_gettimeofday(SB)
   110  	RET
   111  
   112  GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size)
   113  
   114  TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$40
   115  	MOVD	R0, R19
   116  	BL	libc_mach_absolute_time(SB)
   117  	MOVD	R0, 0(R19)
   118  	MOVW	timebase<>+machTimebaseInfo_numer(SB), R20
   119  	MOVD	$timebase<>+machTimebaseInfo_denom(SB), R21
   120  	LDARW	(R21), R21	// atomic read
   121  	CMP	$0, R21
   122  	BNE	initialized
   123  
   124  	SUB	$(machTimebaseInfo__size+15)/16*16, RSP
   125  	MOVD	RSP, R0
   126  	BL	libc_mach_timebase_info(SB)
   127  	MOVW	machTimebaseInfo_numer(RSP), R20
   128  	MOVW	machTimebaseInfo_denom(RSP), R21
   129  	ADD	$(machTimebaseInfo__size+15)/16*16, RSP
   130  
   131  	MOVW	R20, timebase<>+machTimebaseInfo_numer(SB)
   132  	MOVD	$timebase<>+machTimebaseInfo_denom(SB), R22
   133  	STLRW	R21, (R22)	// atomic write
   134  
   135  initialized:
   136  	MOVW	R20, 8(R19)
   137  	MOVW	R21, 12(R19)
   138  	RET
   139  
   140  TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
   141  	MOVW	sig+8(FP), R0
   142  	MOVD	info+16(FP), R1
   143  	MOVD	ctx+24(FP), R2
   144  	MOVD	fn+0(FP), R11
   145  	BL	(R11)
   146  	RET
   147  
   148  TEXT runtime·sigtramp(SB),NOSPLIT,$0
   149  	// Reserve space for callee-save registers and arguments.
   150  	SUB	$(8*16), RSP
   151  
   152  	// Save callee-save registers.
   153  	MOVD	R19, (8*4)(RSP)
   154  	MOVD	R20, (8*5)(RSP)
   155  	MOVD	R21, (8*6)(RSP)
   156  	MOVD	R22, (8*7)(RSP)
   157  	MOVD	R23, (8*8)(RSP)
   158  	MOVD	R24, (8*9)(RSP)
   159  	MOVD	R25, (8*10)(RSP)
   160  	MOVD	R26, (8*11)(RSP)
   161  	MOVD	R27, (8*12)(RSP)
   162  	MOVD	g, (8*13)(RSP)
   163  	MOVD	R29, (8*14)(RSP)
   164  
   165  	// Save arguments.
   166  	MOVW	R0, (8*1)(RSP)	// sig
   167  	MOVD	R1, (8*2)(RSP)	// info
   168  	MOVD	R2, (8*3)(RSP)	// ctx
   169  
   170  	// this might be called in external code context,
   171  	// where g is not set.
   172  	MOVB	runtime·iscgo(SB), R0
   173  	CMP	$0, R0
   174  	BEQ	2(PC)
   175  	BL	runtime·load_g(SB)
   176  
   177  	MOVD RSP, R6
   178  	CMP	 $0, g
   179  	BEQ	 nog
   180  	// iOS always use the main stack to run the signal handler.
   181  	// We need to switch to gsignal ourselves.
   182  	MOVD	g_m(g), R11
   183  	MOVD	m_gsignal(R11), R5
   184  	MOVD	(g_stack+stack_hi)(R5), R6
   185  
   186  nog:
   187  	// Restore arguments.
   188  	MOVW	(8*1)(RSP), R0
   189  	MOVD	(8*2)(RSP), R1
   190  	MOVD	(8*3)(RSP), R2
   191  
   192  	// Reserve space for args and the stack pointer on the
   193  	// gsignal stack.
   194  	SUB	$48, R6
   195  	// Save stack pointer.
   196  	MOVD	RSP, R4
   197  	MOVD	R4, (8*4)(R6)
   198  	// Switch to gsignal stack.
   199  	MOVD	R6, RSP
   200  
   201  	// Call sigtrampgo.
   202  	MOVW	R0, (8*1)(RSP)
   203  	MOVD	R1, (8*2)(RSP)
   204  	MOVD	R2, (8*3)(RSP)
   205  	MOVD	$runtime·sigtrampgo(SB), R11
   206  	BL	(R11)
   207  
   208  	// Switch to old stack.
   209  	MOVD	(8*4)(RSP), R5
   210  	MOVD	R5, RSP
   211  
   212  	// Restore callee-save registers.
   213  	MOVD	(8*4)(RSP), R19
   214  	MOVD	(8*5)(RSP), R20
   215  	MOVD	(8*6)(RSP), R21
   216  	MOVD	(8*7)(RSP), R22
   217  	MOVD	(8*8)(RSP), R23
   218  	MOVD	(8*9)(RSP), R24
   219  	MOVD	(8*10)(RSP), R25
   220  	MOVD	(8*11)(RSP), R26
   221  	MOVD	(8*12)(RSP), R27
   222  	MOVD	(8*13)(RSP), g
   223  	MOVD	(8*14)(RSP), R29
   224  
   225  	ADD $(8*16), RSP
   226  
   227  	RET
   228  
   229  TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
   230  	JMP	runtime·sigtramp(SB)
   231  
   232  TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
   233  	MOVD	8(R0), R1	// arg 2 new
   234  	MOVD	16(R0), R2	// arg 3 old
   235  	MOVW	0(R0), R0	// arg 1 how
   236  	BL	libc_pthread_sigmask(SB)
   237  	CMP $0, R0
   238  	BEQ	2(PC)
   239  	BL	notok<>(SB)
   240  	RET
   241  
   242  TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0
   243  	MOVD	8(R0), R1	// arg 2 new
   244  	MOVD	16(R0), R2	// arg 3 old
   245  	MOVW	0(R0), R0	// arg 1 how
   246  	BL	libc_sigaction(SB)
   247  	CMP	$0, R0
   248  	BEQ	2(PC)
   249  	BL	notok<>(SB)
   250  	RET
   251  
   252  TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0
   253  	MOVW	0(R0), R0	// arg 1 usec
   254  	BL	libc_usleep(SB)
   255  	RET
   256  
   257  TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0
   258  	MOVW	8(R0), R1	// arg 2 miblen
   259  	MOVD	16(R0), R2	// arg 3 out
   260  	MOVD	24(R0), R3	// arg 4 size
   261  	MOVD	32(R0), R4	// arg 5 dst
   262  	MOVD	40(R0), R5	// arg 6 ndst
   263  	MOVD	0(R0), R0	// arg 1 mib
   264  	BL	libc_sysctl(SB)
   265  	RET
   266  
   267  TEXT runtime·kqueue_trampoline(SB),NOSPLIT,$0
   268  	BL	libc_kqueue(SB)
   269  	RET
   270  
   271  TEXT runtime·kevent_trampoline(SB),NOSPLIT,$0
   272  	MOVD	8(R0), R1	// arg 2 keventt
   273  	MOVW	16(R0), R2	// arg 3 nch
   274  	MOVD	24(R0), R3	// arg 4 ev
   275  	MOVW	32(R0), R4	// arg 5 nev
   276  	MOVD	40(R0), R5	// arg 6 ts
   277  	MOVW	0(R0), R0	// arg 1 kq
   278  	BL	libc_kevent(SB)
   279  	MOVD	$-1, R2
   280  	CMP	R0, R2
   281  	BNE	ok
   282  	BL libc_error(SB)
   283  	MOVW	(R0), R0	// errno
   284  	NEG	R0, R0	// caller wants it as a negative error code
   285  ok:
   286  	RET
   287  
   288  TEXT runtime·fcntl_trampoline(SB),NOSPLIT,$0
   289  	SUB	$16, RSP
   290  	MOVW	4(R0), R1	// arg 2 cmd
   291  	MOVW	8(R0), R2	// arg 3 arg
   292  	MOVW	R2, (RSP)	// arg 3 is variadic, pass on stack
   293  	MOVW	0(R0), R0	// arg 1 fd
   294  	BL	libc_fcntl(SB)
   295  	ADD	$16, RSP
   296  	RET
   297  
   298  // sigaltstack on iOS is not supported and will always
   299  // run the signal handler on the main stack, so our sigtramp has
   300  // to do the stack switch ourselves.
   301  TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0
   302  	MOVW	$43, R0
   303  	BL	libc_exit(SB)
   304  	RET
   305  
   306  // Thread related functions
   307  // Note: On darwin/arm64, the runtime always use runtime/cgo to
   308  // create threads, so all thread related functions will just exit with a
   309  // unique status.
   310  
   311  TEXT runtime·mstart_stub(SB),NOSPLIT,$0
   312  	MOVW	$44, R0
   313  	BL	libc_exit(SB)
   314  	RET
   315  
   316  TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0
   317  	MOVW	$45, R0
   318  	BL	libc_exit(SB)
   319  	RET
   320  
   321  TEXT runtime·pthread_attr_setstacksize_trampoline(SB),NOSPLIT,$0
   322  	MOVW	$46, R0
   323  	BL	libc_exit(SB)
   324  	RET
   325  
   326  TEXT runtime·pthread_attr_setdetachstate_trampoline(SB),NOSPLIT,$0
   327  	MOVW	$47, R0
   328  	BL	libc_exit(SB)
   329  	RET
   330  
   331  TEXT runtime·pthread_create_trampoline(SB),NOSPLIT,$0
   332  	MOVW	$48, R0
   333  	BL	libc_exit(SB)
   334  	RET
   335  
   336  TEXT runtime·raise_trampoline(SB),NOSPLIT,$0
   337  	MOVW	0(R0), R0	// arg 1 sig
   338  	BL	libc_raise(SB)
   339  	RET
   340  
   341  TEXT runtime·pthread_mutex_init_trampoline(SB),NOSPLIT,$0
   342  	MOVD	8(R0), R1	// arg 2 attr
   343  	MOVD	0(R0), R0	// arg 1 mutex
   344  	BL	libc_pthread_mutex_init(SB)
   345  	RET
   346  
   347  TEXT runtime·pthread_mutex_lock_trampoline(SB),NOSPLIT,$0
   348  	MOVD	0(R0), R0	// arg 1 mutex
   349  	BL	libc_pthread_mutex_lock(SB)
   350  	RET
   351  
   352  TEXT runtime·pthread_mutex_unlock_trampoline(SB),NOSPLIT,$0
   353  	MOVD	0(R0), R0	// arg 1 mutex
   354  	BL	libc_pthread_mutex_unlock(SB)
   355  	RET
   356  
   357  TEXT runtime·pthread_cond_init_trampoline(SB),NOSPLIT,$0
   358  	MOVD	8(R0), R1	// arg 2 attr
   359  	MOVD	0(R0), R0	// arg 1 cond
   360  	BL	libc_pthread_cond_init(SB)
   361  	RET
   362  
   363  TEXT runtime·pthread_cond_wait_trampoline(SB),NOSPLIT,$0
   364  	MOVD	8(R0), R1	// arg 2 mutex
   365  	MOVD	0(R0), R0	// arg 1 cond
   366  	BL	libc_pthread_cond_wait(SB)
   367  	RET
   368  
   369  TEXT runtime·pthread_cond_timedwait_relative_np_trampoline(SB),NOSPLIT,$0
   370  	MOVD	8(R0), R1	// arg 2 mutex
   371  	MOVD	16(R0), R2	// arg 3 timeout
   372  	MOVD	0(R0), R0	// arg 1 cond
   373  	BL	libc_pthread_cond_timedwait_relative_np(SB)
   374  	RET
   375  
   376  TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0
   377  	MOVD	0(R0), R0	// arg 1 cond
   378  	BL	libc_pthread_cond_signal(SB)
   379  	RET
   380  
   381  // syscall calls a function in libc on behalf of the syscall package.
   382  // syscall takes a pointer to a struct like:
   383  // struct {
   384  //	fn    uintptr
   385  //	a1    uintptr
   386  //	a2    uintptr
   387  //	a3    uintptr
   388  //	r1    uintptr
   389  //	r2    uintptr
   390  //	err   uintptr
   391  // }
   392  // syscall must be called on the g0 stack with the
   393  // C calling convention (use libcCall).
   394  TEXT runtime·syscall(SB),NOSPLIT,$0
   395  	SUB	$16, RSP	// push structure pointer
   396  	MOVD	R0, 8(RSP)
   397  
   398  	MOVD	0(R0), R12	// fn
   399  	MOVD	16(R0), R1	// a2
   400  	MOVD	24(R0), R2	// a3
   401  	MOVD	8(R0), R0	// a1
   402  
   403  	// If fn is declared as vararg, we have to pass the vararg arguments on the stack.
   404  	// (Because ios decided not to adhere to the standard arm64 calling convention, sigh...)
   405  	// The only libSystem calls we support that are vararg are open, fcntl, and ioctl,
   406  	// which are all of the form fn(x, y, ...). So we just need to put the 3rd arg
   407  	// on the stack as well.
   408  	// If we ever have other vararg libSystem calls, we might need to handle more cases.
   409  	MOVD	R2, (RSP)
   410  
   411  	BL	(R12)
   412  
   413  	MOVD	8(RSP), R2	// pop structure pointer
   414  	ADD	$16, RSP
   415  	MOVD	R0, 32(R2)	// save r1
   416  	MOVD	R1, 40(R2)	// save r2
   417  	CMPW	$-1, R0
   418  	BNE	ok
   419  	SUB	$16, RSP	// push structure pointer
   420  	MOVD	R2, 8(RSP)
   421  	BL	libc_error(SB)
   422  	MOVW	(R0), R0
   423  	MOVD	8(RSP), R2	// pop structure pointer
   424  	ADD	$16, RSP
   425  	MOVD	R0, 48(R2)	// save err
   426  ok:
   427  	RET
   428  
   429  // syscallX calls a function in libc on behalf of the syscall package.
   430  // syscallX takes a pointer to a struct like:
   431  // struct {
   432  //	fn    uintptr
   433  //	a1    uintptr
   434  //	a2    uintptr
   435  //	a3    uintptr
   436  //	r1    uintptr
   437  //	r2    uintptr
   438  //	err   uintptr
   439  // }
   440  // syscallX must be called on the g0 stack with the
   441  // C calling convention (use libcCall).
   442  TEXT runtime·syscallX(SB),NOSPLIT,$0
   443  	SUB	$16, RSP	// push structure pointer
   444  	MOVD	R0, (RSP)
   445  
   446  	MOVD	0(R0), R12	// fn
   447  	MOVD	16(R0), R1	// a2
   448  	MOVD	24(R0), R2	// a3
   449  	MOVD	8(R0), R0	// a1
   450  	BL	(R12)
   451  
   452  	MOVD	(RSP), R2	// pop structure pointer
   453  	ADD	$16, RSP
   454  	MOVD	R0, 32(R2)	// save r1
   455  	MOVD	R1, 40(R2)	// save r2
   456  	CMP	$-1, R0
   457  	BNE	ok
   458  	SUB	$16, RSP	// push structure pointer
   459  	MOVD	R2, (RSP)
   460  	BL	libc_error(SB)
   461  	MOVW	(R0), R0
   462  	MOVD	(RSP), R2	// pop structure pointer
   463  	ADD	$16, RSP
   464  	MOVD	R0, 48(R2)	// save err
   465  ok:
   466  	RET
   467  
   468  // syscallXPtr is like syscallX except that the libc function reports an
   469  // error by returning NULL.
   470  TEXT runtime·syscallXPtr(SB),NOSPLIT,$0
   471  	SUB	$16, RSP	// push structure pointer
   472  	MOVD	R0, (RSP)
   473  
   474  	MOVD	0(R0), R12	// fn
   475  	MOVD	16(R0), R1	// a2
   476  	MOVD	24(R0), R2	// a3
   477  	MOVD	8(R0), R0	// a1
   478  	BL	(R12)
   479  
   480  	MOVD	(RSP), R2	// pop structure pointer
   481  	ADD	$16, RSP
   482  	MOVD	R0, 32(R2)	// save r1
   483  	MOVD	R1, 40(R2)	// save r2
   484  	CMP	$0, R0
   485  	BNE	ok
   486  	SUB	$16, RSP	// push structure pointer
   487  	MOVD	R2, (RSP)
   488  	BL	libc_error(SB)
   489  	MOVW	(R0), R0
   490  	MOVD	(RSP), R2	// pop structure pointer
   491  	ADD	$16, RSP
   492  	MOVD	R0, 48(R2)	// save err
   493  ok:
   494  	RET
   495  
   496  // syscall6 calls a function in libc on behalf of the syscall package.
   497  // syscall6 takes a pointer to a struct like:
   498  // struct {
   499  //	fn    uintptr
   500  //	a1    uintptr
   501  //	a2    uintptr
   502  //	a3    uintptr
   503  //	a4    uintptr
   504  //	a5    uintptr
   505  //	a6    uintptr
   506  //	r1    uintptr
   507  //	r2    uintptr
   508  //	err   uintptr
   509  // }
   510  // syscall6 must be called on the g0 stack with the
   511  // C calling convention (use libcCall).
   512  TEXT runtime·syscall6(SB),NOSPLIT,$0
   513  	SUB	$16, RSP	// push structure pointer
   514  	MOVD	R0, 8(RSP)
   515  
   516  	MOVD	0(R0), R12	// fn
   517  	MOVD	16(R0), R1	// a2
   518  	MOVD	24(R0), R2	// a3
   519  	MOVD	32(R0), R3	// a4
   520  	MOVD	40(R0), R4	// a5
   521  	MOVD	48(R0), R5	// a6
   522  	MOVD	8(R0), R0	// a1
   523  
   524  	// If fn is declared as vararg, we have to pass the vararg arguments on the stack.
   525  	// See syscall above. The only function this applies to is openat, for which the 4th
   526  	// arg must be on the stack.
   527  	MOVD	R3, (RSP)
   528  
   529  	BL	(R12)
   530  
   531  	MOVD	8(RSP), R2	// pop structure pointer
   532  	ADD	$16, RSP
   533  	MOVD	R0, 56(R2)	// save r1
   534  	MOVD	R1, 64(R2)	// save r2
   535  	CMPW	$-1, R0
   536  	BNE	ok
   537  	SUB	$16, RSP	// push structure pointer
   538  	MOVD	R2, 8(RSP)
   539  	BL	libc_error(SB)
   540  	MOVW	(R0), R0
   541  	MOVD	8(RSP), R2	// pop structure pointer
   542  	ADD	$16, RSP
   543  	MOVD	R0, 72(R2)	// save err
   544  ok:
   545  	RET
   546  
   547  // syscall6X calls a function in libc on behalf of the syscall package.
   548  // syscall6X takes a pointer to a struct like:
   549  // struct {
   550  //	fn    uintptr
   551  //	a1    uintptr
   552  //	a2    uintptr
   553  //	a3    uintptr
   554  //	a4    uintptr
   555  //	a5    uintptr
   556  //	a6    uintptr
   557  //	r1    uintptr
   558  //	r2    uintptr
   559  //	err   uintptr
   560  // }
   561  // syscall6X must be called on the g0 stack with the
   562  // C calling convention (use libcCall).
   563  TEXT runtime·syscall6X(SB),NOSPLIT,$0
   564  	SUB	$16, RSP	// push structure pointer
   565  	MOVD	R0, (RSP)
   566  
   567  	MOVD	0(R0), R12	// fn
   568  	MOVD	16(R0), R1	// a2
   569  	MOVD	24(R0), R2	// a3
   570  	MOVD	32(R0), R3	// a4
   571  	MOVD	40(R0), R4	// a5
   572  	MOVD	48(R0), R5	// a6
   573  	MOVD	8(R0), R0	// a1
   574  	BL	(R12)
   575  
   576  	MOVD	(RSP), R2	// pop structure pointer
   577  	ADD	$16, RSP
   578  	MOVD	R0, 56(R2)	// save r1
   579  	MOVD	R1, 64(R2)	// save r2
   580  	CMP	$-1, R0
   581  	BNE	ok
   582  	SUB	$16, RSP	// push structure pointer
   583  	MOVD	R2, (RSP)
   584  	BL	libc_error(SB)
   585  	MOVW	(R0), R0
   586  	MOVD	(RSP), R2	// pop structure pointer
   587  	ADD	$16, RSP
   588  	MOVD	R0, 72(R2)	// save err
   589  ok:
   590  	RET