github.com/fjballest/golang@v0.0.0-20151209143359-e4c5fe594ca8/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  // armPublicationBarrier is a native store/store barrier for ARMv7+.
   699  // On earlier ARM revisions, armPublicationBarrier is a no-op.
   700  // This will not work on SMP ARMv6 machines, if any are in use.
   701  // To implement publiationBarrier in sys_$GOOS_arm.s using the native
   702  // instructions, use:
   703  //
   704  //	TEXT ·publicationBarrier(SB),NOSPLIT,$-4-0
   705  //		B	runtime·armPublicationBarrier(SB)
   706  //
   707  TEXT runtime·armPublicationBarrier(SB),NOSPLIT,$-4-0
   708  	MOVB	runtime·goarm(SB), R11
   709  	CMP	$7, R11
   710  	BLT	2(PC)
   711  	WORD $0xf57ff05e	// DMB ST
   712  	RET
   713  
   714  // AES hashing not implemented for ARM
   715  TEXT runtime·aeshash(SB),NOSPLIT,$-4-0
   716  	MOVW	$0, R0
   717  	MOVW	(R0), R1
   718  TEXT runtime·aeshash32(SB),NOSPLIT,$-4-0
   719  	MOVW	$0, R0
   720  	MOVW	(R0), R1
   721  TEXT runtime·aeshash64(SB),NOSPLIT,$-4-0
   722  	MOVW	$0, R0
   723  	MOVW	(R0), R1
   724  TEXT runtime·aeshashstr(SB),NOSPLIT,$-4-0
   725  	MOVW	$0, R0
   726  	MOVW	(R0), R1
   727  
   728  // memhash_varlen(p unsafe.Pointer, h seed) uintptr
   729  // redirects to memhash(p, h, size) using the size
   730  // stored in the closure.
   731  TEXT runtime·memhash_varlen(SB),NOSPLIT,$16-12
   732  	GO_ARGS
   733  	NO_LOCAL_POINTERS
   734  	MOVW	p+0(FP), R0
   735  	MOVW	h+4(FP), R1
   736  	MOVW	4(R7), R2
   737  	MOVW	R0, 4(R13)
   738  	MOVW	R1, 8(R13)
   739  	MOVW	R2, 12(R13)
   740  	BL	runtime·memhash(SB)
   741  	MOVW	16(R13), R0
   742  	MOVW	R0, ret+8(FP)
   743  	RET
   744  
   745  TEXT runtime·memeq(SB),NOSPLIT,$-4-13
   746  	MOVW	a+0(FP), R1
   747  	MOVW	b+4(FP), R2
   748  	MOVW	size+8(FP), R3
   749  	ADD	R1, R3, R6
   750  	MOVW	$1, R0
   751  	MOVB	R0, ret+12(FP)
   752  loop:
   753  	CMP	R1, R6
   754  	RET.EQ
   755  	MOVBU.P	1(R1), R4
   756  	MOVBU.P	1(R2), R5
   757  	CMP	R4, R5
   758  	BEQ	loop
   759  
   760  	MOVW	$0, R0
   761  	MOVB	R0, ret+12(FP)
   762  	RET
   763  
   764  // memequal_varlen(a, b unsafe.Pointer) bool
   765  TEXT runtime·memequal_varlen(SB),NOSPLIT,$16-9
   766  	MOVW	a+0(FP), R0
   767  	MOVW	b+4(FP), R1
   768  	CMP	R0, R1
   769  	BEQ	eq
   770  	MOVW	4(R7), R2    // compiler stores size at offset 4 in the closure
   771  	MOVW	R0, 4(R13)
   772  	MOVW	R1, 8(R13)
   773  	MOVW	R2, 12(R13)
   774  	BL	runtime·memeq(SB)
   775  	MOVB	16(R13), R0
   776  	MOVB	R0, ret+8(FP)
   777  	RET
   778  eq:
   779  	MOVW	$1, R0
   780  	MOVB	R0, ret+8(FP)
   781  	RET
   782  
   783  TEXT runtime·cmpstring(SB),NOSPLIT,$-4-20
   784  	MOVW	s1_base+0(FP), R2
   785  	MOVW	s1_len+4(FP), R0
   786  	MOVW	s2_base+8(FP), R3
   787  	MOVW	s2_len+12(FP), R1
   788  	ADD	$20, R13, R7
   789  	B	runtime·cmpbody(SB)
   790  
   791  TEXT bytes·Compare(SB),NOSPLIT,$-4-28
   792  	MOVW	s1+0(FP), R2
   793  	MOVW	s1+4(FP), R0
   794  	MOVW	s2+12(FP), R3
   795  	MOVW	s2+16(FP), R1
   796  	ADD	$28, R13, R7
   797  	B	runtime·cmpbody(SB)
   798  
   799  // On entry:
   800  // R0 is the length of s1
   801  // R1 is the length of s2
   802  // R2 points to the start of s1
   803  // R3 points to the start of s2
   804  // R7 points to return value (-1/0/1 will be written here)
   805  //
   806  // On exit:
   807  // R4, R5, and R6 are clobbered
   808  TEXT runtime·cmpbody(SB),NOSPLIT,$-4-0
   809  	CMP	R2, R3
   810  	BEQ	samebytes
   811  	CMP 	R0, R1
   812  	MOVW 	R0, R6
   813  	MOVW.LT	R1, R6	// R6 is min(R0, R1)
   814  
   815  	ADD	R2, R6	// R2 is current byte in s1, R6 is last byte in s1 to compare
   816  loop:
   817  	CMP	R2, R6
   818  	BEQ	samebytes // all compared bytes were the same; compare lengths
   819  	MOVBU.P	1(R2), R4
   820  	MOVBU.P	1(R3), R5
   821  	CMP	R4, R5
   822  	BEQ	loop
   823  	// bytes differed
   824  	MOVW.LT	$1, R0
   825  	MOVW.GT	$-1, R0
   826  	MOVW	R0, (R7)
   827  	RET
   828  samebytes:
   829  	CMP	R0, R1
   830  	MOVW.LT	$1, R0
   831  	MOVW.GT	$-1, R0
   832  	MOVW.EQ	$0, R0
   833  	MOVW	R0, (R7)
   834  	RET
   835  
   836  // eqstring tests whether two strings are equal.
   837  // The compiler guarantees that strings passed
   838  // to eqstring have equal length.
   839  // See runtime_test.go:eqstring_generic for
   840  // equivalent Go code.
   841  TEXT runtime·eqstring(SB),NOSPLIT,$-4-17
   842  	MOVW	s1str+0(FP), R2
   843  	MOVW	s2str+8(FP), R3
   844  	MOVW	$1, R8
   845  	MOVB	R8, v+16(FP)
   846  	CMP	R2, R3
   847  	RET.EQ
   848  	MOVW	s1len+4(FP), R0
   849  	ADD	R2, R0, R6
   850  loop:
   851  	CMP	R2, R6
   852  	RET.EQ
   853  	MOVBU.P	1(R2), R4
   854  	MOVBU.P	1(R3), R5
   855  	CMP	R4, R5
   856  	BEQ	loop
   857  	MOVW	$0, R8
   858  	MOVB	R8, v+16(FP)
   859  	RET
   860  
   861  // TODO: share code with memeq?
   862  TEXT bytes·Equal(SB),NOSPLIT,$0-25
   863  	MOVW	a_len+4(FP), R1
   864  	MOVW	b_len+16(FP), R3
   865  	
   866  	CMP	R1, R3		// unequal lengths are not equal
   867  	B.NE	notequal
   868  
   869  	MOVW	a+0(FP), R0
   870  	MOVW	b+12(FP), R2
   871  	ADD	R0, R1		// end
   872  
   873  loop:
   874  	CMP	R0, R1
   875  	B.EQ	equal		// reached the end
   876  	MOVBU.P	1(R0), R4
   877  	MOVBU.P	1(R2), R5
   878  	CMP	R4, R5
   879  	B.EQ	loop
   880  
   881  notequal:
   882  	MOVW	$0, R0
   883  	MOVBU	R0, ret+24(FP)
   884  	RET
   885  
   886  equal:
   887  	MOVW	$1, R0
   888  	MOVBU	R0, ret+24(FP)
   889  	RET
   890  
   891  TEXT bytes·IndexByte(SB),NOSPLIT,$0-20
   892  	MOVW	s+0(FP), R0
   893  	MOVW	s_len+4(FP), R1
   894  	MOVBU	c+12(FP), R2	// byte to find
   895  	MOVW	R0, R4		// store base for later
   896  	ADD	R0, R1		// end
   897  
   898  _loop:
   899  	CMP	R0, R1
   900  	B.EQ	_notfound
   901  	MOVBU.P	1(R0), R3
   902  	CMP	R2, R3
   903  	B.NE	_loop
   904  
   905  	SUB	$1, R0		// R0 will be one beyond the position we want
   906  	SUB	R4, R0		// remove base
   907  	MOVW    R0, ret+16(FP)
   908  	RET
   909  
   910  _notfound:
   911  	MOVW	$-1, R0
   912  	MOVW	R0, ret+16(FP)
   913  	RET
   914  
   915  TEXT strings·IndexByte(SB),NOSPLIT,$0-16
   916  	MOVW	s+0(FP), R0
   917  	MOVW	s_len+4(FP), R1
   918  	MOVBU	c+8(FP), R2	// byte to find
   919  	MOVW	R0, R4		// store base for later
   920  	ADD	R0, R1		// end
   921  
   922  _sib_loop:
   923  	CMP	R0, R1
   924  	B.EQ	_sib_notfound
   925  	MOVBU.P	1(R0), R3
   926  	CMP	R2, R3
   927  	B.NE	_sib_loop
   928  
   929  	SUB	$1, R0		// R0 will be one beyond the position we want
   930  	SUB	R4, R0		// remove base
   931  	MOVW	R0, ret+12(FP)
   932  	RET
   933  
   934  _sib_notfound:
   935  	MOVW	$-1, R0
   936  	MOVW	R0, ret+12(FP)
   937  	RET
   938  
   939  TEXT runtime·fastrand1(SB),NOSPLIT,$-4-4
   940  	MOVW	g_m(g), R1
   941  	MOVW	m_fastrand(R1), R0
   942  	ADD.S	R0, R0
   943  	EOR.MI	$0x88888eef, R0
   944  	MOVW	R0, m_fastrand(R1)
   945  	MOVW	R0, ret+0(FP)
   946  	RET
   947  
   948  TEXT runtime·return0(SB),NOSPLIT,$0
   949  	MOVW	$0, R0
   950  	RET
   951  
   952  TEXT runtime·procyield(SB),NOSPLIT,$-4
   953  	MOVW	cycles+0(FP), R1
   954  	MOVW	$0, R0
   955  yieldloop:
   956  	CMP	R0, R1
   957  	B.NE	2(PC)
   958  	RET
   959  	SUB	$1, R1
   960  	B yieldloop
   961  
   962  // Called from cgo wrappers, this function returns g->m->curg.stack.hi.
   963  // Must obey the gcc calling convention.
   964  TEXT _cgo_topofstack(SB),NOSPLIT,$8
   965  	// R11 and g register are clobbered by load_g.  They are
   966  	// callee-save in the gcc calling convention, so save them here.
   967  	MOVW	R11, saveR11-4(SP)
   968  	MOVW	g, saveG-8(SP)
   969  	
   970  	BL	runtime·load_g(SB)
   971  	MOVW	g_m(g), R0
   972  	MOVW	m_curg(R0), R0
   973  	MOVW	(g_stack+stack_hi)(R0), R0
   974  	
   975  	MOVW	saveG-8(SP), g
   976  	MOVW	saveR11-4(SP), R11
   977  	RET
   978  
   979  // The top-most function running on a goroutine
   980  // returns to goexit+PCQuantum.
   981  TEXT runtime·goexit(SB),NOSPLIT,$-4-0
   982  	MOVW	R0, R0	// NOP
   983  	BL	runtime·goexit1(SB)	// does not return
   984  	// traceback from goexit1 must hit code range of goexit
   985  	MOVW	R0, R0	// NOP
   986  
   987  TEXT runtime·prefetcht0(SB),NOSPLIT,$0-4
   988  	RET
   989  
   990  TEXT runtime·prefetcht1(SB),NOSPLIT,$0-4
   991  	RET
   992  
   993  TEXT runtime·prefetcht2(SB),NOSPLIT,$0-4
   994  	RET
   995  
   996  TEXT runtime·prefetchnta(SB),NOSPLIT,$0-4
   997  	RET
   998  
   999  // x -> x/1000000, x%1000000, called from Go with args, results on stack.
  1000  TEXT runtime·usplit(SB),NOSPLIT,$0-12
  1001  	MOVW	x+0(FP), R0
  1002  	CALL	runtime·usplitR0(SB)
  1003  	MOVW	R0, q+4(FP)
  1004  	MOVW	R1, r+8(FP)
  1005  	RET
  1006  
  1007  // R0, R1 = R0/1000000, R0%1000000
  1008  TEXT runtime·usplitR0(SB),NOSPLIT,$0
  1009  	// magic multiply to avoid software divide without available m.
  1010  	// see output of go tool compile -S for x/1000000.
  1011  	MOVW	R0, R3
  1012  	MOVW	$1125899907, R1
  1013  	MULLU	R1, R0, (R0, R1)
  1014  	MOVW	R0>>18, R0
  1015  	MOVW	$1000000, R1
  1016  	MULU	R0, R1
  1017  	SUB	R1, R3, R1
  1018  	RET
  1019  
  1020  TEXT runtime·sigreturn(SB),NOSPLIT,$0-4
  1021          RET
  1022  
  1023  #ifndef GOOS_nacl
  1024  // This is called from .init_array and follows the platform, not Go, ABI.
  1025  TEXT runtime·addmoduledata(SB),NOSPLIT,$0-4
  1026  	MOVW	R9, saver9-4(SP) // The access to global variables below implicitly uses R9, which is callee-save
  1027  	MOVW	runtime·lastmoduledatap(SB), R1
  1028  	MOVW	R0, moduledata_next(R1)
  1029  	MOVW	R0, runtime·lastmoduledatap(SB)
  1030  	MOVW	saver9-4(SP), R9
  1031  	RET
  1032  #endif
  1033  
  1034  TEXT ·checkASM(SB),NOSPLIT,$0-1
  1035  	MOVW	$1, R3
  1036  	MOVB	R3, ret+0(FP)
  1037  	RET