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// System calls and other sys.stuff for AMD64, 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#include "cgo/abi_amd64.h"
13
14#define CLOCK_REALTIME		0
15
16// Exit the entire program (like C exit)
17TEXT runtime·exit_trampoline(SB),NOSPLIT,$0
18	MOVL	0(DI), DI		// arg 1 exit status
19	CALL	libc_exit(SB)
20	MOVL	$0xf1, 0xf1  // crash
21	RET
22
23TEXT runtime·open_trampoline(SB),NOSPLIT,$0
24	MOVL	8(DI), SI		// arg 2 flags
25	MOVL	12(DI), DX		// arg 3 mode
26	MOVQ	0(DI), DI		// arg 1 pathname
27	XORL	AX, AX			// vararg: say "no float args"
28	CALL	libc_open(SB)
29	RET
30
31TEXT runtime·close_trampoline(SB),NOSPLIT,$0
32	MOVL	0(DI), DI		// arg 1 fd
33	CALL	libc_close(SB)
34	RET
35
36TEXT runtime·read_trampoline(SB),NOSPLIT,$0
37	MOVQ	8(DI), SI		// arg 2 buf
38	MOVL	16(DI), DX		// arg 3 count
39	MOVL	0(DI), DI		// arg 1 fd
40	CALL	libc_read(SB)
41	TESTL	AX, AX
42	JGE	noerr
43	CALL	libc_error(SB)
44	MOVL	(AX), AX
45	NEGL	AX			// caller expects negative errno value
46noerr:
47	RET
48
49TEXT runtime·write_trampoline(SB),NOSPLIT,$0
50	MOVQ	8(DI), SI		// arg 2 buf
51	MOVL	16(DI), DX		// arg 3 count
52	MOVQ	0(DI), DI		// arg 1 fd
53	CALL	libc_write(SB)
54	TESTL	AX, AX
55	JGE	noerr
56	CALL	libc_error(SB)
57	MOVL	(AX), AX
58	NEGL	AX			// caller expects negative errno value
59noerr:
60	RET
61
62TEXT runtime·pipe_trampoline(SB),NOSPLIT,$0
63	CALL	libc_pipe(SB)		// pointer already in DI
64	TESTL	AX, AX
65	JEQ	3(PC)
66	CALL	libc_error(SB)		// return negative errno value
67	NEGL	AX
68	RET
69
70TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0
71	MOVQ	8(DI), SI		// arg 2 new
72	MOVQ	16(DI), DX		// arg 3 old
73	MOVL	0(DI), DI		// arg 1 which
74	CALL	libc_setitimer(SB)
75	RET
76
77TEXT runtime·madvise_trampoline(SB), NOSPLIT, $0
78	MOVQ	8(DI), SI	// arg 2 len
79	MOVL	16(DI), DX	// arg 3 advice
80	MOVQ	0(DI), DI	// arg 1 addr
81	CALL	libc_madvise(SB)
82	// ignore failure - maybe pages are locked
83	RET
84
85TEXT runtime·mlock_trampoline(SB), NOSPLIT, $0
86	UNDEF // unimplemented
87
88GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size)
89
90TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0
91	MOVQ	DI, BX
92	CALL	libc_mach_absolute_time(SB)
93	MOVQ	AX, 0(BX)
94	MOVL	timebase<>+machTimebaseInfo_numer(SB), SI
95	MOVL	timebase<>+machTimebaseInfo_denom(SB), DI // atomic read
96	TESTL	DI, DI
97	JNE	initialized
98
99	SUBQ	$(machTimebaseInfo__size+15)/16*16, SP
100	MOVQ	SP, DI
101	CALL	libc_mach_timebase_info(SB)
102	MOVL	machTimebaseInfo_numer(SP), SI
103	MOVL	machTimebaseInfo_denom(SP), DI
104	ADDQ	$(machTimebaseInfo__size+15)/16*16, SP
105
106	MOVL	SI, timebase<>+machTimebaseInfo_numer(SB)
107	MOVL	DI, AX
108	XCHGL	AX, timebase<>+machTimebaseInfo_denom(SB) // atomic write
109
110initialized:
111	MOVL	SI, 8(BX)
112	MOVL	DI, 12(BX)
113	RET
114
115TEXT runtime·walltime_trampoline(SB),NOSPLIT,$0
116	MOVQ	DI, SI			// arg 2 timespec
117	MOVL	$CLOCK_REALTIME, DI	// arg 1 clock_id
118	CALL	libc_clock_gettime(SB)
119	RET
120
121TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0
122	MOVQ	8(DI), SI		// arg 2 new
123	MOVQ	16(DI), DX		// arg 3 old
124	MOVL	0(DI), DI		// arg 1 sig
125	CALL	libc_sigaction(SB)
126	TESTL	AX, AX
127	JEQ	2(PC)
128	MOVL	$0xf1, 0xf1  // crash
129	RET
130
131TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
132	MOVQ	8(DI), SI	// arg 2 new
133	MOVQ	16(DI), DX	// arg 3 old
134	MOVL	0(DI), DI	// arg 1 how
135	CALL	libc_pthread_sigmask(SB)
136	TESTL	AX, AX
137	JEQ	2(PC)
138	MOVL	$0xf1, 0xf1  // crash
139	RET
140
141TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0
142	MOVQ	8(DI), SI		// arg 2 old
143	MOVQ	0(DI), DI		// arg 1 new
144	CALL	libc_sigaltstack(SB)
145	TESTQ	AX, AX
146	JEQ	2(PC)
147	MOVL	$0xf1, 0xf1  // crash
148	RET
149
150TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0
151	MOVL	0(DI), BX	// signal
152	CALL	libc_getpid(SB)
153	MOVL	AX, DI		// arg 1 pid
154	MOVL	BX, SI		// arg 2 signal
155	CALL	libc_kill(SB)
156	RET
157
158TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
159	MOVQ	fn+0(FP),    AX
160	MOVL	sig+8(FP),   DI
161	MOVQ	info+16(FP), SI
162	MOVQ	ctx+24(FP),  DX
163	MOVQ	SP, BX		// callee-saved
164	ANDQ	$~15, SP	// alignment for x86_64 ABI
165	CALL	AX
166	MOVQ	BX, SP
167	RET
168
169// This is the function registered during sigaction and is invoked when
170// a signal is received. It just redirects to the Go function sigtrampgo.
171// Called using C ABI.
172TEXT runtime·sigtramp(SB),NOSPLIT|TOPFRAME|NOFRAME,$0
173	// Transition from C ABI to Go ABI.
174	PUSH_REGS_HOST_TO_ABI0()
175
176	// Set up ABIInternal environment: g in R14, cleared X15.
177	get_tls(R12)
178	MOVQ	g(R12), R14
179	PXOR	X15, X15
180
181	// Reserve space for spill slots.
182	NOP	SP		// disable vet stack checking
183	ADJSP   $24
184
185	// Call into the Go signal handler
186	MOVQ	DI, AX	// sig
187	MOVQ	SI, BX	// info
188	MOVQ	DX, CX	// ctx
189	CALL	·sigtrampgo<ABIInternal>(SB)
190
191	ADJSP	$-24
192
193	POP_REGS_HOST_TO_ABI0()
194	RET
195
196// Called using C ABI.
197TEXT runtime·sigprofNonGoWrapper<>(SB),NOSPLIT|NOFRAME,$0
198	// Transition from C ABI to Go ABI.
199	PUSH_REGS_HOST_TO_ABI0()
200
201	// Call into the Go signal handler
202	NOP	SP		// disable vet stack checking
203	ADJSP	$24
204	MOVL	DI, 0(SP)	// sig
205	MOVQ	SI, 8(SP)	// info
206	MOVQ	DX, 16(SP)	// ctx
207	CALL	·sigprofNonGo(SB)
208	ADJSP	$-24
209
210	POP_REGS_HOST_TO_ABI0()
211	RET
212
213// Used instead of sigtramp in programs that use cgo.
214// Arguments from kernel are in DI, SI, DX.
215TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
216	// If no traceback function, do usual sigtramp.
217	MOVQ	runtime·cgoTraceback(SB), AX
218	TESTQ	AX, AX
219	JZ	sigtramp
220
221	// If no traceback support function, which means that
222	// runtime/cgo was not linked in, do usual sigtramp.
223	MOVQ	_cgo_callers(SB), AX
224	TESTQ	AX, AX
225	JZ	sigtramp
226
227	// Figure out if we are currently in a cgo call.
228	// If not, just do usual sigtramp.
229	get_tls(CX)
230	MOVQ	g(CX),AX
231	TESTQ	AX, AX
232	JZ	sigtrampnog     // g == nil
233	MOVQ	g_m(AX), AX
234	TESTQ	AX, AX
235	JZ	sigtramp        // g.m == nil
236	MOVL	m_ncgo(AX), CX
237	TESTL	CX, CX
238	JZ	sigtramp        // g.m.ncgo == 0
239	MOVQ	m_curg(AX), CX
240	TESTQ	CX, CX
241	JZ	sigtramp        // g.m.curg == nil
242	MOVQ	g_syscallsp(CX), CX
243	TESTQ	CX, CX
244	JZ	sigtramp        // g.m.curg.syscallsp == 0
245	MOVQ	m_cgoCallers(AX), R8
246	TESTQ	R8, R8
247	JZ	sigtramp        // g.m.cgoCallers == nil
248	MOVL	m_cgoCallersUse(AX), CX
249	TESTL	CX, CX
250	JNZ	sigtramp	// g.m.cgoCallersUse != 0
251
252	// Jump to a function in runtime/cgo.
253	// That function, written in C, will call the user's traceback
254	// function with proper unwind info, and will then call back here.
255	// The first three arguments, and the fifth, are already in registers.
256	// Set the two remaining arguments now.
257	MOVQ	runtime·cgoTraceback(SB), CX
258	MOVQ	$runtime·sigtramp(SB), R9
259	MOVQ	_cgo_callers(SB), AX
260	JMP	AX
261
262sigtramp:
263	JMP	runtime·sigtramp(SB)
264
265sigtrampnog:
266	// Signal arrived on a non-Go thread. If this is SIGPROF, get a
267	// stack trace.
268	CMPL	DI, $27 // 27 == SIGPROF
269	JNZ	sigtramp
270
271	// Lock sigprofCallersUse.
272	MOVL	$0, AX
273	MOVL	$1, CX
274	MOVQ	$runtime·sigprofCallersUse(SB), R11
275	LOCK
276	CMPXCHGL	CX, 0(R11)
277	JNZ	sigtramp  // Skip stack trace if already locked.
278
279	// Jump to the traceback function in runtime/cgo.
280	// It will call back to sigprofNonGo, via sigprofNonGoWrapper, to convert
281	// the arguments to the Go calling convention.
282	// First three arguments to traceback function are in registers already.
283	MOVQ	runtime·cgoTraceback(SB), CX
284	MOVQ	$runtime·sigprofCallers(SB), R8
285	MOVQ	$runtime·sigprofNonGoWrapper<>(SB), R9
286	MOVQ	_cgo_callers(SB), AX
287	JMP	AX
288
289TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0
290	MOVQ	DI, BX
291	MOVQ	0(BX), DI		// arg 1 addr
292	MOVQ	8(BX), SI		// arg 2 len
293	MOVL	16(BX), DX		// arg 3 prot
294	MOVL	20(BX), CX		// arg 4 flags
295	MOVL	24(BX), R8		// arg 5 fid
296	MOVL	28(BX), R9		// arg 6 offset
297	CALL	libc_mmap(SB)
298	XORL	DX, DX
299	CMPQ	AX, $-1
300	JNE	ok
301	CALL	libc_error(SB)
302	MOVLQSX	(AX), DX		// errno
303	XORL	AX, AX
304ok:
305	MOVQ	AX, 32(BX)
306	MOVQ	DX, 40(BX)
307	RET
308
309TEXT runtime·munmap_trampoline(SB),NOSPLIT,$0
310	MOVQ	8(DI), SI		// arg 2 len
311	MOVQ	0(DI), DI		// arg 1 addr
312	CALL	libc_munmap(SB)
313	TESTQ	AX, AX
314	JEQ	2(PC)
315	MOVL	$0xf1, 0xf1  // crash
316	RET
317
318TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0
319	MOVL	0(DI), DI	// arg 1 usec
320	CALL	libc_usleep(SB)
321	RET
322
323TEXT runtime·settls(SB),NOSPLIT,$32
324	// Nothing to do on Darwin, pthread already set thread-local storage up.
325	RET
326
327TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0
328	MOVL	8(DI), SI		// arg 2 miblen
329	MOVQ	16(DI), DX		// arg 3 oldp
330	MOVQ	24(DI), CX		// arg 4 oldlenp
331	MOVQ	32(DI), R8		// arg 5 newp
332	MOVQ	40(DI), R9		// arg 6 newlen
333	MOVQ	0(DI), DI		// arg 1 mib
334	CALL	libc_sysctl(SB)
335	RET
336
337TEXT runtime·sysctlbyname_trampoline(SB),NOSPLIT,$0
338	MOVQ	8(DI), SI		// arg 2 oldp
339	MOVQ	16(DI), DX		// arg 3 oldlenp
340	MOVQ	24(DI), CX		// arg 4 newp
341	MOVQ	32(DI), R8		// arg 5 newlen
342	MOVQ	0(DI), DI		// arg 1 name
343	CALL	libc_sysctlbyname(SB)
344	RET
345
346TEXT runtime·kqueue_trampoline(SB),NOSPLIT,$0
347	CALL	libc_kqueue(SB)
348	RET
349
350TEXT runtime·kevent_trampoline(SB),NOSPLIT,$0
351	MOVQ	8(DI), SI		// arg 2 keventt
352	MOVL	16(DI), DX		// arg 3 nch
353	MOVQ	24(DI), CX		// arg 4 ev
354	MOVL	32(DI), R8		// arg 5 nev
355	MOVQ	40(DI), R9		// arg 6 ts
356	MOVL	0(DI), DI		// arg 1 kq
357	CALL	libc_kevent(SB)
358	CMPL	AX, $-1
359	JNE	ok
360	CALL	libc_error(SB)
361	MOVLQSX	(AX), AX		// errno
362	NEGQ	AX			// caller wants it as a negative error code
363ok:
364	RET
365
366TEXT runtime·fcntl_trampoline(SB),NOSPLIT,$0
367	MOVQ	DI, BX
368	MOVL	0(BX), DI		// arg 1 fd
369	MOVL	4(BX), SI		// arg 2 cmd
370	MOVL	8(BX), DX		// arg 3 arg
371	XORL	AX, AX			// vararg: say "no float args"
372	CALL	libc_fcntl(SB)
373	XORL	DX, DX
374	CMPQ	AX, $-1
375	JNE	noerr
376	CALL	libc_error(SB)
377	MOVL	(AX), DX
378	MOVL	$-1, AX
379noerr:
380	MOVL	AX, 12(BX)
381	MOVL	DX, 16(BX)
382	RET
383
384// mstart_stub is the first function executed on a new thread started by pthread_create.
385// It just does some low-level setup and then calls mstart.
386// Note: called with the C calling convention.
387TEXT runtime·mstart_stub(SB),NOSPLIT|NOFRAME,$0
388	// DI points to the m.
389	// We are already on m's g0 stack.
390
391	// Transition from C ABI to Go ABI.
392	PUSH_REGS_HOST_TO_ABI0()
393
394	MOVQ	m_g0(DI), DX // g
395
396	// Initialize TLS entry.
397	// See cmd/link/internal/ld/sym.go:computeTLSOffset.
398	MOVQ	DX, 0x30(GS)
399
400	CALL	runtime·mstart(SB)
401
402	POP_REGS_HOST_TO_ABI0()
403
404	// Go is all done with this OS thread.
405	// Tell pthread everything is ok (we never join with this thread, so
406	// the value here doesn't really matter).
407	XORL	AX, AX
408	RET
409
410// These trampolines help convert from Go calling convention to C calling convention.
411// They should be called with asmcgocall.
412// A pointer to the arguments is passed in DI.
413// A single int32 result is returned in AX.
414// (For more results, make an args/results structure.)
415TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0
416	MOVQ	0(DI), DI // arg 1 attr
417	CALL	libc_pthread_attr_init(SB)
418	RET
419
420TEXT runtime·pthread_attr_getstacksize_trampoline(SB),NOSPLIT,$0
421	MOVQ	8(DI), SI	// arg 2 size
422	MOVQ	0(DI), DI	// arg 1 attr
423	CALL	libc_pthread_attr_getstacksize(SB)
424	RET
425
426TEXT runtime·pthread_attr_setdetachstate_trampoline(SB),NOSPLIT,$0
427	MOVQ	8(DI), SI	// arg 2 state
428	MOVQ	0(DI), DI	// arg 1 attr
429	CALL	libc_pthread_attr_setdetachstate(SB)
430	RET
431
432TEXT runtime·pthread_create_trampoline(SB),NOSPLIT,$16
433	MOVQ	0(DI), SI	// arg 2 attr
434	MOVQ	8(DI), DX	// arg 3 start
435	MOVQ	16(DI), CX	// arg 4 arg
436	MOVQ	SP, DI		// arg 1 &threadid (which we throw away)
437	CALL	libc_pthread_create(SB)
438	RET
439
440TEXT runtime·raise_trampoline(SB),NOSPLIT,$0
441	MOVL	0(DI), DI	// arg 1 signal
442	CALL	libc_raise(SB)
443	RET
444
445TEXT runtime·pthread_mutex_init_trampoline(SB),NOSPLIT,$0
446	MOVQ	8(DI), SI	// arg 2 attr
447	MOVQ	0(DI), DI	// arg 1 mutex
448	CALL	libc_pthread_mutex_init(SB)
449	RET
450
451TEXT runtime·pthread_mutex_lock_trampoline(SB),NOSPLIT,$0
452	MOVQ	0(DI), DI	// arg 1 mutex
453	CALL	libc_pthread_mutex_lock(SB)
454	RET
455
456TEXT runtime·pthread_mutex_unlock_trampoline(SB),NOSPLIT,$0
457	MOVQ	0(DI), DI	// arg 1 mutex
458	CALL	libc_pthread_mutex_unlock(SB)
459	RET
460
461TEXT runtime·pthread_cond_init_trampoline(SB),NOSPLIT,$0
462	MOVQ	8(DI), SI	// arg 2 attr
463	MOVQ	0(DI), DI	// arg 1 cond
464	CALL	libc_pthread_cond_init(SB)
465	RET
466
467TEXT runtime·pthread_cond_wait_trampoline(SB),NOSPLIT,$0
468	MOVQ	8(DI), SI	// arg 2 mutex
469	MOVQ	0(DI), DI	// arg 1 cond
470	CALL	libc_pthread_cond_wait(SB)
471	RET
472
473TEXT runtime·pthread_cond_timedwait_relative_np_trampoline(SB),NOSPLIT,$0
474	MOVQ	8(DI), SI	// arg 2 mutex
475	MOVQ	16(DI), DX	// arg 3 timeout
476	MOVQ	0(DI), DI	// arg 1 cond
477	CALL	libc_pthread_cond_timedwait_relative_np(SB)
478	RET
479
480TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0
481	MOVQ	0(DI), DI	// arg 1 cond
482	CALL	libc_pthread_cond_signal(SB)
483	RET
484
485TEXT runtime·pthread_self_trampoline(SB),NOSPLIT,$0
486	MOVQ	DI, BX		// BX is caller-save
487	CALL	libc_pthread_self(SB)
488	MOVQ	AX, 0(BX)	// return value
489	RET
490
491TEXT runtime·pthread_kill_trampoline(SB),NOSPLIT,$0
492	MOVQ	8(DI), SI	// arg 2 sig
493	MOVQ	0(DI), DI	// arg 1 thread
494	CALL	libc_pthread_kill(SB)
495	RET
496
497TEXT runtime·osinit_hack_trampoline(SB),NOSPLIT,$0
498	MOVQ	$0, DI	// arg 1 val
499	CALL	libc_notify_is_valid_token(SB)
500	CALL	libc_xpc_date_create_from_current(SB)
501	RET
502
503// syscall calls a function in libc on behalf of the syscall package.
504// syscall takes a pointer to a struct like:
505// struct {
506//	fn    uintptr
507//	a1    uintptr
508//	a2    uintptr
509//	a3    uintptr
510//	r1    uintptr
511//	r2    uintptr
512//	err   uintptr
513// }
514// syscall must be called on the g0 stack with the
515// C calling convention (use libcCall).
516//
517// syscall expects a 32-bit result and tests for 32-bit -1
518// to decide there was an error.
519TEXT runtime·syscall(SB),NOSPLIT,$16
520	MOVQ	(0*8)(DI), CX // fn
521	MOVQ	(2*8)(DI), SI // a2
522	MOVQ	(3*8)(DI), DX // a3
523	MOVQ	DI, (SP)
524	MOVQ	(1*8)(DI), DI // a1
525	XORL	AX, AX	      // vararg: say "no float args"
526
527	CALL	CX
528
529	MOVQ	(SP), DI
530	MOVQ	AX, (4*8)(DI) // r1
531	MOVQ	DX, (5*8)(DI) // r2
532
533	// Standard libc functions return -1 on error
534	// and set errno.
535	CMPL	AX, $-1	      // Note: high 32 bits are junk
536	JNE	ok
537
538	// Get error code from libc.
539	CALL	libc_error(SB)
540	MOVLQSX	(AX), AX
541	MOVQ	(SP), DI
542	MOVQ	AX, (6*8)(DI) // err
543
544ok:
545	XORL	AX, AX        // no error (it's ignored anyway)
546	RET
547
548// syscallX calls a function in libc on behalf of the syscall package.
549// syscallX takes a pointer to a struct like:
550// struct {
551//	fn    uintptr
552//	a1    uintptr
553//	a2    uintptr
554//	a3    uintptr
555//	r1    uintptr
556//	r2    uintptr
557//	err   uintptr
558// }
559// syscallX must be called on the g0 stack with the
560// C calling convention (use libcCall).
561//
562// syscallX is like syscall but expects a 64-bit result
563// and tests for 64-bit -1 to decide there was an error.
564TEXT runtime·syscallX(SB),NOSPLIT,$16
565	MOVQ	(0*8)(DI), CX // fn
566	MOVQ	(2*8)(DI), SI // a2
567	MOVQ	(3*8)(DI), DX // a3
568	MOVQ	DI, (SP)
569	MOVQ	(1*8)(DI), DI // a1
570	XORL	AX, AX	      // vararg: say "no float args"
571
572	CALL	CX
573
574	MOVQ	(SP), DI
575	MOVQ	AX, (4*8)(DI) // r1
576	MOVQ	DX, (5*8)(DI) // r2
577
578	// Standard libc functions return -1 on error
579	// and set errno.
580	CMPQ	AX, $-1
581	JNE	ok
582
583	// Get error code from libc.
584	CALL	libc_error(SB)
585	MOVLQSX	(AX), AX
586	MOVQ	(SP), DI
587	MOVQ	AX, (6*8)(DI) // err
588
589ok:
590	XORL	AX, AX        // no error (it's ignored anyway)
591	RET
592
593// syscallPtr is like syscallX except that the libc function reports an
594// error by returning NULL and setting errno.
595TEXT runtime·syscallPtr(SB),NOSPLIT,$16
596	MOVQ	(0*8)(DI), CX // fn
597	MOVQ	(2*8)(DI), SI // a2
598	MOVQ	(3*8)(DI), DX // a3
599	MOVQ	DI, (SP)
600	MOVQ	(1*8)(DI), DI // a1
601	XORL	AX, AX	      // vararg: say "no float args"
602
603	CALL	CX
604
605	MOVQ	(SP), DI
606	MOVQ	AX, (4*8)(DI) // r1
607	MOVQ	DX, (5*8)(DI) // r2
608
609	// syscallPtr libc functions return NULL on error
610	// and set errno.
611	TESTQ	AX, AX
612	JNE	ok
613
614	// Get error code from libc.
615	CALL	libc_error(SB)
616	MOVLQSX	(AX), AX
617	MOVQ	(SP), DI
618	MOVQ	AX, (6*8)(DI) // err
619
620ok:
621	XORL	AX, AX        // no error (it's ignored anyway)
622	RET
623
624// syscall6 calls a function in libc on behalf of the syscall package.
625// syscall6 takes a pointer to a struct like:
626// struct {
627//	fn    uintptr
628//	a1    uintptr
629//	a2    uintptr
630//	a3    uintptr
631//	a4    uintptr
632//	a5    uintptr
633//	a6    uintptr
634//	r1    uintptr
635//	r2    uintptr
636//	err   uintptr
637// }
638// syscall6 must be called on the g0 stack with the
639// C calling convention (use libcCall).
640//
641// syscall6 expects a 32-bit result and tests for 32-bit -1
642// to decide there was an error.
643TEXT runtime·syscall6(SB),NOSPLIT,$16
644	MOVQ	(0*8)(DI), R11// fn
645	MOVQ	(2*8)(DI), SI // a2
646	MOVQ	(3*8)(DI), DX // a3
647	MOVQ	(4*8)(DI), CX // a4
648	MOVQ	(5*8)(DI), R8 // a5
649	MOVQ	(6*8)(DI), R9 // a6
650	MOVQ	DI, (SP)
651	MOVQ	(1*8)(DI), DI // a1
652	XORL	AX, AX	      // vararg: say "no float args"
653
654	CALL	R11
655
656	MOVQ	(SP), DI
657	MOVQ	AX, (7*8)(DI) // r1
658	MOVQ	DX, (8*8)(DI) // r2
659
660	CMPL	AX, $-1
661	JNE	ok
662
663	CALL	libc_error(SB)
664	MOVLQSX	(AX), AX
665	MOVQ	(SP), DI
666	MOVQ	AX, (9*8)(DI) // err
667
668ok:
669	XORL	AX, AX        // no error (it's ignored anyway)
670	RET
671
672// syscall6X calls a function in libc on behalf of the syscall package.
673// syscall6X takes a pointer to a struct like:
674// struct {
675//	fn    uintptr
676//	a1    uintptr
677//	a2    uintptr
678//	a3    uintptr
679//	a4    uintptr
680//	a5    uintptr
681//	a6    uintptr
682//	r1    uintptr
683//	r2    uintptr
684//	err   uintptr
685// }
686// syscall6X must be called on the g0 stack with the
687// C calling convention (use libcCall).
688//
689// syscall6X is like syscall6 but expects a 64-bit result
690// and tests for 64-bit -1 to decide there was an error.
691TEXT runtime·syscall6X(SB),NOSPLIT,$16
692	MOVQ	(0*8)(DI), R11// fn
693	MOVQ	(2*8)(DI), SI // a2
694	MOVQ	(3*8)(DI), DX // a3
695	MOVQ	(4*8)(DI), CX // a4
696	MOVQ	(5*8)(DI), R8 // a5
697	MOVQ	(6*8)(DI), R9 // a6
698	MOVQ	DI, (SP)
699	MOVQ	(1*8)(DI), DI // a1
700	XORL	AX, AX	      // vararg: say "no float args"
701
702	CALL	R11
703
704	MOVQ	(SP), DI
705	MOVQ	AX, (7*8)(DI) // r1
706	MOVQ	DX, (8*8)(DI) // r2
707
708	CMPQ	AX, $-1
709	JNE	ok
710
711	CALL	libc_error(SB)
712	MOVLQSX	(AX), AX
713	MOVQ	(SP), DI
714	MOVQ	AX, (9*8)(DI) // err
715
716ok:
717	XORL	AX, AX        // no error (it's ignored anyway)
718	RET
719
720// syscall9 calls a function in libc on behalf of the syscall package.
721// syscall9 takes a pointer to a struct like:
722// struct {
723//	fn    uintptr
724//	a1    uintptr
725//	a2    uintptr
726//	a3    uintptr
727//	a4    uintptr
728//	a5    uintptr
729//	a6    uintptr
730//	a7    uintptr
731//	a8    uintptr
732//	a9    uintptr
733//	r1    uintptr
734//	r2    uintptr
735//	err   uintptr
736// }
737// syscall9 must be called on the g0 stack with the
738// C calling convention (use libcCall).
739//
740// syscall9 expects a 32-bit result and tests for 32-bit -1
741// to decide there was an error.
742TEXT runtime·syscall9(SB),NOSPLIT,$16
743	MOVQ	(0*8)(DI), R13// fn
744	MOVQ	(2*8)(DI), SI // a2
745	MOVQ	(3*8)(DI), DX // a3
746	MOVQ	(4*8)(DI), CX // a4
747	MOVQ	(5*8)(DI), R8 // a5
748	MOVQ	(6*8)(DI), R9 // a6
749	MOVQ	(7*8)(DI), R10 // a7
750	MOVQ	(8*8)(DI), R11 // a8
751	MOVQ	(9*8)(DI), R12 // a9
752	MOVQ	DI, (SP)
753	MOVQ	(1*8)(DI), DI // a1
754	XORL	AX, AX	      // vararg: say "no float args"
755
756	CALL	R13
757
758	MOVQ	(SP), DI
759	MOVQ	AX, (10*8)(DI) // r1
760	MOVQ	DX, (11*8)(DI) // r2
761
762	CMPL	AX, $-1
763	JNE	ok
764
765	CALL	libc_error(SB)
766	MOVLQSX	(AX), AX
767	MOVQ	(SP), DI
768	MOVQ	AX, (12*8)(DI) // err
769
770ok:
771	XORL	AX, AX        // no error (it's ignored anyway)
772	RET
773
774// syscall_x509 is for crypto/x509. It is like syscall6 but does not check for errors,
775// takes 5 uintptrs and 1 float64, and only returns one value,
776// for use with standard C ABI functions.
777TEXT runtime·syscall_x509(SB),NOSPLIT,$16
778	MOVQ	(0*8)(DI), R11// fn
779	MOVQ	(2*8)(DI), SI // a2
780	MOVQ	(3*8)(DI), DX // a3
781	MOVQ	(4*8)(DI), CX // a4
782	MOVQ	(5*8)(DI), R8 // a5
783	MOVQ	(6*8)(DI), X0 // f1
784	MOVQ	DI, (SP)
785	MOVQ	(1*8)(DI), DI // a1
786	XORL	AX, AX	      // vararg: say "no float args"
787
788	CALL	R11
789
790	MOVQ	(SP), DI
791	MOVQ	AX, (7*8)(DI) // r1
792
793	XORL	AX, AX        // no error (it's ignored anyway)
794	RET
795
796TEXT runtime·issetugid_trampoline(SB),NOSPLIT,$0
797	CALL	libc_issetugid(SB)
798	RET
799
800// mach_vm_region_trampoline calls mach_vm_region from libc.
801TEXT runtime·mach_vm_region_trampoline(SB),NOSPLIT,$0
802	MOVQ	0(DI), SI // address
803	MOVQ	8(DI), DX // size
804	MOVL	16(DI), CX // flavor
805	MOVQ	24(DI), R8 // info
806	MOVQ	32(DI), R9 // count
807	MOVQ	40(DI), R10 // object_name
808	MOVQ	$libc_mach_task_self_(SB), DI
809	MOVL	0(DI), DI
810	CALL	libc_mach_vm_region(SB)
811	RET
812
813// proc_regionfilename_trampoline calls proc_regionfilename.
814TEXT runtime·proc_regionfilename_trampoline(SB),NOSPLIT,$0
815	MOVQ	8(DI), SI // address
816	MOVQ	16(DI), DX // buffer
817	MOVQ	24(DI), CX // buffer_size
818	MOVQ	0(DI), DI // pid
819	CALL	libc_proc_regionfilename(SB)
820	RET
821