github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/src/runtime/asm_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  #include "go_asm.h"
     6  #include "go_tls.h"
     7  #include "tls_arm64.h"
     8  #include "funcdata.h"
     9  #include "textflag.h"
    10  
    11  TEXT runtime·rt0_go(SB),NOSPLIT,$0
    12  	// SP = stack; R0 = argc; R1 = argv
    13  
    14  	SUB	$32, RSP
    15  	MOVW	R0, 8(RSP) // argc
    16  	MOVD	R1, 16(RSP) // argv
    17  
    18  	// create istack out of the given (operating system) stack.
    19  	// _cgo_init may update stackguard.
    20  	MOVD	$runtime·g0(SB), g
    21  	MOVD RSP, R7
    22  	MOVD	$(-64*1024)(R7), R0
    23  	MOVD	R0, g_stackguard0(g)
    24  	MOVD	R0, g_stackguard1(g)
    25  	MOVD	R0, (g_stack+stack_lo)(g)
    26  	MOVD	R7, (g_stack+stack_hi)(g)
    27  
    28  	// if there is a _cgo_init, call it using the gcc ABI.
    29  	MOVD	_cgo_init(SB), R12
    30  	CMP	$0, R12
    31  	BEQ	nocgo
    32  
    33  	MRS_TPIDR_R0			// load TLS base pointer
    34  	MOVD	R0, R3			// arg 3: TLS base pointer
    35  #ifdef TLSG_IS_VARIABLE
    36  	MOVD	$runtime·tls_g(SB), R2 	// arg 2: &tls_g
    37  #else
    38  	MOVD	$0, R2		        // arg 2: not used when using platform's TLS
    39  #endif
    40  	MOVD	$setg_gcc<>(SB), R1	// arg 1: setg
    41  	MOVD	g, R0			// arg 0: G
    42  	BL	(R12)
    43  	MOVD	_cgo_init(SB), R12
    44  	CMP	$0, R12
    45  	BEQ	nocgo
    46  
    47  nocgo:
    48  	// update stackguard after _cgo_init
    49  	MOVD	(g_stack+stack_lo)(g), R0
    50  	ADD	$const__StackGuard, R0
    51  	MOVD	R0, g_stackguard0(g)
    52  	MOVD	R0, g_stackguard1(g)
    53  
    54  	// set the per-goroutine and per-mach "registers"
    55  	MOVD	$runtime·m0(SB), R0
    56  
    57  	// save m->g0 = g0
    58  	MOVD	g, m_g0(R0)
    59  	// save m0 to g0->m
    60  	MOVD	R0, g_m(g)
    61  
    62  	BL	runtime·check(SB)
    63  
    64  	MOVW	8(RSP), R0	// copy argc
    65  	MOVW	R0, -8(RSP)
    66  	MOVD	16(RSP), R0		// copy argv
    67  	MOVD	R0, 0(RSP)
    68  	BL	runtime·args(SB)
    69  	BL	runtime·osinit(SB)
    70  	BL	runtime·schedinit(SB)
    71  
    72  	// create a new goroutine to start program
    73  	MOVD	$runtime·mainPC(SB), R0		// entry
    74  	MOVD	RSP, R7
    75  	MOVD.W	$0, -8(R7)
    76  	MOVD.W	R0, -8(R7)
    77  	MOVD.W	$0, -8(R7)
    78  	MOVD.W	$0, -8(R7)
    79  	MOVD	R7, RSP
    80  	BL	runtime·newproc(SB)
    81  	ADD	$32, RSP
    82  
    83  	// start this M
    84  	BL	runtime·mstart(SB)
    85  
    86  	MOVD	$0, R0
    87  	MOVD	R0, (R0)	// boom
    88  	UNDEF
    89  
    90  DATA	runtime·mainPC+0(SB)/8,$runtime·main(SB)
    91  GLOBL	runtime·mainPC(SB),RODATA,$8
    92  
    93  TEXT runtime·breakpoint(SB),NOSPLIT,$-8-0
    94  	BRK
    95  	RET
    96  
    97  TEXT runtime·asminit(SB),NOSPLIT,$-8-0
    98  	RET
    99  
   100  /*
   101   *  go-routine
   102   */
   103  
   104  // void gosave(Gobuf*)
   105  // save state in Gobuf; setjmp
   106  TEXT runtime·gosave(SB), NOSPLIT, $-8-8
   107  	MOVD	buf+0(FP), R3
   108  	MOVD	RSP, R0
   109  	MOVD	R0, gobuf_sp(R3)
   110  	MOVD	LR, gobuf_pc(R3)
   111  	MOVD	g, gobuf_g(R3)
   112  	MOVD	ZR, gobuf_lr(R3)
   113  	MOVD	ZR, gobuf_ret(R3)
   114  	// Assert ctxt is zero. See func save.
   115  	MOVD	gobuf_ctxt(R3), R0
   116  	CMP	$0, R0
   117  	BEQ	2(PC)
   118  	CALL	runtime·badctxt(SB)
   119  	RET
   120  
   121  // void gogo(Gobuf*)
   122  // restore state from Gobuf; longjmp
   123  TEXT runtime·gogo(SB), NOSPLIT, $24-8
   124  	MOVD	buf+0(FP), R5
   125  
   126  	// If ctxt is not nil, invoke deletion barrier before overwriting.
   127  	MOVD	gobuf_ctxt(R5), R0
   128  	CMP	$0, R0
   129  	BEQ	nilctxt
   130  	MOVD	$gobuf_ctxt(R5), R0
   131  	MOVD	R0, 8(RSP)
   132  	MOVD	ZR, 16(RSP)
   133  	BL	runtime·writebarrierptr_prewrite(SB)
   134  	MOVD	buf+0(FP), R5
   135  
   136  nilctxt:
   137  	MOVD	gobuf_g(R5), g
   138  	BL	runtime·save_g(SB)
   139  
   140  	MOVD	0(g), R4	// make sure g is not nil
   141  	MOVD	gobuf_sp(R5), R0
   142  	MOVD	R0, RSP
   143  	MOVD	gobuf_lr(R5), LR
   144  	MOVD	gobuf_ret(R5), R0
   145  	MOVD	gobuf_ctxt(R5), R26
   146  	MOVD	$0, gobuf_sp(R5)
   147  	MOVD	$0, gobuf_ret(R5)
   148  	MOVD	$0, gobuf_lr(R5)
   149  	MOVD	$0, gobuf_ctxt(R5)
   150  	CMP	ZR, ZR // set condition codes for == test, needed by stack split
   151  	MOVD	gobuf_pc(R5), R6
   152  	B	(R6)
   153  
   154  // void mcall(fn func(*g))
   155  // Switch to m->g0's stack, call fn(g).
   156  // Fn must never return. It should gogo(&g->sched)
   157  // to keep running g.
   158  TEXT runtime·mcall(SB), NOSPLIT, $-8-8
   159  	// Save caller state in g->sched
   160  	MOVD	RSP, R0
   161  	MOVD	R0, (g_sched+gobuf_sp)(g)
   162  	MOVD	LR, (g_sched+gobuf_pc)(g)
   163  	MOVD	$0, (g_sched+gobuf_lr)(g)
   164  	MOVD	g, (g_sched+gobuf_g)(g)
   165  
   166  	// Switch to m->g0 & its stack, call fn.
   167  	MOVD	g, R3
   168  	MOVD	g_m(g), R8
   169  	MOVD	m_g0(R8), g
   170  	BL	runtime·save_g(SB)
   171  	CMP	g, R3
   172  	BNE	2(PC)
   173  	B	runtime·badmcall(SB)
   174  	MOVD	fn+0(FP), R26			// context
   175  	MOVD	0(R26), R4			// code pointer
   176  	MOVD	(g_sched+gobuf_sp)(g), R0
   177  	MOVD	R0, RSP	// sp = m->g0->sched.sp
   178  	MOVD	R3, -8(RSP)
   179  	MOVD	$0, -16(RSP)
   180  	SUB	$16, RSP
   181  	BL	(R4)
   182  	B	runtime·badmcall2(SB)
   183  
   184  // systemstack_switch is a dummy routine that systemstack leaves at the bottom
   185  // of the G stack. We need to distinguish the routine that
   186  // lives at the bottom of the G stack from the one that lives
   187  // at the top of the system stack because the one at the top of
   188  // the system stack terminates the stack walk (see topofstack()).
   189  TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0
   190  	UNDEF
   191  	BL	(LR)	// make sure this function is not leaf
   192  	RET
   193  
   194  // func systemstack(fn func())
   195  TEXT runtime·systemstack(SB), NOSPLIT, $0-8
   196  	MOVD	fn+0(FP), R3	// R3 = fn
   197  	MOVD	R3, R26		// context
   198  	MOVD	g_m(g), R4	// R4 = m
   199  
   200  	MOVD	m_gsignal(R4), R5	// R5 = gsignal
   201  	CMP	g, R5
   202  	BEQ	noswitch
   203  
   204  	MOVD	m_g0(R4), R5	// R5 = g0
   205  	CMP	g, R5
   206  	BEQ	noswitch
   207  
   208  	MOVD	m_curg(R4), R6
   209  	CMP	g, R6
   210  	BEQ	switch
   211  
   212  	// Bad: g is not gsignal, not g0, not curg. What is it?
   213  	// Hide call from linker nosplit analysis.
   214  	MOVD	$runtime·badsystemstack(SB), R3
   215  	BL	(R3)
   216  
   217  switch:
   218  	// save our state in g->sched. Pretend to
   219  	// be systemstack_switch if the G stack is scanned.
   220  	MOVD	$runtime·systemstack_switch(SB), R6
   221  	ADD	$8, R6	// get past prologue
   222  	MOVD	R6, (g_sched+gobuf_pc)(g)
   223  	MOVD	RSP, R0
   224  	MOVD	R0, (g_sched+gobuf_sp)(g)
   225  	MOVD	$0, (g_sched+gobuf_lr)(g)
   226  	MOVD	g, (g_sched+gobuf_g)(g)
   227  
   228  	// switch to g0
   229  	MOVD	R5, g
   230  	BL	runtime·save_g(SB)
   231  	MOVD	(g_sched+gobuf_sp)(g), R3
   232  	// make it look like mstart called systemstack on g0, to stop traceback
   233  	SUB	$16, R3
   234  	AND	$~15, R3
   235  	MOVD	$runtime·mstart(SB), R4
   236  	MOVD	R4, 0(R3)
   237  	MOVD	R3, RSP
   238  
   239  	// call target function
   240  	MOVD	0(R26), R3	// code pointer
   241  	BL	(R3)
   242  
   243  	// switch back to g
   244  	MOVD	g_m(g), R3
   245  	MOVD	m_curg(R3), g
   246  	BL	runtime·save_g(SB)
   247  	MOVD	(g_sched+gobuf_sp)(g), R0
   248  	MOVD	R0, RSP
   249  	MOVD	$0, (g_sched+gobuf_sp)(g)
   250  	RET
   251  
   252  noswitch:
   253  	// already on m stack, just call directly
   254  	MOVD	0(R26), R3	// code pointer
   255  	BL	(R3)
   256  	RET
   257  
   258  /*
   259   * support for morestack
   260   */
   261  
   262  // Called during function prolog when more stack is needed.
   263  // Caller has already loaded:
   264  // R3 prolog's LR (R30)
   265  //
   266  // The traceback routines see morestack on a g0 as being
   267  // the top of a stack (for example, morestack calling newstack
   268  // calling the scheduler calling newm calling gc), so we must
   269  // record an argument size. For that purpose, it has no arguments.
   270  TEXT runtime·morestack(SB),NOSPLIT,$-8-0
   271  	// Cannot grow scheduler stack (m->g0).
   272  	MOVD	g_m(g), R8
   273  	MOVD	m_g0(R8), R4
   274  	CMP	g, R4
   275  	BNE	3(PC)
   276  	BL	runtime·badmorestackg0(SB)
   277  	B	runtime·abort(SB)
   278  
   279  	// Cannot grow signal stack (m->gsignal).
   280  	MOVD	m_gsignal(R8), R4
   281  	CMP	g, R4
   282  	BNE	3(PC)
   283  	BL	runtime·badmorestackgsignal(SB)
   284  	B	runtime·abort(SB)
   285  
   286  	// Called from f.
   287  	// Set g->sched to context in f
   288  	MOVD	RSP, R0
   289  	MOVD	R0, (g_sched+gobuf_sp)(g)
   290  	MOVD	LR, (g_sched+gobuf_pc)(g)
   291  	MOVD	R3, (g_sched+gobuf_lr)(g)
   292  	// newstack will fill gobuf.ctxt.
   293  
   294  	// Called from f.
   295  	// Set m->morebuf to f's callers.
   296  	MOVD	R3, (m_morebuf+gobuf_pc)(R8)	// f's caller's PC
   297  	MOVD	RSP, R0
   298  	MOVD	R0, (m_morebuf+gobuf_sp)(R8)	// f's caller's RSP
   299  	MOVD	g, (m_morebuf+gobuf_g)(R8)
   300  
   301  	// Call newstack on m->g0's stack.
   302  	MOVD	m_g0(R8), g
   303  	BL	runtime·save_g(SB)
   304  	MOVD	(g_sched+gobuf_sp)(g), R0
   305  	MOVD	R0, RSP
   306  	MOVD.W	$0, -16(RSP)	// create a call frame on g0
   307  	MOVD	R26, 8(RSP)	// ctxt argument
   308  	BL	runtime·newstack(SB)
   309  
   310  	// Not reached, but make sure the return PC from the call to newstack
   311  	// is still in this function, and not the beginning of the next.
   312  	UNDEF
   313  
   314  TEXT runtime·morestack_noctxt(SB),NOSPLIT,$-4-0
   315  	MOVW	$0, R26
   316  	B runtime·morestack(SB)
   317  
   318  TEXT runtime·stackBarrier(SB),NOSPLIT,$0
   319  	// We came here via a RET to an overwritten LR.
   320  	// R0 may be live (see return0). Other registers are available.
   321  
   322  	// Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal.
   323  	MOVD	(g_stkbar+slice_array)(g), R4
   324  	MOVD	g_stkbarPos(g), R5
   325  	MOVD	$stkbar__size, R6
   326  	MUL	R5, R6
   327  	ADD	R4, R6
   328  	MOVD	stkbar_savedLRVal(R6), R6
   329  	// Record that this stack barrier was hit.
   330  	ADD	$1, R5
   331  	MOVD	R5, g_stkbarPos(g)
   332  	// Jump to the original return PC.
   333  	B	(R6)
   334  
   335  // reflectcall: call a function with the given argument list
   336  // func call(argtype *_type, f *FuncVal, arg *byte, argsize, retoffset uint32).
   337  // we don't have variable-sized frames, so we use a small number
   338  // of constant-sized-frame functions to encode a few bits of size in the pc.
   339  // Caution: ugly multiline assembly macros in your future!
   340  
   341  #define DISPATCH(NAME,MAXSIZE)		\
   342  	MOVD	$MAXSIZE, R27;		\
   343  	CMP	R27, R16;		\
   344  	BGT	3(PC);			\
   345  	MOVD	$NAME(SB), R27;	\
   346  	B	(R27)
   347  // Note: can't just "B NAME(SB)" - bad inlining results.
   348  
   349  TEXT reflect·call(SB), NOSPLIT, $0-0
   350  	B	·reflectcall(SB)
   351  
   352  TEXT ·reflectcall(SB), NOSPLIT, $-8-32
   353  	MOVWU argsize+24(FP), R16
   354  	DISPATCH(runtime·call32, 32)
   355  	DISPATCH(runtime·call64, 64)
   356  	DISPATCH(runtime·call128, 128)
   357  	DISPATCH(runtime·call256, 256)
   358  	DISPATCH(runtime·call512, 512)
   359  	DISPATCH(runtime·call1024, 1024)
   360  	DISPATCH(runtime·call2048, 2048)
   361  	DISPATCH(runtime·call4096, 4096)
   362  	DISPATCH(runtime·call8192, 8192)
   363  	DISPATCH(runtime·call16384, 16384)
   364  	DISPATCH(runtime·call32768, 32768)
   365  	DISPATCH(runtime·call65536, 65536)
   366  	DISPATCH(runtime·call131072, 131072)
   367  	DISPATCH(runtime·call262144, 262144)
   368  	DISPATCH(runtime·call524288, 524288)
   369  	DISPATCH(runtime·call1048576, 1048576)
   370  	DISPATCH(runtime·call2097152, 2097152)
   371  	DISPATCH(runtime·call4194304, 4194304)
   372  	DISPATCH(runtime·call8388608, 8388608)
   373  	DISPATCH(runtime·call16777216, 16777216)
   374  	DISPATCH(runtime·call33554432, 33554432)
   375  	DISPATCH(runtime·call67108864, 67108864)
   376  	DISPATCH(runtime·call134217728, 134217728)
   377  	DISPATCH(runtime·call268435456, 268435456)
   378  	DISPATCH(runtime·call536870912, 536870912)
   379  	DISPATCH(runtime·call1073741824, 1073741824)
   380  	MOVD	$runtime·badreflectcall(SB), R0
   381  	B	(R0)
   382  
   383  #define CALLFN(NAME,MAXSIZE)			\
   384  TEXT NAME(SB), WRAPPER, $MAXSIZE-24;		\
   385  	NO_LOCAL_POINTERS;			\
   386  	/* copy arguments to stack */		\
   387  	MOVD	arg+16(FP), R3;			\
   388  	MOVWU	argsize+24(FP), R4;			\
   389  	MOVD	RSP, R5;				\
   390  	ADD	$(8-1), R5;			\
   391  	SUB	$1, R3;				\
   392  	ADD	R5, R4;				\
   393  	CMP	R5, R4;				\
   394  	BEQ	4(PC);				\
   395  	MOVBU.W	1(R3), R6;			\
   396  	MOVBU.W	R6, 1(R5);			\
   397  	B	-4(PC);				\
   398  	/* call function */			\
   399  	MOVD	f+8(FP), R26;			\
   400  	MOVD	(R26), R0;			\
   401  	PCDATA  $PCDATA_StackMapIndex, $0;	\
   402  	BL	(R0);				\
   403  	/* copy return values back */		\
   404  	MOVD	argtype+0(FP), R7;		\
   405  	MOVD	arg+16(FP), R3;			\
   406  	MOVWU	n+24(FP), R4;			\
   407  	MOVWU	retoffset+28(FP), R6;		\
   408  	ADD	$8, RSP, R5;			\
   409  	ADD	R6, R5; 			\
   410  	ADD	R6, R3;				\
   411  	SUB	R6, R4;				\
   412  	BL	callRet<>(SB);			\
   413  	RET
   414  
   415  // callRet copies return values back at the end of call*. This is a
   416  // separate function so it can allocate stack space for the arguments
   417  // to reflectcallmove. It does not follow the Go ABI; it expects its
   418  // arguments in registers.
   419  TEXT callRet<>(SB), NOSPLIT, $40-0
   420  	MOVD	R7, 8(RSP)
   421  	MOVD	R3, 16(RSP)
   422  	MOVD	R5, 24(RSP)
   423  	MOVD	R4, 32(RSP)
   424  	BL	runtime·reflectcallmove(SB)
   425  	RET
   426  
   427  // These have 8 added to make the overall frame size a multiple of 16,
   428  // as required by the ABI. (There is another +8 for the saved LR.)
   429  CALLFN(·call32, 40 )
   430  CALLFN(·call64, 72 )
   431  CALLFN(·call128, 136 )
   432  CALLFN(·call256, 264 )
   433  CALLFN(·call512, 520 )
   434  CALLFN(·call1024, 1032 )
   435  CALLFN(·call2048, 2056 )
   436  CALLFN(·call4096, 4104 )
   437  CALLFN(·call8192, 8200 )
   438  CALLFN(·call16384, 16392 )
   439  CALLFN(·call32768, 32776 )
   440  CALLFN(·call65536, 65544 )
   441  CALLFN(·call131072, 131080 )
   442  CALLFN(·call262144, 262152 )
   443  CALLFN(·call524288, 524296 )
   444  CALLFN(·call1048576, 1048584 )
   445  CALLFN(·call2097152, 2097160 )
   446  CALLFN(·call4194304, 4194312 )
   447  CALLFN(·call8388608, 8388616 )
   448  CALLFN(·call16777216, 16777224 )
   449  CALLFN(·call33554432, 33554440 )
   450  CALLFN(·call67108864, 67108872 )
   451  CALLFN(·call134217728, 134217736 )
   452  CALLFN(·call268435456, 268435464 )
   453  CALLFN(·call536870912, 536870920 )
   454  CALLFN(·call1073741824, 1073741832 )
   455  
   456  // AES hashing not implemented for ARM64, issue #10109.
   457  TEXT runtime·aeshash(SB),NOSPLIT,$-8-0
   458  	MOVW	$0, R0
   459  	MOVW	(R0), R1
   460  TEXT runtime·aeshash32(SB),NOSPLIT,$-8-0
   461  	MOVW	$0, R0
   462  	MOVW	(R0), R1
   463  TEXT runtime·aeshash64(SB),NOSPLIT,$-8-0
   464  	MOVW	$0, R0
   465  	MOVW	(R0), R1
   466  TEXT runtime·aeshashstr(SB),NOSPLIT,$-8-0
   467  	MOVW	$0, R0
   468  	MOVW	(R0), R1
   469  	
   470  TEXT runtime·procyield(SB),NOSPLIT,$0-0
   471  	MOVWU	cycles+0(FP), R0
   472  again:
   473  	YIELD
   474  	SUBW	$1, R0
   475  	CBNZ	R0, again
   476  	RET
   477  
   478  // void jmpdefer(fv, sp);
   479  // called from deferreturn.
   480  // 1. grab stored LR for caller
   481  // 2. sub 4 bytes to get back to BL deferreturn
   482  // 3. BR to fn
   483  TEXT runtime·jmpdefer(SB), NOSPLIT, $-8-16
   484  	MOVD	0(RSP), R0
   485  	SUB	$4, R0
   486  	MOVD	R0, LR
   487  
   488  	MOVD	fv+0(FP), R26
   489  	MOVD	argp+8(FP), R0
   490  	MOVD	R0, RSP
   491  	SUB	$8, RSP
   492  	MOVD	0(R26), R3
   493  	B	(R3)
   494  
   495  // Save state of caller into g->sched. Smashes R0.
   496  TEXT gosave<>(SB),NOSPLIT,$-8
   497  	MOVD	LR, (g_sched+gobuf_pc)(g)
   498  	MOVD RSP, R0
   499  	MOVD	R0, (g_sched+gobuf_sp)(g)
   500  	MOVD	$0, (g_sched+gobuf_lr)(g)
   501  	MOVD	$0, (g_sched+gobuf_ret)(g)
   502  	// Assert ctxt is zero. See func save.
   503  	MOVD	(g_sched+gobuf_ctxt)(g), R0
   504  	CMP	$0, R0
   505  	BEQ	2(PC)
   506  	CALL	runtime·badctxt(SB)
   507  	RET
   508  
   509  // func asmcgocall(fn, arg unsafe.Pointer) int32
   510  // Call fn(arg) on the scheduler stack,
   511  // aligned appropriately for the gcc ABI.
   512  // See cgocall.go for more details.
   513  TEXT ·asmcgocall(SB),NOSPLIT,$0-20
   514  	MOVD	fn+0(FP), R1
   515  	MOVD	arg+8(FP), R0
   516  
   517  	MOVD	RSP, R2		// save original stack pointer
   518  	MOVD	g, R4
   519  
   520  	// Figure out if we need to switch to m->g0 stack.
   521  	// We get called to create new OS threads too, and those
   522  	// come in on the m->g0 stack already.
   523  	MOVD	g_m(g), R8
   524  	MOVD	m_g0(R8), R3
   525  	CMP	R3, g
   526  	BEQ	g0
   527  	MOVD	R0, R9	// gosave<> and save_g might clobber R0
   528  	BL	gosave<>(SB)
   529  	MOVD	R3, g
   530  	BL	runtime·save_g(SB)
   531  	MOVD	(g_sched+gobuf_sp)(g), R0
   532  	MOVD	R0, RSP
   533  	MOVD	R9, R0
   534  
   535  	// Now on a scheduling stack (a pthread-created stack).
   536  g0:
   537  	// Save room for two of our pointers /*, plus 32 bytes of callee
   538  	// save area that lives on the caller stack. */
   539  	MOVD	RSP, R13
   540  	SUB	$16, R13
   541  	MOVD	R13, RSP
   542  	MOVD	R4, 0(RSP)	// save old g on stack
   543  	MOVD	(g_stack+stack_hi)(R4), R4
   544  	SUB	R2, R4
   545  	MOVD	R4, 8(RSP)	// save depth in old g stack (can't just save SP, as stack might be copied during a callback)
   546  	BL	(R1)
   547  	MOVD	R0, R9
   548  
   549  	// Restore g, stack pointer. R0 is errno, so don't touch it
   550  	MOVD	0(RSP), g
   551  	BL	runtime·save_g(SB)
   552  	MOVD	(g_stack+stack_hi)(g), R5
   553  	MOVD	8(RSP), R6
   554  	SUB	R6, R5
   555  	MOVD	R9, R0
   556  	MOVD	R5, RSP
   557  
   558  	MOVW	R0, ret+16(FP)
   559  	RET
   560  
   561  // cgocallback(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt)
   562  // Turn the fn into a Go func (by taking its address) and call
   563  // cgocallback_gofunc.
   564  TEXT runtime·cgocallback(SB),NOSPLIT,$40-32
   565  	MOVD	$fn+0(FP), R0
   566  	MOVD	R0, 8(RSP)
   567  	MOVD	frame+8(FP), R0
   568  	MOVD	R0, 16(RSP)
   569  	MOVD	framesize+16(FP), R0
   570  	MOVD	R0, 24(RSP)
   571  	MOVD	ctxt+24(FP), R0
   572  	MOVD	R0, 32(RSP)
   573  	MOVD	$runtime·cgocallback_gofunc(SB), R0
   574  	BL	(R0)
   575  	RET
   576  
   577  // cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize, uintptr ctxt)
   578  // See cgocall.go for more details.
   579  TEXT ·cgocallback_gofunc(SB),NOSPLIT,$24-32
   580  	NO_LOCAL_POINTERS
   581  
   582  	// Load g from thread-local storage.
   583  	MOVB	runtime·iscgo(SB), R3
   584  	CMP	$0, R3
   585  	BEQ	nocgo
   586  	BL	runtime·load_g(SB)
   587  nocgo:
   588  
   589  	// If g is nil, Go did not create the current thread.
   590  	// Call needm to obtain one for temporary use.
   591  	// In this case, we're running on the thread stack, so there's
   592  	// lots of space, but the linker doesn't know. Hide the call from
   593  	// the linker analysis by using an indirect call.
   594  	CMP	$0, g
   595  	BEQ	needm
   596  
   597  	MOVD	g_m(g), R8
   598  	MOVD	R8, savedm-8(SP)
   599  	B	havem
   600  
   601  needm:
   602  	MOVD	g, savedm-8(SP) // g is zero, so is m.
   603  	MOVD	$runtime·needm(SB), R0
   604  	BL	(R0)
   605  
   606  	// Set m->sched.sp = SP, so that if a panic happens
   607  	// during the function we are about to execute, it will
   608  	// have a valid SP to run on the g0 stack.
   609  	// The next few lines (after the havem label)
   610  	// will save this SP onto the stack and then write
   611  	// the same SP back to m->sched.sp. That seems redundant,
   612  	// but if an unrecovered panic happens, unwindm will
   613  	// restore the g->sched.sp from the stack location
   614  	// and then systemstack will try to use it. If we don't set it here,
   615  	// that restored SP will be uninitialized (typically 0) and
   616  	// will not be usable.
   617  	MOVD	g_m(g), R8
   618  	MOVD	m_g0(R8), R3
   619  	MOVD	RSP, R0
   620  	MOVD	R0, (g_sched+gobuf_sp)(R3)
   621  
   622  havem:
   623  	// Now there's a valid m, and we're running on its m->g0.
   624  	// Save current m->g0->sched.sp on stack and then set it to SP.
   625  	// Save current sp in m->g0->sched.sp in preparation for
   626  	// switch back to m->curg stack.
   627  	// NOTE: unwindm knows that the saved g->sched.sp is at 16(RSP) aka savedsp-16(SP).
   628  	// Beware that the frame size is actually 32.
   629  	MOVD	m_g0(R8), R3
   630  	MOVD	(g_sched+gobuf_sp)(R3), R4
   631  	MOVD	R4, savedsp-16(SP)
   632  	MOVD	RSP, R0
   633  	MOVD	R0, (g_sched+gobuf_sp)(R3)
   634  
   635  	// Switch to m->curg stack and call runtime.cgocallbackg.
   636  	// Because we are taking over the execution of m->curg
   637  	// but *not* resuming what had been running, we need to
   638  	// save that information (m->curg->sched) so we can restore it.
   639  	// We can restore m->curg->sched.sp easily, because calling
   640  	// runtime.cgocallbackg leaves SP unchanged upon return.
   641  	// To save m->curg->sched.pc, we push it onto the stack.
   642  	// This has the added benefit that it looks to the traceback
   643  	// routine like cgocallbackg is going to return to that
   644  	// PC (because the frame we allocate below has the same
   645  	// size as cgocallback_gofunc's frame declared above)
   646  	// so that the traceback will seamlessly trace back into
   647  	// the earlier calls.
   648  	//
   649  	// In the new goroutine, -8(SP) is unused (where SP refers to
   650  	// m->curg's SP while we're setting it up, before we've adjusted it).
   651  	MOVD	m_curg(R8), g
   652  	BL	runtime·save_g(SB)
   653  	MOVD	(g_sched+gobuf_sp)(g), R4 // prepare stack as R4
   654  	MOVD	(g_sched+gobuf_pc)(g), R5
   655  	MOVD	R5, -(24+8)(R4)
   656  	MOVD	ctxt+24(FP), R0
   657  	MOVD	R0, -(16+8)(R4)
   658  	MOVD	$-(24+8)(R4), R0 // maintain 16-byte SP alignment
   659  	MOVD	R0, RSP
   660  	BL	runtime·cgocallbackg(SB)
   661  
   662  	// Restore g->sched (== m->curg->sched) from saved values.
   663  	MOVD	0(RSP), R5
   664  	MOVD	R5, (g_sched+gobuf_pc)(g)
   665  	MOVD	RSP, R4
   666  	ADD	$(24+8), R4, R4
   667  	MOVD	R4, (g_sched+gobuf_sp)(g)
   668  
   669  	// Switch back to m->g0's stack and restore m->g0->sched.sp.
   670  	// (Unlike m->curg, the g0 goroutine never uses sched.pc,
   671  	// so we do not have to restore it.)
   672  	MOVD	g_m(g), R8
   673  	MOVD	m_g0(R8), g
   674  	BL	runtime·save_g(SB)
   675  	MOVD	(g_sched+gobuf_sp)(g), R0
   676  	MOVD	R0, RSP
   677  	MOVD	savedsp-16(SP), R4
   678  	MOVD	R4, (g_sched+gobuf_sp)(g)
   679  
   680  	// If the m on entry was nil, we called needm above to borrow an m
   681  	// for the duration of the call. Since the call is over, return it with dropm.
   682  	MOVD	savedm-8(SP), R6
   683  	CMP	$0, R6
   684  	BNE	droppedm
   685  	MOVD	$runtime·dropm(SB), R0
   686  	BL	(R0)
   687  droppedm:
   688  
   689  	// Done!
   690  	RET
   691  
   692  // Called from cgo wrappers, this function returns g->m->curg.stack.hi.
   693  // Must obey the gcc calling convention.
   694  TEXT _cgo_topofstack(SB),NOSPLIT,$24
   695  	// g (R28) and REGTMP (R27)  might be clobbered by load_g. They
   696  	// are callee-save in the gcc calling convention, so save them.
   697  	MOVD	R27, savedR27-8(SP)
   698  	MOVD	g, saveG-16(SP)
   699  
   700  	BL	runtime·load_g(SB)
   701  	MOVD	g_m(g), R0
   702  	MOVD	m_curg(R0), R0
   703  	MOVD	(g_stack+stack_hi)(R0), R0
   704  
   705  	MOVD	saveG-16(SP), g
   706  	MOVD	savedR28-8(SP), R27
   707  	RET
   708  
   709  // void setg(G*); set g. for use by needm.
   710  TEXT runtime·setg(SB), NOSPLIT, $0-8
   711  	MOVD	gg+0(FP), g
   712  	// This only happens if iscgo, so jump straight to save_g
   713  	BL	runtime·save_g(SB)
   714  	RET
   715  
   716  // void setg_gcc(G*); set g called from gcc
   717  TEXT setg_gcc<>(SB),NOSPLIT,$8
   718  	MOVD	R0, g
   719  	MOVD	R27, savedR27-8(SP)
   720  	BL	runtime·save_g(SB)
   721  	MOVD	savedR27-8(SP), R27
   722  	RET
   723  
   724  TEXT runtime·getcallerpc(SB),NOSPLIT,$8-16
   725  	MOVD	16(RSP), R0		// LR saved by caller
   726  	MOVD	runtime·stackBarrierPC(SB), R1
   727  	CMP	R0, R1
   728  	BNE	nobar
   729  	// Get original return PC.
   730  	BL	runtime·nextBarrierPC(SB)
   731  	MOVD	8(RSP), R0
   732  nobar:
   733  	MOVD	R0, ret+8(FP)
   734  	RET
   735  
   736  TEXT runtime·setcallerpc(SB),NOSPLIT,$8-16
   737  	MOVD	pc+8(FP), R0
   738  	MOVD	16(RSP), R1
   739  	MOVD	runtime·stackBarrierPC(SB), R2
   740  	CMP	R1, R2
   741  	BEQ	setbar
   742  	MOVD	R0, 16(RSP)		// set LR in caller
   743  	RET
   744  setbar:
   745  	// Set the stack barrier return PC.
   746  	MOVD	R0, 8(RSP)
   747  	BL	runtime·setNextBarrierPC(SB)
   748  	RET
   749  
   750  TEXT runtime·abort(SB),NOSPLIT,$-8-0
   751  	B	(ZR)
   752  	UNDEF
   753  
   754  // memhash_varlen(p unsafe.Pointer, h seed) uintptr
   755  // redirects to memhash(p, h, size) using the size
   756  // stored in the closure.
   757  TEXT runtime·memhash_varlen(SB),NOSPLIT,$40-24
   758  	GO_ARGS
   759  	NO_LOCAL_POINTERS
   760  	MOVD	p+0(FP), R3
   761  	MOVD	h+8(FP), R4
   762  	MOVD	8(R26), R5
   763  	MOVD	R3, 8(RSP)
   764  	MOVD	R4, 16(RSP)
   765  	MOVD	R5, 24(RSP)
   766  	BL	runtime·memhash(SB)
   767  	MOVD	32(RSP), R3
   768  	MOVD	R3, ret+16(FP)
   769  	RET
   770  
   771  // memequal(p, q unsafe.Pointer, size uintptr) bool
   772  TEXT runtime·memequal(SB),NOSPLIT,$-8-25
   773  	MOVD	a+0(FP), R1
   774  	MOVD	b+8(FP), R2
   775  	MOVD	size+16(FP), R3
   776  	ADD	R1, R3, R6
   777  	MOVD	$1, R0
   778  	MOVB	R0, ret+24(FP)
   779  	CMP	R1, R2
   780  	BEQ	done
   781  loop:
   782  	CMP	R1, R6
   783  	BEQ	done
   784  	MOVBU.P	1(R1), R4
   785  	MOVBU.P	1(R2), R5
   786  	CMP	R4, R5
   787  	BEQ	loop
   788  
   789  	MOVB	$0, ret+24(FP)
   790  done:
   791  	RET
   792  
   793  // memequal_varlen(a, b unsafe.Pointer) bool
   794  TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17
   795  	MOVD	a+0(FP), R3
   796  	MOVD	b+8(FP), R4
   797  	CMP	R3, R4
   798  	BEQ	eq
   799  	MOVD	8(R26), R5    // compiler stores size at offset 8 in the closure
   800  	MOVD	R3, 8(RSP)
   801  	MOVD	R4, 16(RSP)
   802  	MOVD	R5, 24(RSP)
   803  	BL	runtime·memequal(SB)
   804  	MOVBU	32(RSP), R3
   805  	MOVB	R3, ret+16(FP)
   806  	RET
   807  eq:
   808  	MOVD	$1, R3
   809  	MOVB	R3, ret+16(FP)
   810  	RET
   811  
   812  TEXT runtime·cmpstring(SB),NOSPLIT,$-4-40
   813  	MOVD	s1_base+0(FP), R2
   814  	MOVD	s1_len+8(FP), R0
   815  	MOVD	s2_base+16(FP), R3
   816  	MOVD	s2_len+24(FP), R1
   817  	ADD	$40, RSP, R7
   818  	B	runtime·cmpbody<>(SB)
   819  
   820  TEXT bytes·Compare(SB),NOSPLIT,$-4-56
   821  	MOVD	s1+0(FP), R2
   822  	MOVD	s1+8(FP), R0
   823  	MOVD	s2+24(FP), R3
   824  	MOVD	s2+32(FP), R1
   825  	ADD	$56, RSP, R7
   826  	B	runtime·cmpbody<>(SB)
   827  
   828  // On entry:
   829  // R0 is the length of s1
   830  // R1 is the length of s2
   831  // R2 points to the start of s1
   832  // R3 points to the start of s2
   833  // R7 points to return value (-1/0/1 will be written here)
   834  //
   835  // On exit:
   836  // R4, R5, and R6 are clobbered
   837  TEXT runtime·cmpbody<>(SB),NOSPLIT,$-4-0
   838  	CMP	R2, R3
   839  	BEQ	samebytes // same starting pointers; compare lengths
   840  	CMP	R0, R1
   841  	CSEL    LT, R1, R0, R6 // R6 is min(R0, R1)
   842  
   843  	ADD	R2, R6	// R2 is current byte in s1, R6 is last byte in s1 to compare
   844  loop:
   845  	CMP	R2, R6
   846  	BEQ	samebytes // all compared bytes were the same; compare lengths
   847  	MOVBU.P	1(R2), R4
   848  	MOVBU.P	1(R3), R5
   849  	CMP	R4, R5
   850  	BEQ	loop
   851  	// bytes differed
   852  	MOVD	$1, R4
   853  	CSNEG	LT, R4, R4, R4
   854  	MOVD	R4, (R7)
   855  	RET
   856  samebytes:
   857  	MOVD	$1, R4
   858  	CMP	R0, R1
   859  	CSNEG	LT, R4, R4, R4
   860  	CSEL	EQ, ZR, R4, R4
   861  	MOVD	R4, (R7)
   862  	RET
   863  
   864  // eqstring tests whether two strings are equal.
   865  // The compiler guarantees that strings passed
   866  // to eqstring have equal length.
   867  // See runtime_test.go:eqstring_generic for
   868  // equivalent Go code.
   869  TEXT runtime·eqstring(SB),NOSPLIT,$0-33
   870  	MOVD	s1_base+0(FP), R0
   871  	MOVD	s1_len+8(FP), R1
   872  	MOVD	s2_base+16(FP), R2
   873  	ADD	R0, R1		// end
   874  loop:
   875  	CMP	R0, R1
   876  	BEQ	equal		// reaches the end
   877  	MOVBU.P	1(R0), R4
   878  	MOVBU.P	1(R2), R5
   879  	CMP	R4, R5
   880  	BEQ	loop
   881  notequal:
   882  	MOVB	ZR, ret+32(FP)
   883  	RET
   884  equal:
   885  	MOVD	$1, R0
   886  	MOVB	R0, ret+32(FP)
   887  	RET
   888  
   889  //
   890  // functions for other packages
   891  //
   892  TEXT bytes·IndexByte(SB),NOSPLIT,$0-40
   893  	MOVD	b+0(FP), R0
   894  	MOVD	b_len+8(FP), R1
   895  	MOVBU	c+24(FP), R2	// byte to find
   896  	MOVD	R0, R4		// store base for later
   897  	ADD	R0, R1		// end
   898  loop:
   899  	CMP	R0, R1
   900  	BEQ	notfound
   901  	MOVBU.P	1(R0), R3
   902  	CMP	R2, R3
   903  	BNE	loop
   904  
   905  	SUB	$1, R0		// R0 will be one beyond the position we want
   906  	SUB	R4, R0		// remove base
   907  	MOVD	R0, ret+32(FP)
   908  	RET
   909  
   910  notfound:
   911  	MOVD	$-1, R0
   912  	MOVD	R0, ret+32(FP)
   913  	RET
   914  
   915  TEXT strings·IndexByte(SB),NOSPLIT,$0-32
   916  	MOVD	s+0(FP), R0
   917  	MOVD	s_len+8(FP), R1
   918  	MOVBU	c+16(FP), R2	// byte to find
   919  	MOVD	R0, R4		// store base for later
   920  	ADD	R0, R1		// end
   921  loop:
   922  	CMP	R0, R1
   923  	BEQ	notfound
   924  	MOVBU.P	1(R0), R3
   925  	CMP	R2, R3
   926  	BNE	loop
   927  
   928  	SUB	$1, R0		// R0 will be one beyond the position we want
   929  	SUB	R4, R0		// remove base
   930  	MOVD	R0, ret+24(FP)
   931  	RET
   932  
   933  notfound:
   934  	MOVD	$-1, R0
   935  	MOVD	R0, ret+24(FP)
   936  	RET
   937  
   938  // TODO: share code with memequal?
   939  TEXT bytes·Equal(SB),NOSPLIT,$0-49
   940  	MOVD	a_len+8(FP), R1
   941  	MOVD	b_len+32(FP), R3
   942  	CMP	R1, R3		// unequal lengths are not equal
   943  	BNE	notequal
   944  	MOVD	a+0(FP), R0
   945  	MOVD	b+24(FP), R2
   946  	ADD	R0, R1		// end
   947  loop:
   948  	CMP	R0, R1
   949  	BEQ	equal		// reaches the end
   950  	MOVBU.P	1(R0), R4
   951  	MOVBU.P	1(R2), R5
   952  	CMP	R4, R5
   953  	BEQ	loop
   954  notequal:
   955  	MOVB	ZR, ret+48(FP)
   956  	RET
   957  equal:
   958  	MOVD	$1, R0
   959  	MOVB	R0, ret+48(FP)
   960  	RET
   961  
   962  TEXT runtime·fastrand(SB),NOSPLIT,$-8-4
   963  	MOVD	g_m(g), R1
   964  	MOVWU	m_fastrand(R1), R0
   965  	ADD	R0, R0
   966  	CMPW	$0, R0
   967  	BGE	notneg
   968  	EOR	$0x88888eef, R0
   969  notneg:
   970  	MOVW	R0, m_fastrand(R1)
   971  	MOVW	R0, ret+0(FP)
   972  	RET
   973  
   974  TEXT runtime·return0(SB), NOSPLIT, $0
   975  	MOVW	$0, R0
   976  	RET
   977  
   978  // The top-most function running on a goroutine
   979  // returns to goexit+PCQuantum.
   980  TEXT runtime·goexit(SB),NOSPLIT,$-8-0
   981  	MOVD	R0, R0	// NOP
   982  	BL	runtime·goexit1(SB)	// does not return
   983  
   984  // TODO(aram): use PRFM here.
   985  TEXT runtime·prefetcht0(SB),NOSPLIT,$0-8
   986  	RET
   987  
   988  TEXT runtime·prefetcht1(SB),NOSPLIT,$0-8
   989  	RET
   990  
   991  TEXT runtime·prefetcht2(SB),NOSPLIT,$0-8
   992  	RET
   993  
   994  TEXT runtime·prefetchnta(SB),NOSPLIT,$0-8
   995  	RET
   996  
   997  TEXT runtime·sigreturn(SB),NOSPLIT,$0-0
   998  	RET
   999  
  1000  // This is called from .init_array and follows the platform, not Go, ABI.
  1001  TEXT runtime·addmoduledata(SB),NOSPLIT,$0-0
  1002  	SUB	$0x10, RSP
  1003  	MOVD	R27, 8(RSP) // The access to global variables below implicitly uses R27, which is callee-save
  1004  	MOVD	runtime·lastmoduledatap(SB), R1
  1005  	MOVD	R0, moduledata_next(R1)
  1006  	MOVD	R0, runtime·lastmoduledatap(SB)
  1007  	MOVD	8(RSP), R27
  1008  	ADD	$0x10, RSP
  1009  	RET
  1010  
  1011  TEXT ·checkASM(SB),NOSPLIT,$0-1
  1012  	MOVW	$1, R3
  1013  	MOVB	R3, ret+0(FP)
  1014  	RET