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, OpenBSD.
6// System calls are implemented in libc/libpthread, this file
7// contains trampolines that convert from Go to C calling convention.
8// Some direct system call implementations currently remain.
9//
10
11#include "go_asm.h"
12#include "go_tls.h"
13#include "textflag.h"
14#include "cgo/abi_amd64.h"
15
16#define CLOCK_MONOTONIC	$3
17
18TEXT runtime·settls(SB),NOSPLIT,$0
19	// Nothing to do, pthread already set thread-local storage up.
20	RET
21
22// mstart_stub is the first function executed on a new thread started by pthread_create.
23// It just does some low-level setup and then calls mstart.
24// Note: called with the C calling convention.
25TEXT runtime·mstart_stub(SB),NOSPLIT,$0
26	// DI points to the m.
27	// We are already on m's g0 stack.
28
29	// Transition from C ABI to Go ABI.
30	PUSH_REGS_HOST_TO_ABI0()
31
32	// Load g and save to TLS entry.
33	// See cmd/link/internal/ld/sym.go:computeTLSOffset.
34	MOVQ	m_g0(DI), DX // g
35	MOVQ	DX, -8(FS)
36
37	CALL	runtime·mstart(SB)
38
39	POP_REGS_HOST_TO_ABI0()
40
41	// Go is all done with this OS thread.
42	// Tell pthread everything is ok (we never join with this thread, so
43	// the value here doesn't really matter).
44	XORL	AX, AX
45	RET
46
47TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
48	MOVQ	fn+0(FP),    AX
49	MOVL	sig+8(FP),   DI
50	MOVQ	info+16(FP), SI
51	MOVQ	ctx+24(FP),  DX
52	MOVQ	SP, BX		// callee-saved
53	ANDQ	$~15, SP	// alignment for x86_64 ABI
54	CALL	AX
55	MOVQ	BX, SP
56	RET
57
58// Called using C ABI.
59TEXT runtime·sigtramp(SB),NOSPLIT|TOPFRAME|NOFRAME,$0
60	// Transition from C ABI to Go ABI.
61	PUSH_REGS_HOST_TO_ABI0()
62
63	// Set up ABIInternal environment: g in R14, cleared X15.
64	get_tls(R12)
65	MOVQ	g(R12), R14
66	PXOR	X15, X15
67
68	// Reserve space for spill slots.
69	NOP	SP		// disable vet stack checking
70	ADJSP   $24
71
72	// Call into the Go signal handler
73	MOVQ	DI, AX	// sig
74	MOVQ	SI, BX	// info
75	MOVQ	DX, CX	// ctx
76	CALL	·sigtrampgo<ABIInternal>(SB)
77
78	ADJSP	$-24
79
80	POP_REGS_HOST_TO_ABI0()
81	RET
82
83//
84// These trampolines help convert from Go calling convention to C calling convention.
85// They should be called with asmcgocall.
86// A pointer to the arguments is passed in DI.
87// A single int32 result is returned in AX.
88// (For more results, make an args/results structure.)
89TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0
90	MOVQ	0(DI), DI		// arg 1 - attr
91	CALL	libc_pthread_attr_init(SB)
92	RET
93
94TEXT runtime·pthread_attr_destroy_trampoline(SB),NOSPLIT,$0
95	MOVQ	0(DI), DI		// arg 1 - attr
96	CALL	libc_pthread_attr_destroy(SB)
97	RET
98
99TEXT runtime·pthread_attr_getstacksize_trampoline(SB),NOSPLIT,$0
100	MOVQ	8(DI), SI		// arg 2 - stacksize
101	MOVQ	0(DI), DI		// arg 1 - attr
102	CALL	libc_pthread_attr_getstacksize(SB)
103	RET
104
105TEXT runtime·pthread_attr_setdetachstate_trampoline(SB),NOSPLIT,$0
106	MOVQ	8(DI), SI		// arg 2 - detachstate
107	MOVQ	0(DI), DI		// arg 1 - attr
108	CALL	libc_pthread_attr_setdetachstate(SB)
109	RET
110
111TEXT runtime·pthread_create_trampoline(SB),NOSPLIT,$16
112	MOVQ	0(DI), SI		// arg 2 - attr
113	MOVQ	8(DI), DX		// arg 3 - start
114	MOVQ	16(DI), CX		// arg 4 - arg
115	MOVQ	SP, DI			// arg 1 - &thread (discarded)
116	CALL	libc_pthread_create(SB)
117	RET
118
119TEXT runtime·thrkill_trampoline(SB),NOSPLIT,$0
120	MOVL	8(DI), SI		// arg 2 - signal
121	MOVQ	$0, DX			// arg 3 - tcb
122	MOVL	0(DI), DI		// arg 1 - tid
123	CALL	libc_thrkill(SB)
124	RET
125
126TEXT runtime·thrsleep_trampoline(SB),NOSPLIT,$0
127	MOVL	8(DI), SI		// arg 2 - clock_id
128	MOVQ	16(DI), DX		// arg 3 - abstime
129	MOVQ	24(DI), CX		// arg 4 - lock
130	MOVQ	32(DI), R8		// arg 5 - abort
131	MOVQ	0(DI), DI		// arg 1 - id
132	CALL	libc_thrsleep(SB)
133	RET
134
135TEXT runtime·thrwakeup_trampoline(SB),NOSPLIT,$0
136	MOVL	8(DI), SI		// arg 2 - count
137	MOVQ	0(DI), DI		// arg 1 - id
138	CALL	libc_thrwakeup(SB)
139	RET
140
141TEXT runtime·exit_trampoline(SB),NOSPLIT,$0
142	MOVL	0(DI), DI		// arg 1 exit status
143	CALL	libc_exit(SB)
144	MOVL	$0xf1, 0xf1  // crash
145	RET
146
147TEXT runtime·getthrid_trampoline(SB),NOSPLIT,$0
148	MOVQ	DI, BX			// BX is caller-save
149	CALL	libc_getthrid(SB)
150	MOVL	AX, 0(BX)		// return value
151	RET
152
153TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0
154	MOVL	0(DI), BX	// signal
155	CALL	libc_getpid(SB)
156	MOVL	AX, DI		// arg 1 pid
157	MOVL	BX, SI		// arg 2 signal
158	CALL	libc_kill(SB)
159	RET
160
161TEXT runtime·sched_yield_trampoline(SB),NOSPLIT,$0
162	CALL	libc_sched_yield(SB)
163	RET
164
165TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0
166	MOVQ	DI, BX
167	MOVQ	0(BX), DI		// arg 1 addr
168	MOVQ	8(BX), SI		// arg 2 len
169	MOVL	16(BX), DX		// arg 3 prot
170	MOVL	20(BX), CX		// arg 4 flags
171	MOVL	24(BX), R8		// arg 5 fid
172	MOVL	28(BX), R9		// arg 6 offset
173	CALL	libc_mmap(SB)
174	XORL	DX, DX
175	CMPQ	AX, $-1
176	JNE	ok
177	CALL	libc_errno(SB)
178	MOVLQSX	(AX), DX		// errno
179	XORQ	AX, AX
180ok:
181	MOVQ	AX, 32(BX)
182	MOVQ	DX, 40(BX)
183	RET
184
185TEXT runtime·munmap_trampoline(SB),NOSPLIT,$0
186	MOVQ	8(DI), SI		// arg 2 len
187	MOVQ	0(DI), DI		// arg 1 addr
188	CALL	libc_munmap(SB)
189	TESTQ	AX, AX
190	JEQ	2(PC)
191	MOVL	$0xf1, 0xf1  // crash
192	RET
193
194TEXT runtime·madvise_trampoline(SB), NOSPLIT, $0
195	MOVQ	8(DI), SI	// arg 2 len
196	MOVL	16(DI), DX	// arg 3 advice
197	MOVQ	0(DI), DI	// arg 1 addr
198	CALL	libc_madvise(SB)
199	// ignore failure - maybe pages are locked
200	RET
201
202TEXT runtime·open_trampoline(SB),NOSPLIT,$0
203	MOVL	8(DI), SI		// arg 2 - flags
204	MOVL	12(DI), DX		// arg 3 - mode
205	MOVQ	0(DI), DI		// arg 1 - path
206	XORL	AX, AX			// vararg: say "no float args"
207	CALL	libc_open(SB)
208	RET
209
210TEXT runtime·close_trampoline(SB),NOSPLIT,$0
211	MOVL	0(DI), DI		// arg 1 - fd
212	CALL	libc_close(SB)
213	RET
214
215TEXT runtime·read_trampoline(SB),NOSPLIT,$0
216	MOVQ	8(DI), SI		// arg 2 - buf
217	MOVL	16(DI), DX		// arg 3 - count
218	MOVL	0(DI), DI		// arg 1 - fd
219	CALL	libc_read(SB)
220	TESTL	AX, AX
221	JGE	noerr
222	CALL	libc_errno(SB)
223	MOVL	(AX), AX		// errno
224	NEGL	AX			// caller expects negative errno value
225noerr:
226	RET
227
228TEXT runtime·write_trampoline(SB),NOSPLIT,$0
229	MOVQ	8(DI), SI		// arg 2 buf
230	MOVL	16(DI), DX		// arg 3 count
231	MOVL	0(DI), DI		// arg 1 fd
232	CALL	libc_write(SB)
233	TESTL	AX, AX
234	JGE	noerr
235	CALL	libc_errno(SB)
236	MOVL	(AX), AX		// errno
237	NEGL	AX			// caller expects negative errno value
238noerr:
239	RET
240
241TEXT runtime·pipe2_trampoline(SB),NOSPLIT,$0
242	MOVL	8(DI), SI		// arg 2 flags
243	MOVQ	0(DI), DI		// arg 1 filedes
244	CALL	libc_pipe2(SB)
245	TESTL	AX, AX
246	JEQ	3(PC)
247	CALL	libc_errno(SB)
248	MOVL	(AX), AX		// errno
249	NEGL	AX			// caller expects negative errno value
250	RET
251
252TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0
253	MOVQ	8(DI), SI		// arg 2 new
254	MOVQ	16(DI), DX		// arg 3 old
255	MOVL	0(DI), DI		// arg 1 which
256	CALL	libc_setitimer(SB)
257	RET
258
259TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0
260	MOVL	0(DI), DI		// arg 1 usec
261	CALL	libc_usleep(SB)
262	RET
263
264TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0
265	MOVL	8(DI), SI		// arg 2 miblen
266	MOVQ	16(DI), DX		// arg 3 out
267	MOVQ	24(DI), CX		// arg 4 size
268	MOVQ	32(DI), R8		// arg 5 dst
269	MOVQ	40(DI), R9		// arg 6 ndst
270	MOVQ	0(DI), DI		// arg 1 mib
271	CALL	libc_sysctl(SB)
272	RET
273
274TEXT runtime·kqueue_trampoline(SB),NOSPLIT,$0
275	CALL	libc_kqueue(SB)
276	RET
277
278TEXT runtime·kevent_trampoline(SB),NOSPLIT,$0
279	MOVQ	8(DI), SI		// arg 2 keventt
280	MOVL	16(DI), DX		// arg 3 nch
281	MOVQ	24(DI), CX		// arg 4 ev
282	MOVL	32(DI), R8		// arg 5 nev
283	MOVQ	40(DI), R9		// arg 6 ts
284	MOVL	0(DI), DI		// arg 1 kq
285	CALL	libc_kevent(SB)
286	CMPL	AX, $-1
287	JNE	ok
288	CALL	libc_errno(SB)
289	MOVL	(AX), AX		// errno
290	NEGL	AX			// caller expects negative errno value
291ok:
292	RET
293
294TEXT runtime·clock_gettime_trampoline(SB),NOSPLIT,$0
295	MOVQ	8(DI), SI		// arg 2 tp
296	MOVL	0(DI), DI		// arg 1 clock_id
297	CALL	libc_clock_gettime(SB)
298	TESTL	AX, AX
299	JEQ	noerr
300	CALL	libc_errno(SB)
301	MOVL	(AX), AX		// errno
302	NEGL	AX			// caller expects negative errno value
303noerr:
304	RET
305
306TEXT runtime·fcntl_trampoline(SB),NOSPLIT,$0
307	MOVQ	DI, BX
308	MOVL	0(BX), DI		// arg 1 fd
309	MOVL	4(BX), SI		// arg 2 cmd
310	MOVL	8(BX), DX		// arg 3 arg
311	XORL	AX, AX			// vararg: say "no float args"
312	CALL	libc_fcntl(SB)
313	XORL	DX, DX
314	CMPL	AX, $-1
315	JNE	noerr
316	CALL	libc_errno(SB)
317	MOVL	(AX), DX
318	MOVL	$-1, AX
319noerr:
320	MOVL	AX, 12(BX)
321	MOVL	DX, 16(BX)
322	RET
323
324TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0
325	MOVQ	8(DI), SI		// arg 2 new
326	MOVQ	16(DI), DX		// arg 3 old
327	MOVL	0(DI), DI		// arg 1 sig
328	CALL	libc_sigaction(SB)
329	TESTL	AX, AX
330	JEQ	2(PC)
331	MOVL	$0xf1, 0xf1  // crash
332	RET
333
334TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
335	MOVQ	8(DI), SI	// arg 2 new
336	MOVQ	16(DI), DX	// arg 3 old
337	MOVL	0(DI), DI	// arg 1 how
338	CALL	libc_pthread_sigmask(SB)
339	TESTL	AX, AX
340	JEQ	2(PC)
341	MOVL	$0xf1, 0xf1  // crash
342	RET
343
344TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0
345	MOVQ	8(DI), SI		// arg 2 old
346	MOVQ	0(DI), DI		// arg 1 new
347	CALL	libc_sigaltstack(SB)
348	TESTQ	AX, AX
349	JEQ	2(PC)
350	MOVL	$0xf1, 0xf1  // crash
351	RET
352
353// syscall calls a function in libc on behalf of the syscall package.
354// syscall takes a pointer to a struct like:
355// struct {
356//	fn    uintptr
357//	a1    uintptr
358//	a2    uintptr
359//	a3    uintptr
360//	r1    uintptr
361//	r2    uintptr
362//	err   uintptr
363// }
364// syscall must be called on the g0 stack with the
365// C calling convention (use libcCall).
366//
367// syscall expects a 32-bit result and tests for 32-bit -1
368// to decide there was an error.
369TEXT runtime·syscall(SB),NOSPLIT,$16
370	MOVQ	(0*8)(DI), CX // fn
371	MOVQ	(2*8)(DI), SI // a2
372	MOVQ	(3*8)(DI), DX // a3
373	MOVQ	DI, (SP)
374	MOVQ	(1*8)(DI), DI // a1
375	XORL	AX, AX	      // vararg: say "no float args"
376
377	CALL	CX
378
379	MOVQ	(SP), DI
380	MOVQ	AX, (4*8)(DI) // r1
381	MOVQ	DX, (5*8)(DI) // r2
382
383	// Standard libc functions return -1 on error
384	// and set errno.
385	CMPL	AX, $-1	      // Note: high 32 bits are junk
386	JNE	ok
387
388	// Get error code from libc.
389	CALL	libc_errno(SB)
390	MOVLQSX	(AX), AX
391	MOVQ	(SP), DI
392	MOVQ	AX, (6*8)(DI) // err
393
394ok:
395	XORL	AX, AX        // no error (it's ignored anyway)
396	RET
397
398// syscallX calls a function in libc on behalf of the syscall package.
399// syscallX takes a pointer to a struct like:
400// struct {
401//	fn    uintptr
402//	a1    uintptr
403//	a2    uintptr
404//	a3    uintptr
405//	r1    uintptr
406//	r2    uintptr
407//	err   uintptr
408// }
409// syscallX must be called on the g0 stack with the
410// C calling convention (use libcCall).
411//
412// syscallX is like syscall but expects a 64-bit result
413// and tests for 64-bit -1 to decide there was an error.
414TEXT runtime·syscallX(SB),NOSPLIT,$16
415	MOVQ	(0*8)(DI), CX // fn
416	MOVQ	(2*8)(DI), SI // a2
417	MOVQ	(3*8)(DI), DX // a3
418	MOVQ	DI, (SP)
419	MOVQ	(1*8)(DI), DI // a1
420	XORL	AX, AX	      // vararg: say "no float args"
421
422	CALL	CX
423
424	MOVQ	(SP), DI
425	MOVQ	AX, (4*8)(DI) // r1
426	MOVQ	DX, (5*8)(DI) // r2
427
428	// Standard libc functions return -1 on error
429	// and set errno.
430	CMPQ	AX, $-1
431	JNE	ok
432
433	// Get error code from libc.
434	CALL	libc_errno(SB)
435	MOVLQSX	(AX), AX
436	MOVQ	(SP), DI
437	MOVQ	AX, (6*8)(DI) // err
438
439ok:
440	XORL	AX, AX        // no error (it's ignored anyway)
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//
460// syscall6 expects a 32-bit result and tests for 32-bit -1
461// to decide there was an error.
462TEXT runtime·syscall6(SB),NOSPLIT,$16
463	MOVQ	(0*8)(DI), R11// fn
464	MOVQ	(2*8)(DI), SI // a2
465	MOVQ	(3*8)(DI), DX // a3
466	MOVQ	(4*8)(DI), CX // a4
467	MOVQ	(5*8)(DI), R8 // a5
468	MOVQ	(6*8)(DI), R9 // a6
469	MOVQ	DI, (SP)
470	MOVQ	(1*8)(DI), DI // a1
471	XORL	AX, AX	      // vararg: say "no float args"
472
473	CALL	R11
474
475	MOVQ	(SP), DI
476	MOVQ	AX, (7*8)(DI) // r1
477	MOVQ	DX, (8*8)(DI) // r2
478
479	CMPL	AX, $-1
480	JNE	ok
481
482	CALL	libc_errno(SB)
483	MOVLQSX	(AX), AX
484	MOVQ	(SP), DI
485	MOVQ	AX, (9*8)(DI) // err
486
487ok:
488	XORL	AX, AX        // no error (it's ignored anyway)
489	RET
490
491// syscall6X calls a function in libc on behalf of the syscall package.
492// syscall6X takes a pointer to a struct like:
493// struct {
494//	fn    uintptr
495//	a1    uintptr
496//	a2    uintptr
497//	a3    uintptr
498//	a4    uintptr
499//	a5    uintptr
500//	a6    uintptr
501//	r1    uintptr
502//	r2    uintptr
503//	err   uintptr
504// }
505// syscall6X must be called on the g0 stack with the
506// C calling convention (use libcCall).
507//
508// syscall6X is like syscall6 but expects a 64-bit result
509// and tests for 64-bit -1 to decide there was an error.
510TEXT runtime·syscall6X(SB),NOSPLIT,$16
511	MOVQ	(0*8)(DI), R11// fn
512	MOVQ	(2*8)(DI), SI // a2
513	MOVQ	(3*8)(DI), DX // a3
514	MOVQ	(4*8)(DI), CX // a4
515	MOVQ	(5*8)(DI), R8 // a5
516	MOVQ	(6*8)(DI), R9 // a6
517	MOVQ	DI, (SP)
518	MOVQ	(1*8)(DI), DI // a1
519	XORL	AX, AX	      // vararg: say "no float args"
520
521	CALL	R11
522
523	MOVQ	(SP), DI
524	MOVQ	AX, (7*8)(DI) // r1
525	MOVQ	DX, (8*8)(DI) // r2
526
527	CMPQ	AX, $-1
528	JNE	ok
529
530	CALL	libc_errno(SB)
531	MOVLQSX	(AX), AX
532	MOVQ	(SP), DI
533	MOVQ	AX, (9*8)(DI) // err
534
535ok:
536	XORL	AX, AX        // no error (it's ignored anyway)
537	RET
538
539// syscall10 calls a function in libc on behalf of the syscall package.
540// syscall10 takes a pointer to a struct like:
541// struct {
542//	fn    uintptr
543//	a1    uintptr
544//	a2    uintptr
545//	a3    uintptr
546//	a4    uintptr
547//	a5    uintptr
548//	a6    uintptr
549//	a7    uintptr
550//	a8    uintptr
551//	a9    uintptr
552//	a10   uintptr
553//	r1    uintptr
554//	r2    uintptr
555//	err   uintptr
556// }
557// syscall10 must be called on the g0 stack with the
558// C calling convention (use libcCall).
559TEXT runtime·syscall10(SB),NOSPLIT,$48
560	// Arguments a1 to a6 get passed in registers, with a7 onwards being
561	// passed via the stack per the x86-64 System V ABI
562	// (https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf).
563	MOVQ	(7*8)(DI), R10	// a7
564	MOVQ	(8*8)(DI), R11	// a8
565	MOVQ	(9*8)(DI), R12	// a9
566	MOVQ	(10*8)(DI), R13	// a10
567	MOVQ	R10, (0*8)(SP)	// a7
568	MOVQ	R11, (1*8)(SP)	// a8
569	MOVQ	R12, (2*8)(SP)	// a9
570	MOVQ	R13, (3*8)(SP)	// a10
571	MOVQ	(0*8)(DI), R11	// fn
572	MOVQ	(2*8)(DI), SI	// a2
573	MOVQ	(3*8)(DI), DX	// a3
574	MOVQ	(4*8)(DI), CX	// a4
575	MOVQ	(5*8)(DI), R8	// a5
576	MOVQ	(6*8)(DI), R9	// a6
577	MOVQ	DI, (4*8)(SP)
578	MOVQ	(1*8)(DI), DI	// a1
579	XORL	AX, AX	     	// vararg: say "no float args"
580
581	CALL	R11
582
583	MOVQ	(4*8)(SP), DI
584	MOVQ	AX, (11*8)(DI) // r1
585	MOVQ	DX, (12*8)(DI) // r2
586
587	CMPL	AX, $-1
588	JNE	ok
589
590	CALL	libc_errno(SB)
591	MOVLQSX	(AX), AX
592	MOVQ	(4*8)(SP), DI
593	MOVQ	AX, (13*8)(DI) // err
594
595ok:
596	XORL	AX, AX        // no error (it's ignored anyway)
597	RET
598
599// syscall10X calls a function in libc on behalf of the syscall package.
600// syscall10X takes a pointer to a struct like:
601// struct {
602//	fn    uintptr
603//	a1    uintptr
604//	a2    uintptr
605//	a3    uintptr
606//	a4    uintptr
607//	a5    uintptr
608//	a6    uintptr
609//	a7    uintptr
610//	a8    uintptr
611//	a9    uintptr
612//	a10   uintptr
613//	r1    uintptr
614//	r2    uintptr
615//	err   uintptr
616// }
617// syscall10X must be called on the g0 stack with the
618// C calling convention (use libcCall).
619//
620// syscall10X is like syscall10 but expects a 64-bit result
621// and tests for 64-bit -1 to decide there was an error.
622TEXT runtime·syscall10X(SB),NOSPLIT,$48
623	// Arguments a1 to a6 get passed in registers, with a7 onwards being
624	// passed via the stack per the x86-64 System V ABI
625	// (https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf).
626	MOVQ	(7*8)(DI), R10	// a7
627	MOVQ	(8*8)(DI), R11	// a8
628	MOVQ	(9*8)(DI), R12	// a9
629	MOVQ	(10*8)(DI), R13	// a10
630	MOVQ	R10, (0*8)(SP)	// a7
631	MOVQ	R11, (1*8)(SP)	// a8
632	MOVQ	R12, (2*8)(SP)	// a9
633	MOVQ	R13, (3*8)(SP)	// a10
634	MOVQ	(0*8)(DI), R11	// fn
635	MOVQ	(2*8)(DI), SI	// a2
636	MOVQ	(3*8)(DI), DX	// a3
637	MOVQ	(4*8)(DI), CX	// a4
638	MOVQ	(5*8)(DI), R8	// a5
639	MOVQ	(6*8)(DI), R9	// a6
640	MOVQ	DI, (4*8)(SP)
641	MOVQ	(1*8)(DI), DI	// a1
642	XORL	AX, AX	     	// vararg: say "no float args"
643
644	CALL	R11
645
646	MOVQ	(4*8)(SP), DI
647	MOVQ	AX, (11*8)(DI) // r1
648	MOVQ	DX, (12*8)(DI) // r2
649
650	CMPQ	AX, $-1
651	JNE	ok
652
653	CALL	libc_errno(SB)
654	MOVLQSX	(AX), AX
655	MOVQ	(4*8)(SP), DI
656	MOVQ	AX, (13*8)(DI) // err
657
658ok:
659	XORL	AX, AX        // no error (it's ignored anyway)
660	RET
661
662TEXT runtime·issetugid_trampoline(SB),NOSPLIT,$0
663	MOVQ	DI, BX			// BX is caller-save
664	CALL	libc_issetugid(SB)
665	MOVL	AX, 0(BX)		// return value
666	RET
667