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