github.com/zxy12/go_duplicate_112_new@v0.0.0-20200807091221-747231827200/src/runtime/sys_darwin_arm.s (about)

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