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