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