github.com/gidoBOSSftw5731/go/src@v0.0.0-20210226122457-d24b0edbf019/runtime/sys_windows_arm.s (about)

     1  // Copyright 2018 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 "textflag.h"
     8  
     9  // Note: For system ABI, R0-R3 are args, R4-R11 are callee-save.
    10  
    11  // void runtime·asmstdcall(void *c);
    12  TEXT runtime·asmstdcall(SB),NOSPLIT|NOFRAME,$0
    13  	MOVM.DB.W [R4, R5, R14], (R13)	// push {r4, r5, lr}
    14  	MOVW	R0, R4			// put libcall * in r4
    15  	MOVW	R13, R5			// save stack pointer in r5
    16  
    17  	// SetLastError(0)
    18  	MOVW	$0, R0
    19  	MRC	15, 0, R1, C13, C0, 2
    20  	MOVW	R0, 0x34(R1)
    21  
    22  	MOVW	8(R4), R12	// libcall->args
    23  
    24  	// Do we have more than 4 arguments?
    25  	MOVW	4(R4), R0	// libcall->n
    26  	SUB.S	$4, R0, R2
    27  	BLE	loadregs
    28  
    29  	// Reserve stack space for remaining args
    30  	SUB	R2<<2, R13
    31  	BIC	$0x7, R13	// alignment for ABI
    32  
    33  	// R0: count of arguments
    34  	// R1:
    35  	// R2: loop counter, from 0 to (n-4)
    36  	// R3: scratch
    37  	// R4: pointer to libcall struct
    38  	// R12: libcall->args
    39  	MOVW	$0, R2
    40  stackargs:
    41  	ADD	$4, R2, R3		// r3 = args[4 + i]
    42  	MOVW	R3<<2(R12), R3
    43  	MOVW	R3, R2<<2(R13)		// stack[i] = r3
    44  
    45  	ADD	$1, R2			// i++
    46  	SUB	$4, R0, R3		// while (i < (n - 4))
    47  	CMP	R3, R2
    48  	BLT	stackargs
    49  
    50  loadregs:
    51  	CMP	$3, R0
    52  	MOVW.GT 12(R12), R3
    53  
    54  	CMP	$2, R0
    55  	MOVW.GT 8(R12), R2
    56  
    57  	CMP	$1, R0
    58  	MOVW.GT 4(R12), R1
    59  
    60  	CMP	$0, R0
    61  	MOVW.GT 0(R12), R0
    62  
    63  	BIC	$0x7, R13		// alignment for ABI
    64  	MOVW	0(R4), R12		// branch to libcall->fn
    65  	BL	(R12)
    66  
    67  	MOVW	R5, R13			// free stack space
    68  	MOVW	R0, 12(R4)		// save return value to libcall->r1
    69  	MOVW	R1, 16(R4)
    70  
    71  	// GetLastError
    72  	MRC	15, 0, R1, C13, C0, 2
    73  	MOVW	0x34(R1), R0
    74  	MOVW	R0, 20(R4)		// store in libcall->err
    75  
    76  	MOVM.IA.W (R13), [R4, R5, R15]
    77  
    78  TEXT runtime·badsignal2(SB),NOSPLIT|NOFRAME,$0
    79  	MOVM.DB.W [R4, R14], (R13)	// push {r4, lr}
    80  	MOVW	R13, R4			// save original stack pointer
    81  	SUB	$8, R13			// space for 2 variables
    82  	BIC	$0x7, R13		// alignment for ABI
    83  
    84  	// stderr
    85  	MOVW	runtime·_GetStdHandle(SB), R1
    86  	MOVW	$-12, R0
    87  	BL	(R1)
    88  
    89  	MOVW	$runtime·badsignalmsg(SB), R1	// lpBuffer
    90  	MOVW	$runtime·badsignallen(SB), R2	// lpNumberOfBytesToWrite
    91  	MOVW	(R2), R2
    92  	ADD	$0x4, R13, R3		// lpNumberOfBytesWritten
    93  	MOVW	$0, R12			// lpOverlapped
    94  	MOVW	R12, (R13)
    95  
    96  	MOVW	runtime·_WriteFile(SB), R12
    97  	BL	(R12)
    98  
    99  	MOVW	R4, R13			// restore SP
   100  	MOVM.IA.W (R13), [R4, R15]	// pop {r4, pc}
   101  
   102  TEXT runtime·getlasterror(SB),NOSPLIT,$0
   103  	MRC	15, 0, R0, C13, C0, 2
   104  	MOVW	0x34(R0), R0
   105  	MOVW	R0, ret+0(FP)
   106  	RET
   107  
   108  // Called by Windows as a Vectored Exception Handler (VEH).
   109  // First argument is pointer to struct containing
   110  // exception record and context pointers.
   111  // Handler function is stored in R1
   112  // Return 0 for 'not handled', -1 for handled.
   113  // int32_t sigtramp(
   114  //     PEXCEPTION_POINTERS ExceptionInfo,
   115  //     func *GoExceptionHandler);
   116  TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0
   117  	MOVM.DB.W [R0, R4-R11, R14], (R13)	// push {r0, r4-r11, lr} (SP-=40)
   118  	SUB	$(8+20), R13		// reserve space for g, sp, and
   119  					// parameters/retval to go call
   120  
   121  	MOVW	R0, R6			// Save param0
   122  	MOVW	R1, R7			// Save param1
   123  
   124  	BL      runtime·load_g(SB)
   125  	CMP	$0, g			// is there a current g?
   126  	BL.EQ	runtime·badsignal2(SB)
   127  
   128  	// save g and SP in case of stack switch
   129  	MOVW	R13, 24(R13)
   130  	MOVW	g, 20(R13)
   131  
   132  	// do we need to switch to the g0 stack?
   133  	MOVW	g, R5			// R5 = g
   134  	MOVW	g_m(R5), R2		// R2 = m
   135  	MOVW	m_g0(R2), R4		// R4 = g0
   136  	CMP	R5, R4			// if curg == g0
   137  	BEQ	g0
   138  
   139  	// switch to g0 stack
   140  	MOVW	R4, g				// g = g0
   141  	MOVW	(g_sched+gobuf_sp)(g), R3	// R3 = g->gobuf.sp
   142  	BL      runtime·save_g(SB)
   143  
   144  	// make room for sighandler arguments
   145  	// and re-save old SP for restoring later.
   146  	// (note that the 24(R3) here must match the 24(R13) above.)
   147  	SUB	$40, R3
   148  	MOVW	R13, 24(R3)		// save old stack pointer
   149  	MOVW	R3, R13			// switch stack
   150  
   151  g0:
   152  	MOVW	0(R6), R2	// R2 = ExceptionPointers->ExceptionRecord
   153  	MOVW	4(R6), R3	// R3 = ExceptionPointers->ContextRecord
   154  
   155  	MOVW	$0, R4
   156  	MOVW	R4, 0(R13)	// No saved link register.
   157  	MOVW	R2, 4(R13)	// Move arg0 (ExceptionRecord) into position
   158  	MOVW	R3, 8(R13)	// Move arg1 (ContextRecord) into position
   159  	MOVW	R5, 12(R13)	// Move arg2 (original g) into position
   160  	BL	(R7)		// Call the go routine
   161  	MOVW	16(R13), R4	// Fetch return value from stack
   162  
   163  	// Save system stack pointer for sigresume setup below.
   164  	// The exact value does not matter - nothing is read or written
   165  	// from this address. It just needs to be on the system stack.
   166  	MOVW	R13, R12
   167  
   168  	// switch back to original stack and g
   169  	MOVW	24(R13), R13
   170  	MOVW	20(R13), g
   171  	BL      runtime·save_g(SB)
   172  
   173  done:
   174  	MOVW	R4, R0				// move retval into position
   175  	ADD	$(8 + 20), R13			// free locals
   176  	MOVM.IA.W (R13), [R3, R4-R11, R14]	// pop {r3, r4-r11, lr}
   177  
   178  	// if return value is CONTINUE_SEARCH, do not set up control
   179  	// flow guard workaround
   180  	CMP	$0, R0
   181  	BEQ	return
   182  
   183  	// Check if we need to set up the control flow guard workaround.
   184  	// On Windows, the stack pointer in the context must lie within
   185  	// system stack limits when we resume from exception.
   186  	// Store the resume SP and PC on the g0 stack,
   187  	// and return to sigresume on the g0 stack. sigresume
   188  	// pops the saved PC and SP from the g0 stack, resuming execution
   189  	// at the desired location.
   190  	// If sigresume has already been set up by a previous exception
   191  	// handler, don't clobber the stored SP and PC on the stack.
   192  	MOVW	4(R3), R3			// PEXCEPTION_POINTERS->Context
   193  	MOVW	context_pc(R3), R2		// load PC from context record
   194  	MOVW	$sigresume<>(SB), R1
   195  	CMP	R1, R2
   196  	B.EQ	return				// do not clobber saved SP/PC
   197  
   198  	// Save resume SP and PC into R0, R1.
   199  	MOVW	context_spr(R3), R2
   200  	MOVW	R2, context_r0(R3)
   201  	MOVW	context_pc(R3), R2
   202  	MOVW	R2, context_r1(R3)
   203  
   204  	// Set up context record to return to sigresume on g0 stack
   205  	MOVW	R12, context_spr(R3)
   206  	MOVW	$sigresume<>(SB), R2
   207  	MOVW	R2, context_pc(R3)
   208  
   209  return:
   210  	B	(R14)				// return
   211  
   212  // Trampoline to resume execution from exception handler.
   213  // This is part of the control flow guard workaround.
   214  // It switches stacks and jumps to the continuation address.
   215  // R0 and R1 are set above at the end of sigtramp<>
   216  // in the context that starts executing at sigresume<>.
   217  TEXT sigresume<>(SB),NOSPLIT|NOFRAME,$0
   218  	// Important: do not smash LR,
   219  	// which is set to a live value when handling
   220  	// a signal by pushing a call to sigpanic onto the stack.
   221  	MOVW	R0, R13
   222  	B	(R1)
   223  
   224  TEXT runtime·exceptiontramp(SB),NOSPLIT|NOFRAME,$0
   225  	MOVW	$runtime·exceptionhandler(SB), R1
   226  	B	sigtramp<>(SB)
   227  
   228  TEXT runtime·firstcontinuetramp(SB),NOSPLIT|NOFRAME,$0
   229  	MOVW	$runtime·firstcontinuehandler(SB), R1
   230  	B	sigtramp<>(SB)
   231  
   232  TEXT runtime·lastcontinuetramp(SB),NOSPLIT|NOFRAME,$0
   233  	MOVW	$runtime·lastcontinuehandler(SB), R1
   234  	B	sigtramp<>(SB)
   235  
   236  TEXT runtime·ctrlhandler(SB),NOSPLIT|NOFRAME,$0
   237  	MOVW	$runtime·ctrlhandler1(SB), R1
   238  	B	runtime·externalthreadhandler(SB)
   239  
   240  TEXT runtime·profileloop(SB),NOSPLIT|NOFRAME,$0
   241  	MOVW	$runtime·profileloop1(SB), R1
   242  	B	runtime·externalthreadhandler(SB)
   243  
   244  // int32 externalthreadhandler(uint32 arg, int (*func)(uint32))
   245  // stack layout:
   246  //   +----------------+
   247  //   | callee-save    |
   248  //   | registers      |
   249  //   +----------------+
   250  //   | m              |
   251  //   +----------------+
   252  // 20| g              |
   253  //   +----------------+
   254  // 16| func ptr (r1)  |
   255  //   +----------------+
   256  // 12| argument (r0)  |
   257  //---+----------------+
   258  // 8 | param1         | (also return value for called Go function)
   259  //   +----------------+
   260  // 4 | param0         |
   261  //   +----------------+
   262  // 0 | slot for LR    |
   263  //   +----------------+
   264  //
   265  TEXT runtime·externalthreadhandler(SB),NOSPLIT|NOFRAME|TOPFRAME,$0
   266  	MOVM.DB.W [R4-R11, R14], (R13)		// push {r4-r11, lr}
   267  	SUB	$(m__size + g__size + 20), R13	// space for locals
   268  	MOVW	R14, 0(R13)			// push LR again for anything unwinding the stack
   269  	MOVW	R0, 12(R13)
   270  	MOVW	R1, 16(R13)
   271  
   272  	// zero out m and g structures
   273  	ADD	$20, R13, R0			// compute pointer to g
   274  	MOVW	R0, 4(R13)
   275  	MOVW	$(m__size + g__size), R0
   276  	MOVW	R0, 8(R13)
   277  	BL	runtime·memclrNoHeapPointers(SB)
   278  
   279  	// initialize m and g structures
   280  	ADD	$20, R13, R2			// R2 = g
   281  	ADD	$(20 + g__size), R13, R3	// R3 = m
   282  	MOVW	R2, m_g0(R3)			// m->g0 = g
   283  	MOVW	R3, g_m(R2)			// g->m = m
   284  	MOVW	R2, m_curg(R3)			// m->curg = g
   285  
   286  	MOVW	R2, g
   287  	BL	runtime·save_g(SB)
   288  
   289  	// set up stackguard stuff
   290  	MOVW	R13, R0
   291  	MOVW	R0, g_stack+stack_hi(g)
   292  	SUB	$(32*1024), R0
   293  	MOVW	R0, (g_stack+stack_lo)(g)
   294  	MOVW	R0, g_stackguard0(g)
   295  	MOVW	R0, g_stackguard1(g)
   296  
   297  	// move argument into position and call function
   298  	MOVW	12(R13), R0
   299  	MOVW	R0, 4(R13)
   300  	MOVW	16(R13), R1
   301  	BL	(R1)
   302  
   303  	// clear g
   304  	MOVW	$0, g
   305  	BL	runtime·save_g(SB)
   306  
   307  	MOVW	8(R13), R0			// load return value
   308  	ADD	$(m__size + g__size + 20), R13	// free locals
   309  	MOVM.IA.W (R13), [R4-R11, R15]		// pop {r4-r11, pc}
   310  
   311  GLOBL runtime·cbctxts(SB), NOPTR, $4
   312  
   313  TEXT runtime·callbackasm1(SB),NOSPLIT|NOFRAME,$0
   314  	// On entry, the trampoline in zcallback_windows_arm.s left
   315  	// the callback index in R12 (which is volatile in the C ABI).
   316  
   317  	// Push callback register arguments r0-r3. We do this first so
   318  	// they're contiguous with stack arguments.
   319  	MOVM.DB.W [R0-R3], (R13)
   320  	// Push C callee-save registers r4-r11 and lr.
   321  	MOVM.DB.W [R4-R11, R14], (R13)
   322  	SUB	$(16 + callbackArgs__size), R13	// space for locals
   323  
   324  	// Create a struct callbackArgs on our stack.
   325  	MOVW	R12, (16+callbackArgs_index)(R13)	// callback index
   326  	MOVW	$(16+callbackArgs__size+4*9)(R13), R0
   327  	MOVW	R0, (16+callbackArgs_args)(R13)		// address of args vector
   328  	MOVW	$0, R0
   329  	MOVW	R0, (16+callbackArgs_result)(R13)	// result
   330  
   331  	// Prepare for entry to Go.
   332  	BL	runtime·load_g(SB)
   333  
   334  	// Call cgocallback, which will call callbackWrap(frame).
   335  	MOVW	$0, R0
   336  	MOVW	R0, 12(R13)	// context
   337  	MOVW	$16(R13), R1	// R1 = &callbackArgs{...}
   338  	MOVW	R1, 8(R13)	// frame (address of callbackArgs)
   339  	MOVW	$·callbackWrap(SB), R1
   340  	MOVW	R1, 4(R13)	// PC of function to call
   341  	BL	runtime·cgocallback(SB)
   342  
   343  	// Get callback result.
   344  	MOVW	(16+callbackArgs_result)(R13), R0
   345  
   346  	ADD	$(16 + callbackArgs__size), R13	// free locals
   347  	MOVM.IA.W (R13), [R4-R11, R12]	// pop {r4-r11, lr=>r12}
   348  	ADD	$(4*4), R13	// skip r0-r3
   349  	B	(R12)	// return
   350  
   351  // uint32 tstart_stdcall(M *newm);
   352  TEXT runtime·tstart_stdcall(SB),NOSPLIT|NOFRAME,$0
   353  	MOVM.DB.W [R4-R11, R14], (R13)		// push {r4-r11, lr}
   354  
   355  	MOVW	m_g0(R0), g
   356  	MOVW	R0, g_m(g)
   357  	BL	runtime·save_g(SB)
   358  
   359  	// Layout new m scheduler stack on os stack.
   360  	MOVW	R13, R0
   361  	MOVW	R0, g_stack+stack_hi(g)
   362  	SUB	$(64*1024), R0
   363  	MOVW	R0, (g_stack+stack_lo)(g)
   364  	MOVW	R0, g_stackguard0(g)
   365  	MOVW	R0, g_stackguard1(g)
   366  
   367  	BL	runtime·emptyfunc(SB)	// fault if stack check is wrong
   368  	BL	runtime·mstart(SB)
   369  
   370  	// Exit the thread.
   371  	MOVW	$0, R0
   372  	MOVM.IA.W (R13), [R4-R11, R15]		// pop {r4-r11, pc}
   373  
   374  // Runs on OS stack.
   375  // duration (in -100ns units) is in dt+0(FP).
   376  // g may be nil.
   377  TEXT runtime·usleep2(SB),NOSPLIT|NOFRAME,$0-4
   378  	MOVW	dt+0(FP), R3
   379  	MOVM.DB.W [R4, R14], (R13)	// push {r4, lr}
   380  	MOVW	R13, R4			// Save SP
   381  	SUB	$8, R13			// R13 = R13 - 8
   382  	BIC	$0x7, R13		// Align SP for ABI
   383  	MOVW	$0, R1			// R1 = FALSE (alertable)
   384  	MOVW	$-1, R0			// R0 = handle
   385  	MOVW	R13, R2			// R2 = pTime
   386  	MOVW	R3, 0(R2)		// time_lo
   387  	MOVW	R0, 4(R2)		// time_hi
   388  	MOVW	runtime·_NtWaitForSingleObject(SB), R3
   389  	BL	(R3)
   390  	MOVW	R4, R13			// Restore SP
   391  	MOVM.IA.W (R13), [R4, R15]	// pop {R4, pc}
   392  
   393  // Runs on OS stack.
   394  // duration (in -100ns units) is in dt+0(FP).
   395  // g is valid.
   396  // TODO: neeeds to be implemented properly.
   397  TEXT runtime·usleep2HighRes(SB),NOSPLIT|NOFRAME,$0-4
   398  	B	runtime·abort(SB)
   399  
   400  // Runs on OS stack.
   401  TEXT runtime·switchtothread(SB),NOSPLIT|NOFRAME,$0
   402  	MOVM.DB.W [R4, R14], (R13)  	// push {R4, lr}
   403  	MOVW    R13, R4
   404  	BIC	$0x7, R13		// alignment for ABI
   405  	MOVW	runtime·_SwitchToThread(SB), R0
   406  	BL	(R0)
   407  	MOVW 	R4, R13			// restore stack pointer
   408  	MOVM.IA.W (R13), [R4, R15]	// pop {R4, pc}
   409  
   410  TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-0
   411  	B	runtime·armPublicationBarrier(SB)
   412  
   413  // never called (cgo not supported)
   414  TEXT runtime·read_tls_fallback(SB),NOSPLIT|NOFRAME,$0
   415  	MOVW	$0xabcd, R0
   416  	MOVW	R0, (R0)
   417  	RET
   418  
   419  // See http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
   420  // Must read hi1, then lo, then hi2. The snapshot is valid if hi1 == hi2.
   421  #define _INTERRUPT_TIME 0x7ffe0008
   422  #define _SYSTEM_TIME 0x7ffe0014
   423  #define time_lo 0
   424  #define time_hi1 4
   425  #define time_hi2 8
   426  
   427  TEXT runtime·nanotime1(SB),NOSPLIT|NOFRAME,$0-8
   428  	MOVW	$0, R0
   429  	MOVB	runtime·useQPCTime(SB), R0
   430  	CMP	$0, R0
   431  	BNE	useQPC
   432  	MOVW	$_INTERRUPT_TIME, R3
   433  loop:
   434  	MOVW	time_hi1(R3), R1
   435  	MOVW	time_lo(R3), R0
   436  	MOVW	time_hi2(R3), R2
   437  	CMP	R1, R2
   438  	BNE	loop
   439  
   440  	// wintime = R1:R0, multiply by 100
   441  	MOVW	$100, R2
   442  	MULLU	R0, R2, (R4, R3)    // R4:R3 = R1:R0 * R2
   443  	MULA	R1, R2, R4, R4
   444  
   445  	// wintime*100 = R4:R3
   446  	MOVW	R3, ret_lo+0(FP)
   447  	MOVW	R4, ret_hi+4(FP)
   448  	RET
   449  useQPC:
   450  	B	runtime·nanotimeQPC(SB)		// tail call
   451  
   452  TEXT time·now(SB),NOSPLIT|NOFRAME,$0-20
   453  	MOVW    $0, R0
   454  	MOVB    runtime·useQPCTime(SB), R0
   455  	CMP	$0, R0
   456  	BNE	useQPC
   457  	MOVW	$_INTERRUPT_TIME, R3
   458  loop:
   459  	MOVW	time_hi1(R3), R1
   460  	MOVW	time_lo(R3), R0
   461  	MOVW	time_hi2(R3), R2
   462  	CMP	R1, R2
   463  	BNE	loop
   464  
   465  	// wintime = R1:R0, multiply by 100
   466  	MOVW	$100, R2
   467  	MULLU	R0, R2, (R4, R3)    // R4:R3 = R1:R0 * R2
   468  	MULA	R1, R2, R4, R4
   469  
   470  	// wintime*100 = R4:R3
   471  	MOVW	R3, mono+12(FP)
   472  	MOVW	R4, mono+16(FP)
   473  
   474  	MOVW	$_SYSTEM_TIME, R3
   475  wall:
   476  	MOVW	time_hi1(R3), R1
   477  	MOVW	time_lo(R3), R0
   478  	MOVW	time_hi2(R3), R2
   479  	CMP	R1, R2
   480  	BNE	wall
   481  
   482  	// w = R1:R0 in 100ns untis
   483  	// convert to Unix epoch (but still 100ns units)
   484  	#define delta 116444736000000000
   485  	SUB.S   $(delta & 0xFFFFFFFF), R0
   486  	SBC     $(delta >> 32), R1
   487  
   488  	// Convert to nSec
   489  	MOVW    $100, R2
   490  	MULLU   R0, R2, (R4, R3)    // R4:R3 = R1:R0 * R2
   491  	MULA    R1, R2, R4, R4
   492  	// w = R2:R1 in nSec
   493  	MOVW    R3, R1	      // R4:R3 -> R2:R1
   494  	MOVW    R4, R2
   495  
   496  	// multiply nanoseconds by reciprocal of 10**9 (scaled by 2**61)
   497  	// to get seconds (96 bit scaled result)
   498  	MOVW	$0x89705f41, R3		// 2**61 * 10**-9
   499  	MULLU	R1,R3,(R6,R5)		// R7:R6:R5 = R2:R1 * R3
   500  	MOVW	$0,R7
   501  	MULALU	R2,R3,(R7,R6)
   502  
   503  	// unscale by discarding low 32 bits, shifting the rest by 29
   504  	MOVW	R6>>29,R6		// R7:R6 = (R7:R6:R5 >> 61)
   505  	ORR	R7<<3,R6
   506  	MOVW	R7>>29,R7
   507  
   508  	// subtract (10**9 * sec) from nsec to get nanosecond remainder
   509  	MOVW	$1000000000, R5	// 10**9
   510  	MULLU	R6,R5,(R9,R8)   // R9:R8 = R7:R6 * R5
   511  	MULA	R7,R5,R9,R9
   512  	SUB.S	R8,R1		// R2:R1 -= R9:R8
   513  	SBC	R9,R2
   514  
   515  	// because reciprocal was a truncated repeating fraction, quotient
   516  	// may be slightly too small -- adjust to make remainder < 10**9
   517  	CMP	R5,R1	// if remainder > 10**9
   518  	SUB.HS	R5,R1   //    remainder -= 10**9
   519  	ADD.HS	$1,R6	//    sec += 1
   520  
   521  	MOVW	R6,sec_lo+0(FP)
   522  	MOVW	R7,sec_hi+4(FP)
   523  	MOVW	R1,nsec+8(FP)
   524  	RET
   525  useQPC:
   526  	B	runtime·nowQPC(SB)		// tail call
   527  
   528  // save_g saves the g register (R10) into thread local memory
   529  // so that we can call externally compiled
   530  // ARM code that will overwrite those registers.
   531  // NOTE: runtime.gogo assumes that R1 is preserved by this function.
   532  //       runtime.mcall assumes this function only clobbers R0 and R11.
   533  // Returns with g in R0.
   534  // Save the value in the _TEB->TlsSlots array.
   535  // Effectively implements TlsSetValue().
   536  // tls_g stores the TLS slot allocated TlsAlloc().
   537  TEXT runtime·save_g(SB),NOSPLIT|NOFRAME,$0
   538  	MRC	15, 0, R0, C13, C0, 2
   539  	ADD	$0xe10, R0
   540  	MOVW 	$runtime·tls_g(SB), R11
   541  	MOVW	(R11), R11
   542  	MOVW	g, R11<<2(R0)
   543  	MOVW	g, R0	// preserve R0 across call to setg<>
   544  	RET
   545  
   546  // load_g loads the g register from thread-local memory,
   547  // for use after calling externally compiled
   548  // ARM code that overwrote those registers.
   549  // Get the value from the _TEB->TlsSlots array.
   550  // Effectively implements TlsGetValue().
   551  TEXT runtime·load_g(SB),NOSPLIT|NOFRAME,$0
   552  	MRC	15, 0, R0, C13, C0, 2
   553  	ADD	$0xe10, R0
   554  	MOVW 	$runtime·tls_g(SB), g
   555  	MOVW	(g), g
   556  	MOVW	g<<2(R0), g
   557  	RET
   558  
   559  // This is called from rt0_go, which runs on the system stack
   560  // using the initial stack allocated by the OS.
   561  // It calls back into standard C using the BL below.
   562  // To do that, the stack pointer must be 8-byte-aligned.
   563  TEXT runtime·_initcgo(SB),NOSPLIT|NOFRAME,$0
   564  	MOVM.DB.W [R4, R14], (R13)	// push {r4, lr}
   565  
   566  	// Ensure stack is 8-byte aligned before calling C code
   567  	MOVW	R13, R4
   568  	BIC	$0x7, R13
   569  
   570  	// Allocate a TLS slot to hold g across calls to external code
   571  	MOVW 	$runtime·_TlsAlloc(SB), R0
   572  	MOVW	(R0), R0
   573  	BL	(R0)
   574  
   575  	// Assert that slot is less than 64 so we can use _TEB->TlsSlots
   576  	CMP	$64, R0
   577  	MOVW	$runtime·abort(SB), R1
   578  	BL.GE	(R1)
   579  
   580  	// Save Slot into tls_g
   581  	MOVW 	$runtime·tls_g(SB), R1
   582  	MOVW	R0, (R1)
   583  
   584  	MOVW	R4, R13
   585  	MOVM.IA.W (R13), [R4, R15]	// pop {r4, pc}
   586  
   587  // Holds the TLS Slot, which was allocated by TlsAlloc()
   588  GLOBL runtime·tls_g+0(SB), NOPTR, $4