github.com/s1s1ty/go@v0.0.0-20180207192209-104445e3140f/src/runtime/sys_darwin_386.s (about)

     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 386, Darwin
     6  // See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
     7  // or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
     8  
     9  #include "go_asm.h"
    10  #include "go_tls.h"
    11  #include "textflag.h"
    12  
    13  // Exit the entire program (like C exit)
    14  TEXT runtime·exit(SB),NOSPLIT,$0
    15  	MOVL	$1, AX
    16  	INT	$0x80
    17  	MOVL	$0xf1, 0xf1  // crash
    18  	RET
    19  
    20  // Exit this OS thread (like pthread_exit, which eventually
    21  // calls __bsdthread_terminate).
    22  TEXT exit1<>(SB),NOSPLIT,$16-0
    23  	// __bsdthread_terminate takes 4 word-size arguments.
    24  	// Set them all to 0. (None are an exit status.)
    25  	MOVL	$0, 0(SP)
    26  	MOVL	$0, 4(SP)
    27  	MOVL	$0, 8(SP)
    28  	MOVL	$0, 12(SP)
    29  	MOVL	$361, AX
    30  	INT	$0x80
    31  	JAE 2(PC)
    32  	MOVL	$0xf1, 0xf1  // crash
    33  	RET
    34  
    35  GLOBL exitStack<>(SB),RODATA,$(4*4)
    36  DATA exitStack<>+0x00(SB)/4, $0
    37  DATA exitStack<>+0x04(SB)/4, $0
    38  DATA exitStack<>+0x08(SB)/4, $0
    39  DATA exitStack<>+0x0c(SB)/4, $0
    40  
    41  // func exitThread(wait *uint32)
    42  TEXT runtime·exitThread(SB),NOSPLIT,$0-4
    43  	MOVL	wait+0(FP), AX
    44  	// We're done using the stack.
    45  	MOVL	$0, (AX)
    46  	// __bsdthread_terminate takes 4 arguments, which it expects
    47  	// on the stack. They should all be 0, so switch over to a
    48  	// fake stack of 0s. It won't write to the stack.
    49  	MOVL	$exitStack<>(SB), SP
    50  	MOVL	$361, AX	// __bsdthread_terminate
    51  	INT	$0x80
    52  	MOVL	$0xf1, 0xf1  // crash
    53  	JMP	0(PC)
    54  
    55  TEXT runtime·open(SB),NOSPLIT,$0
    56  	MOVL	$5, AX
    57  	INT	$0x80
    58  	JAE	2(PC)
    59  	MOVL	$-1, AX
    60  	MOVL	AX, ret+12(FP)
    61  	RET
    62  
    63  TEXT runtime·closefd(SB),NOSPLIT,$0
    64  	MOVL	$6, AX
    65  	INT	$0x80
    66  	JAE	2(PC)
    67  	MOVL	$-1, AX
    68  	MOVL	AX, ret+4(FP)
    69  	RET
    70  
    71  TEXT runtime·read(SB),NOSPLIT,$0
    72  	MOVL	$3, AX
    73  	INT	$0x80
    74  	JAE	2(PC)
    75  	MOVL	$-1, AX
    76  	MOVL	AX, ret+12(FP)
    77  	RET
    78  
    79  TEXT runtime·write(SB),NOSPLIT,$0
    80  	MOVL	$4, AX
    81  	INT	$0x80
    82  	JAE	2(PC)
    83  	MOVL	$-1, AX
    84  	MOVL	AX, ret+12(FP)
    85  	RET
    86  
    87  TEXT runtime·raise(SB),NOSPLIT,$0
    88  	// Ideally we'd send the signal to the current thread,
    89  	// not the whole process, but that's too hard on OS X.
    90  	JMP	runtime·raiseproc(SB)
    91  
    92  TEXT runtime·raiseproc(SB),NOSPLIT,$16
    93  	MOVL	$20, AX // getpid
    94  	INT	$0x80
    95  	MOVL	AX, 4(SP)	// pid
    96  	MOVL	sig+0(FP), AX
    97  	MOVL	AX, 8(SP)	// signal
    98  	MOVL	$1, 12(SP)	// posix
    99  	MOVL	$37, AX // kill
   100  	INT	$0x80
   101  	RET
   102  
   103  TEXT runtime·mmap(SB),NOSPLIT,$0
   104  	MOVL	$197, AX
   105  	INT	$0x80
   106  	JAE	ok
   107  	MOVL	$0, p+24(FP)
   108  	MOVL	AX, err+28(FP)
   109  	RET
   110  ok:
   111  	MOVL	AX, p+24(FP)
   112  	MOVL	$0, err+28(FP)
   113  	RET
   114  
   115  TEXT runtime·madvise(SB),NOSPLIT,$0
   116  	MOVL	$75, AX
   117  	INT	$0x80
   118  	// ignore failure - maybe pages are locked
   119  	RET
   120  
   121  TEXT runtime·munmap(SB),NOSPLIT,$0
   122  	MOVL	$73, AX
   123  	INT	$0x80
   124  	JAE	2(PC)
   125  	MOVL	$0xf1, 0xf1  // crash
   126  	RET
   127  
   128  TEXT runtime·setitimer(SB),NOSPLIT,$0
   129  	MOVL	$83, AX
   130  	INT	$0x80
   131  	RET
   132  
   133  // OS X comm page time offsets
   134  // http://www.opensource.apple.com/source/xnu/xnu-1699.26.8/osfmk/i386/cpu_capabilities.h
   135  #define	cpu_capabilities	0x20
   136  #define	nt_tsc_base	0x50
   137  #define	nt_scale	0x58
   138  #define	nt_shift	0x5c
   139  #define	nt_ns_base	0x60
   140  #define	nt_generation	0x68
   141  #define	gtod_generation	0x6c
   142  #define	gtod_ns_base	0x70
   143  #define	gtod_sec_base	0x78
   144  
   145  // called from assembly
   146  // 64-bit unix nanoseconds returned in DX:AX.
   147  // I'd much rather write this in C but we need
   148  // assembly for the 96-bit multiply and RDTSC.
   149  //
   150  // Note that we could arrange to return monotonic time here
   151  // as well, but we don't bother, for two reasons:
   152  // 1. macOS only supports 64-bit systems, so no one should
   153  // be using the 32-bit code in production.
   154  // This code is only maintained to make it easier for developers
   155  // using Macs to test the 32-bit compiler.
   156  // 2. On some (probably now unsupported) CPUs,
   157  // the code falls back to the system call always,
   158  // so it can't even use the comm page at all. 
   159  TEXT runtime·now(SB),NOSPLIT,$40
   160  	MOVL	$0xffff0000, BP /* comm page base */
   161  	
   162  	// Test for slow CPU. If so, the math is completely
   163  	// different, and unimplemented here, so use the
   164  	// system call.
   165  	MOVL	cpu_capabilities(BP), AX
   166  	TESTL	$0x4000, AX
   167  	JNZ	systime
   168  
   169  	// Loop trying to take a consistent snapshot
   170  	// of the time parameters.
   171  timeloop:
   172  	MOVL	gtod_generation(BP), BX
   173  	TESTL	BX, BX
   174  	JZ	systime
   175  	MOVL	nt_generation(BP), CX
   176  	TESTL	CX, CX
   177  	JZ	timeloop
   178  	RDTSC
   179  	MOVL	nt_tsc_base(BP), SI
   180  	MOVL	(nt_tsc_base+4)(BP), DI
   181  	MOVL	SI, 0(SP)
   182  	MOVL	DI, 4(SP)
   183  	MOVL	nt_scale(BP), SI
   184  	MOVL	SI, 8(SP)
   185  	MOVL	nt_ns_base(BP), SI
   186  	MOVL	(nt_ns_base+4)(BP), DI
   187  	MOVL	SI, 12(SP)
   188  	MOVL	DI, 16(SP)
   189  	CMPL	nt_generation(BP), CX
   190  	JNE	timeloop
   191  	MOVL	gtod_ns_base(BP), SI
   192  	MOVL	(gtod_ns_base+4)(BP), DI
   193  	MOVL	SI, 20(SP)
   194  	MOVL	DI, 24(SP)
   195  	MOVL	gtod_sec_base(BP), SI
   196  	MOVL	(gtod_sec_base+4)(BP), DI
   197  	MOVL	SI, 28(SP)
   198  	MOVL	DI, 32(SP)
   199  	CMPL	gtod_generation(BP), BX
   200  	JNE	timeloop
   201  
   202  	// Gathered all the data we need. Compute time.
   203  	//	((tsc - nt_tsc_base) * nt_scale) >> 32 + nt_ns_base - gtod_ns_base + gtod_sec_base*1e9
   204  	// The multiply and shift extracts the top 64 bits of the 96-bit product.
   205  	SUBL	0(SP), AX // DX:AX = (tsc - nt_tsc_base)
   206  	SBBL	4(SP), DX
   207  
   208  	// We have x = tsc - nt_tsc_base - DX:AX to be
   209  	// multiplied by y = nt_scale = 8(SP), keeping the top 64 bits of the 96-bit product.
   210  	// x*y = (x&0xffffffff)*y + (x&0xffffffff00000000)*y
   211  	// (x*y)>>32 = ((x&0xffffffff)*y)>>32 + (x>>32)*y
   212  	MOVL	DX, CX // SI = (x&0xffffffff)*y >> 32
   213  	MOVL	$0, DX
   214  	MULL	8(SP)
   215  	MOVL	DX, SI
   216  
   217  	MOVL	CX, AX // DX:AX = (x>>32)*y
   218  	MOVL	$0, DX
   219  	MULL	8(SP)
   220  
   221  	ADDL	SI, AX	// DX:AX += (x&0xffffffff)*y >> 32
   222  	ADCL	$0, DX
   223  	
   224  	// DX:AX is now ((tsc - nt_tsc_base) * nt_scale) >> 32.
   225  	ADDL	12(SP), AX	// DX:AX += nt_ns_base
   226  	ADCL	16(SP), DX
   227  	SUBL	20(SP), AX	// DX:AX -= gtod_ns_base
   228  	SBBL	24(SP), DX
   229  	MOVL	AX, SI	// DI:SI = DX:AX
   230  	MOVL	DX, DI
   231  	MOVL	28(SP), AX	// DX:AX = gtod_sec_base*1e9
   232  	MOVL	32(SP), DX
   233  	MOVL	$1000000000, CX
   234  	MULL	CX
   235  	ADDL	SI, AX	// DX:AX += DI:SI
   236  	ADCL	DI, DX
   237  	RET
   238  
   239  systime:
   240  	// Fall back to system call (usually first call in this thread)
   241  	LEAL	16(SP), AX	// must be non-nil, unused
   242  	MOVL	AX, 4(SP)
   243  	MOVL	$0, 8(SP)	// time zone pointer
   244  	MOVL	$0, 12(SP)	// required as of Sierra; Issue 16570
   245  	MOVL	$116, AX // SYS_GETTIMEOFDAY
   246  	INT	$0x80
   247  	CMPL	AX, $0
   248  	JNE	inreg
   249  	MOVL	16(SP), AX
   250  	MOVL	20(SP), DX
   251  inreg:
   252  	// sec is in AX, usec in DX
   253  	// convert to DX:AX nsec
   254  	MOVL	DX, BX
   255  	MOVL	$1000000000, CX
   256  	MULL	CX
   257  	IMULL	$1000, BX
   258  	ADDL	BX, AX
   259  	ADCL	$0, DX
   260  	RET
   261  
   262  // func now() (sec int64, nsec int32, mono uint64)
   263  TEXT time·now(SB),NOSPLIT,$0-20
   264  	CALL	runtime·now(SB)
   265  	MOVL	AX, BX
   266  	MOVL	DX, BP
   267  	SUBL	runtime·startNano(SB), BX
   268  	SBBL	runtime·startNano+4(SB), BP
   269  	MOVL	BX, mono+12(FP)
   270  	MOVL	BP, mono+16(FP)
   271  	MOVL	$1000000000, CX
   272  	DIVL	CX
   273  	MOVL	AX, sec+0(FP)
   274  	MOVL	$0, sec+4(FP)
   275  	MOVL	DX, nsec+8(FP)
   276  	RET
   277  
   278  // func nanotime() int64
   279  TEXT runtime·nanotime(SB),NOSPLIT,$0
   280  	CALL	runtime·now(SB)
   281  	SUBL	runtime·startNano(SB), AX
   282  	SBBL	runtime·startNano+4(SB), DX
   283  	MOVL	AX, ret_lo+0(FP)
   284  	MOVL	DX, ret_hi+4(FP)
   285  	RET
   286  
   287  TEXT runtime·sigprocmask(SB),NOSPLIT,$0
   288  	MOVL	$329, AX  // pthread_sigmask (on OS X, sigprocmask==entire process)
   289  	INT	$0x80
   290  	JAE	2(PC)
   291  	MOVL	$0xf1, 0xf1  // crash
   292  	RET
   293  
   294  TEXT runtime·sigaction(SB),NOSPLIT,$0
   295  	MOVL	$46, AX
   296  	INT	$0x80
   297  	JAE	2(PC)
   298  	MOVL	$0xf1, 0xf1  // crash
   299  	RET
   300  
   301  TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
   302  	MOVL	fn+0(FP), AX
   303  	MOVL	sig+4(FP), BX
   304  	MOVL	info+8(FP), CX
   305  	MOVL	ctx+12(FP), DX
   306  	MOVL	SP, SI
   307  	SUBL	$32, SP
   308  	ANDL	$~15, SP	// align stack: handler might be a C function
   309  	MOVL	BX, 0(SP)
   310  	MOVL	CX, 4(SP)
   311  	MOVL	DX, 8(SP)
   312  	MOVL	SI, 12(SP)	// save SI: handler might be a Go function
   313  	CALL	AX
   314  	MOVL	12(SP), AX
   315  	MOVL	AX, SP
   316  	RET
   317  
   318  // Sigtramp's job is to call the actual signal handler.
   319  // It is called with the following arguments on the stack:
   320  //	0(SP)	"return address" - ignored
   321  //	4(SP)	actual handler
   322  //	8(SP)	siginfo style
   323  //	12(SP)	signal number
   324  //	16(SP)	siginfo
   325  //	20(SP)	context
   326  TEXT runtime·sigtramp(SB),NOSPLIT,$20
   327  	MOVL	sig+8(FP), BX
   328  	MOVL	BX, 0(SP)
   329  	MOVL	info+12(FP), BX
   330  	MOVL	BX, 4(SP)
   331  	MOVL	ctx+16(FP), BX
   332  	MOVL	BX, 8(SP)
   333  	CALL	runtime·sigtrampgo(SB)
   334  
   335  	// call sigreturn
   336  	MOVL	ctx+16(FP), CX
   337  	MOVL	infostyle+4(FP), BX
   338  	MOVL	$0, 0(SP)	// "caller PC" - ignored
   339  	MOVL	CX, 4(SP)
   340  	MOVL	BX, 8(SP)
   341  	MOVL	$184, AX	// sigreturn(ucontext, infostyle)
   342  	INT	$0x80
   343  	MOVL	$0xf1, 0xf1  // crash
   344  	RET
   345  
   346  TEXT runtime·sigaltstack(SB),NOSPLIT,$0
   347  	MOVL	$53, AX
   348  	INT	$0x80
   349  	JAE	2(PC)
   350  	MOVL	$0xf1, 0xf1  // crash
   351  	RET
   352  
   353  TEXT runtime·usleep(SB),NOSPLIT,$32
   354  	MOVL	$0, DX
   355  	MOVL	usec+0(FP), AX
   356  	MOVL	$1000000, CX
   357  	DIVL	CX
   358  	MOVL	AX, 24(SP)  // sec
   359  	MOVL	DX, 28(SP)  // usec
   360  
   361  	// select(0, 0, 0, 0, &tv)
   362  	MOVL	$0, 0(SP)  // "return PC" - ignored
   363  	MOVL	$0, 4(SP)
   364  	MOVL	$0, 8(SP)
   365  	MOVL	$0, 12(SP)
   366  	MOVL	$0, 16(SP)
   367  	LEAL	24(SP), AX
   368  	MOVL	AX, 20(SP)
   369  	MOVL	$93, AX
   370  	INT	$0x80
   371  	RET
   372  
   373  // func bsdthread_create(stk, arg unsafe.Pointer, fn uintptr) int32
   374  // System call args are: func arg stack pthread flags.
   375  TEXT runtime·bsdthread_create(SB),NOSPLIT,$32
   376  	MOVL	$360, AX
   377  	// 0(SP) is where the caller PC would be; kernel skips it
   378  	MOVL	fn+8(FP), BX
   379  	MOVL	BX, 4(SP)	// func
   380  	MOVL	arg+4(FP), BX
   381  	MOVL	BX, 8(SP)	// arg
   382  	MOVL	stk+0(FP), BX
   383  	MOVL	BX, 12(SP)	// stack
   384  	MOVL    $0, 16(SP)      // pthread
   385  	MOVL	$0x1000000, 20(SP)	// flags = PTHREAD_START_CUSTOM
   386  	INT	$0x80
   387  	JAE	4(PC)
   388  	NEGL	AX
   389  	MOVL	AX, ret+12(FP)
   390  	RET
   391  	MOVL	$0, AX
   392  	MOVL	AX, ret+12(FP)
   393  	RET
   394  
   395  // The thread that bsdthread_create creates starts executing here,
   396  // because we registered this function using bsdthread_register
   397  // at startup.
   398  //	AX = "pthread" (= 0x0)
   399  //	BX = mach thread port
   400  //	CX = "func" (= fn)
   401  //	DX = "arg" (= m)
   402  //	DI = stack top
   403  //	SI = flags (= 0x1000000)
   404  //	SP = stack - C_32_STK_ALIGN
   405  TEXT runtime·bsdthread_start(SB),NOSPLIT,$0
   406  	// set up ldt 7+id to point at m->tls.
   407  	LEAL	m_tls(DX), BP
   408  	MOVL	m_id(DX), DI
   409  	ADDL	$7, DI	// m0 is LDT#7. count up.
   410  	// setldt(tls#, &tls, sizeof tls)
   411  	PUSHAL	// save registers
   412  	PUSHL	$32	// sizeof tls
   413  	PUSHL	BP	// &tls
   414  	PUSHL	DI	// tls #
   415  	CALL	runtime·setldt(SB)
   416  	POPL	AX
   417  	POPL	AX
   418  	POPL	AX
   419  	POPAL
   420  
   421  	// Now segment is established. Initialize m, g.
   422  	get_tls(BP)
   423  	MOVL    m_g0(DX), AX
   424  	MOVL	AX, g(BP)
   425  	MOVL	DX, g_m(AX)
   426  	MOVL	BX, m_procid(DX)	// m->procid = thread port (for debuggers)
   427  	CALL	runtime·stackcheck(SB)		// smashes AX
   428  	CALL	CX	// fn()
   429  	CALL	exit1<>(SB)
   430  	RET
   431  
   432  // func bsdthread_register() int32
   433  // registers callbacks for threadstart (see bsdthread_create above
   434  // and wqthread and pthsize (not used).  returns 0 on success.
   435  TEXT runtime·bsdthread_register(SB),NOSPLIT,$40
   436  	MOVL	$366, AX
   437  	// 0(SP) is where kernel expects caller PC; ignored
   438  	MOVL	$runtime·bsdthread_start(SB), 4(SP)	// threadstart
   439  	MOVL	$0, 8(SP)	// wqthread, not used by us
   440  	MOVL	$0, 12(SP)	// pthsize, not used by us
   441  	MOVL	$0, 16(SP)	// dummy_value [sic]
   442  	MOVL	$0, 20(SP)	// targetconc_ptr
   443  	MOVL	$0, 24(SP)	// dispatchqueue_offset
   444  	INT	$0x80
   445  	JAE	4(PC)
   446  	NEGL	AX
   447  	MOVL	AX, ret+0(FP)
   448  	RET
   449  	MOVL	$0, AX
   450  	MOVL	AX, ret+0(FP)
   451  	RET
   452  
   453  // Invoke Mach system call.
   454  // Assumes system call number in AX,
   455  // caller PC on stack, caller's caller PC next,
   456  // and then the system call arguments.
   457  //
   458  // Can be used for BSD too, but we don't,
   459  // because if you use this interface the BSD
   460  // system call numbers need an extra field
   461  // in the high 16 bits that seems to be the
   462  // argument count in bytes but is not always.
   463  // INT $0x80 works fine for those.
   464  TEXT runtime·sysenter(SB),NOSPLIT,$0
   465  	POPL	DX
   466  	MOVL	SP, CX
   467  	BYTE $0x0F; BYTE $0x34;  // SYSENTER
   468  	// returns to DX with SP set to CX
   469  
   470  TEXT runtime·mach_msg_trap(SB),NOSPLIT,$0
   471  	MOVL	$-31, AX
   472  	CALL	runtime·sysenter(SB)
   473  	MOVL	AX, ret+28(FP)
   474  	RET
   475  
   476  TEXT runtime·mach_reply_port(SB),NOSPLIT,$0
   477  	MOVL	$-26, AX
   478  	CALL	runtime·sysenter(SB)
   479  	MOVL	AX, ret+0(FP)
   480  	RET
   481  
   482  TEXT runtime·mach_task_self(SB),NOSPLIT,$0
   483  	MOVL	$-28, AX
   484  	CALL	runtime·sysenter(SB)
   485  	MOVL	AX, ret+0(FP)
   486  	RET
   487  
   488  // Mach provides trap versions of the semaphore ops,
   489  // instead of requiring the use of RPC.
   490  
   491  // func mach_semaphore_wait(sema uint32) int32
   492  TEXT runtime·mach_semaphore_wait(SB),NOSPLIT,$0
   493  	MOVL	$-36, AX
   494  	CALL	runtime·sysenter(SB)
   495  	MOVL	AX, ret+4(FP)
   496  	RET
   497  
   498  // func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
   499  TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0
   500  	MOVL	$-38, AX
   501  	CALL	runtime·sysenter(SB)
   502  	MOVL	AX, ret+12(FP)
   503  	RET
   504  
   505  // func mach_semaphore_signal(sema uint32) int32
   506  TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0
   507  	MOVL	$-33, AX
   508  	CALL	runtime·sysenter(SB)
   509  	MOVL	AX, ret+4(FP)
   510  	RET
   511  
   512  // func mach_semaphore_signal_all(sema uint32) int32
   513  TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0
   514  	MOVL	$-34, AX
   515  	CALL	runtime·sysenter(SB)
   516  	MOVL	AX, ret+4(FP)
   517  	RET
   518  
   519  // func setldt(entry int, address int, limit int)
   520  // entry and limit are ignored.
   521  TEXT runtime·setldt(SB),NOSPLIT,$32
   522  	MOVL	address+4(FP), BX	// aka base
   523  
   524  	/*
   525  	 * When linking against the system libraries,
   526  	 * we use its pthread_create and let it set up %gs
   527  	 * for us.  When we do that, the private storage
   528  	 * we get is not at 0(GS) but at 0x468(GS).
   529  	 * 8l rewrites 0(TLS) into 0x468(GS) for us.
   530  	 * To accommodate that rewrite, we translate the
   531  	 * address and limit here so that 0x468(GS) maps to 0(address).
   532  	 *
   533  	 * See cgo/gcc_darwin_386.c:/468 for the derivation
   534  	 * of the constant.
   535  	 */
   536  	SUBL	$0x468, BX
   537  
   538  	/*
   539  	 * Must set up as USER_CTHREAD segment because
   540  	 * Darwin forces that value into %gs for signal handlers,
   541  	 * and if we don't set one up, we'll get a recursive
   542  	 * fault trying to get into the signal handler.
   543  	 * Since we have to set one up anyway, it might as
   544  	 * well be the value we want.  So don't bother with
   545  	 * i386_set_ldt.
   546  	 */
   547  	MOVL	BX, 4(SP)
   548  	MOVL	$3, AX	// thread_fast_set_cthread_self - machdep call #3
   549  	INT	$0x82	// sic: 0x82, not 0x80, for machdep call
   550  
   551  	XORL	AX, AX
   552  	MOVW	GS, AX
   553  	RET
   554  
   555  TEXT runtime·sysctl(SB),NOSPLIT,$0
   556  	MOVL	$202, AX
   557  	INT	$0x80
   558  	JAE	4(PC)
   559  	NEGL	AX
   560  	MOVL	AX, ret+24(FP)
   561  	RET
   562  	MOVL	$0, AX
   563  	MOVL	AX, ret+24(FP)
   564  	RET
   565  
   566  // func kqueue() int32
   567  TEXT runtime·kqueue(SB),NOSPLIT,$0
   568  	MOVL	$362, AX
   569  	INT	$0x80
   570  	JAE	2(PC)
   571  	NEGL	AX
   572  	MOVL	AX, ret+0(FP)
   573  	RET
   574  
   575  // func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
   576  TEXT runtime·kevent(SB),NOSPLIT,$0
   577  	MOVL	$363, AX
   578  	INT	$0x80
   579  	JAE	2(PC)
   580  	NEGL	AX
   581  	MOVL	AX, ret+24(FP)
   582  	RET
   583  
   584  // func closeonexec(fd int32)
   585  TEXT runtime·closeonexec(SB),NOSPLIT,$32
   586  	MOVL	$92, AX  // fcntl
   587  	// 0(SP) is where the caller PC would be; kernel skips it
   588  	MOVL	fd+0(FP), BX
   589  	MOVL	BX, 4(SP)  // fd
   590  	MOVL	$2, 8(SP)  // F_SETFD
   591  	MOVL	$1, 12(SP)  // FD_CLOEXEC
   592  	INT	$0x80
   593  	JAE	2(PC)
   594  	NEGL	AX
   595  	RET