github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/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|NOFRAME,$0 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|NOFRAME,$0 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 g, 32(R13) 40 MOVW R11, 36(R13) 41 42 // Skip floating point registers on GOARM < 6. 43 MOVB runtime·goarm(SB), R11 44 CMP $6, R11 45 BLT skipfpsave 46 MOVD F8, (40+8*0)(R13) 47 MOVD F9, (40+8*1)(R13) 48 MOVD F10, (40+8*2)(R13) 49 MOVD F11, (40+8*3)(R13) 50 MOVD F12, (40+8*4)(R13) 51 MOVD F13, (40+8*5)(R13) 52 MOVD F14, (40+8*6)(R13) 53 MOVD F15, (40+8*7)(R13) 54 skipfpsave: 55 // Save argc/argv. 56 MOVW R0, _rt0_arm_lib_argc<>(SB) 57 MOVW R1, _rt0_arm_lib_argv<>(SB) 58 59 MOVW $0, g // Initialize g. 60 61 // Synchronous initialization. 62 CALL runtime·libpreinit(SB) 63 64 // Create a new thread to do the runtime initialization. 65 MOVW _cgo_sys_thread_create(SB), R2 66 CMP $0, R2 67 BEQ nocgo 68 MOVW $_rt0_arm_lib_go<>(SB), R0 69 MOVW $0, R1 70 BL (R2) 71 B rr 72 nocgo: 73 MOVW $0x800000, R0 // stacksize = 8192KB 74 MOVW $_rt0_arm_lib_go<>(SB), R1 // fn 75 MOVW R0, 4(R13) 76 MOVW R1, 8(R13) 77 BL runtime·newosproc0(SB) 78 rr: 79 // Restore callee-save registers and return. 80 MOVB runtime·goarm(SB), R11 81 CMP $6, R11 82 BLT skipfprest 83 MOVD (40+8*0)(R13), F8 84 MOVD (40+8*1)(R13), F9 85 MOVD (40+8*2)(R13), F10 86 MOVD (40+8*3)(R13), F11 87 MOVD (40+8*4)(R13), F12 88 MOVD (40+8*5)(R13), F13 89 MOVD (40+8*6)(R13), F14 90 MOVD (40+8*7)(R13), F15 91 skipfprest: 92 MOVW 12(R13), R4 93 MOVW 16(R13), R5 94 MOVW 20(R13), R6 95 MOVW 24(R13), R7 96 MOVW 28(R13), R8 97 MOVW 32(R13), g 98 MOVW 36(R13), R11 99 RET 100 101 // _rt0_arm_lib_go initializes the Go runtime. 102 // This is started in a separate thread by _rt0_arm_lib. 103 TEXT _rt0_arm_lib_go<>(SB),NOSPLIT,$8 104 MOVW _rt0_arm_lib_argc<>(SB), R0 105 MOVW _rt0_arm_lib_argv<>(SB), R1 106 B runtime·rt0_go(SB) 107 108 DATA _rt0_arm_lib_argc<>(SB)/4,$0 109 GLOBL _rt0_arm_lib_argc<>(SB),NOPTR,$4 110 DATA _rt0_arm_lib_argv<>(SB)/4,$0 111 GLOBL _rt0_arm_lib_argv<>(SB),NOPTR,$4 112 113 // using NOFRAME means do not save LR on stack. 114 // argc is in R0, argv is in R1. 115 TEXT runtime·rt0_go(SB),NOSPLIT|NOFRAME,$0 116 MOVW $0xcafebabe, R12 117 118 // copy arguments forward on an even stack 119 // use R13 instead of SP to avoid linker rewriting the offsets 120 SUB $64, R13 // plenty of scratch 121 AND $~7, R13 122 MOVW R0, 60(R13) // save argc, argv away 123 MOVW R1, 64(R13) 124 125 // set up g register 126 // g is R10 127 MOVW $runtime·g0(SB), g 128 MOVW $runtime·m0(SB), R8 129 130 // save m->g0 = g0 131 MOVW g, m_g0(R8) 132 // save g->m = m0 133 MOVW R8, g_m(g) 134 135 // create istack out of the OS stack 136 // (1MB of system stack is available on iOS and Android) 137 MOVW $(-64*1024+104)(R13), R0 138 MOVW R0, g_stackguard0(g) 139 MOVW R0, g_stackguard1(g) 140 MOVW R0, (g_stack+stack_lo)(g) 141 MOVW R13, (g_stack+stack_hi)(g) 142 143 BL runtime·emptyfunc(SB) // fault if stack check is wrong 144 145 BL runtime·_initcgo(SB) // will clobber R0-R3 146 147 // update stackguard after _cgo_init 148 MOVW (g_stack+stack_lo)(g), R0 149 ADD $const__StackGuard, R0 150 MOVW R0, g_stackguard0(g) 151 MOVW R0, g_stackguard1(g) 152 153 BL runtime·check(SB) 154 155 // saved argc, argv 156 MOVW 60(R13), R0 157 MOVW R0, 4(R13) 158 MOVW 64(R13), R1 159 MOVW R1, 8(R13) 160 BL runtime·args(SB) 161 BL runtime·checkgoarm(SB) 162 BL runtime·osinit(SB) 163 BL runtime·schedinit(SB) 164 165 // create a new goroutine to start program 166 MOVW $runtime·mainPC(SB), R0 167 MOVW.W R0, -4(R13) 168 MOVW $8, R0 169 MOVW.W R0, -4(R13) 170 MOVW $0, R0 171 MOVW.W R0, -4(R13) // push $0 as guard 172 BL runtime·newproc(SB) 173 MOVW $12(R13), R13 // pop args and LR 174 175 // start this M 176 BL runtime·mstart(SB) 177 178 MOVW $1234, R0 179 MOVW $1000, R1 180 MOVW R0, (R1) // fail hard 181 182 DATA runtime·mainPC+0(SB)/4,$runtime·main(SB) 183 GLOBL runtime·mainPC(SB),RODATA,$4 184 185 TEXT runtime·breakpoint(SB),NOSPLIT,$0-0 186 // gdb won't skip this breakpoint instruction automatically, 187 // so you must manually "set $pc+=4" to skip it and continue. 188 #ifdef GOOS_plan9 189 WORD $0xD1200070 // undefined instruction used as armv5 breakpoint in Plan 9 190 #else 191 WORD $0xe7f001f0 // undefined instruction that gdb understands is a software breakpoint 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|NOFRAME,$0-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|NOFRAME,$0-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 B runtime·abort(SB) 321 322 switch: 323 // save our state in g->sched. Pretend to 324 // be systemstack_switch if the G stack is scanned. 325 MOVW $runtime·systemstack_switch(SB), R3 326 ADD $4, R3, R3 // get past push {lr} 327 MOVW R3, (g_sched+gobuf_pc)(g) 328 MOVW R13, (g_sched+gobuf_sp)(g) 329 MOVW LR, (g_sched+gobuf_lr)(g) 330 MOVW g, (g_sched+gobuf_g)(g) 331 332 // switch to g0 333 MOVW R0, R5 334 MOVW R2, R0 335 BL setg<>(SB) 336 MOVW R5, R0 337 MOVW (g_sched+gobuf_sp)(R2), R3 338 // make it look like mstart called systemstack on g0, to stop traceback 339 SUB $4, R3, R3 340 MOVW $runtime·mstart(SB), R4 341 MOVW R4, 0(R3) 342 MOVW R3, R13 343 344 // call target function 345 MOVW R0, R7 346 MOVW 0(R0), R0 347 BL (R0) 348 349 // switch back to g 350 MOVW g_m(g), R1 351 MOVW m_curg(R1), R0 352 BL setg<>(SB) 353 MOVW (g_sched+gobuf_sp)(g), R13 354 MOVW $0, R3 355 MOVW R3, (g_sched+gobuf_sp)(g) 356 RET 357 358 noswitch: 359 // Using a tail call here cleans up tracebacks since we won't stop 360 // at an intermediate systemstack. 361 MOVW R0, R7 362 MOVW 0(R0), R0 363 MOVW.P 4(R13), R14 // restore LR 364 B (R0) 365 366 /* 367 * support for morestack 368 */ 369 370 // Called during function prolog when more stack is needed. 371 // R3 prolog's LR 372 // using NOFRAME means do not save LR on stack. 373 // 374 // The traceback routines see morestack on a g0 as being 375 // the top of a stack (for example, morestack calling newstack 376 // calling the scheduler calling newm calling gc), so we must 377 // record an argument size. For that purpose, it has no arguments. 378 TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 379 // Cannot grow scheduler stack (m->g0). 380 MOVW g_m(g), R8 381 MOVW m_g0(R8), R4 382 CMP g, R4 383 BNE 3(PC) 384 BL runtime·badmorestackg0(SB) 385 B runtime·abort(SB) 386 387 // Cannot grow signal stack (m->gsignal). 388 MOVW m_gsignal(R8), R4 389 CMP g, R4 390 BNE 3(PC) 391 BL runtime·badmorestackgsignal(SB) 392 B runtime·abort(SB) 393 394 // Called from f. 395 // Set g->sched to context in f. 396 MOVW R13, (g_sched+gobuf_sp)(g) 397 MOVW LR, (g_sched+gobuf_pc)(g) 398 MOVW R3, (g_sched+gobuf_lr)(g) 399 MOVW R7, (g_sched+gobuf_ctxt)(g) 400 401 // Called from f. 402 // Set m->morebuf to f's caller. 403 MOVW R3, (m_morebuf+gobuf_pc)(R8) // f's caller's PC 404 MOVW R13, (m_morebuf+gobuf_sp)(R8) // f's caller's SP 405 MOVW g, (m_morebuf+gobuf_g)(R8) 406 407 // Call newstack on m->g0's stack. 408 MOVW m_g0(R8), R0 409 BL setg<>(SB) 410 MOVW (g_sched+gobuf_sp)(g), R13 411 MOVW $0, R0 412 MOVW.W R0, -4(R13) // create a call frame on g0 (saved LR) 413 BL runtime·newstack(SB) 414 415 // Not reached, but make sure the return PC from the call to newstack 416 // is still in this function, and not the beginning of the next. 417 RET 418 419 TEXT runtime·morestack_noctxt(SB),NOSPLIT|NOFRAME,$0-0 420 MOVW $0, R7 421 B runtime·morestack(SB) 422 423 // reflectcall: call a function with the given argument list 424 // func call(argtype *_type, f *FuncVal, arg *byte, argsize, retoffset uint32). 425 // we don't have variable-sized frames, so we use a small number 426 // of constant-sized-frame functions to encode a few bits of size in the pc. 427 // Caution: ugly multiline assembly macros in your future! 428 429 #define DISPATCH(NAME,MAXSIZE) \ 430 CMP $MAXSIZE, R0; \ 431 B.HI 3(PC); \ 432 MOVW $NAME(SB), R1; \ 433 B (R1) 434 435 TEXT ·reflectcall(SB),NOSPLIT|NOFRAME,$0-20 436 MOVW argsize+12(FP), R0 437 DISPATCH(runtime·call16, 16) 438 DISPATCH(runtime·call32, 32) 439 DISPATCH(runtime·call64, 64) 440 DISPATCH(runtime·call128, 128) 441 DISPATCH(runtime·call256, 256) 442 DISPATCH(runtime·call512, 512) 443 DISPATCH(runtime·call1024, 1024) 444 DISPATCH(runtime·call2048, 2048) 445 DISPATCH(runtime·call4096, 4096) 446 DISPATCH(runtime·call8192, 8192) 447 DISPATCH(runtime·call16384, 16384) 448 DISPATCH(runtime·call32768, 32768) 449 DISPATCH(runtime·call65536, 65536) 450 DISPATCH(runtime·call131072, 131072) 451 DISPATCH(runtime·call262144, 262144) 452 DISPATCH(runtime·call524288, 524288) 453 DISPATCH(runtime·call1048576, 1048576) 454 DISPATCH(runtime·call2097152, 2097152) 455 DISPATCH(runtime·call4194304, 4194304) 456 DISPATCH(runtime·call8388608, 8388608) 457 DISPATCH(runtime·call16777216, 16777216) 458 DISPATCH(runtime·call33554432, 33554432) 459 DISPATCH(runtime·call67108864, 67108864) 460 DISPATCH(runtime·call134217728, 134217728) 461 DISPATCH(runtime·call268435456, 268435456) 462 DISPATCH(runtime·call536870912, 536870912) 463 DISPATCH(runtime·call1073741824, 1073741824) 464 MOVW $runtime·badreflectcall(SB), R1 465 B (R1) 466 467 #define CALLFN(NAME,MAXSIZE) \ 468 TEXT NAME(SB), WRAPPER, $MAXSIZE-20; \ 469 NO_LOCAL_POINTERS; \ 470 /* copy arguments to stack */ \ 471 MOVW argptr+8(FP), R0; \ 472 MOVW argsize+12(FP), R2; \ 473 ADD $4, R13, R1; \ 474 CMP $0, R2; \ 475 B.EQ 5(PC); \ 476 MOVBU.P 1(R0), R5; \ 477 MOVBU.P R5, 1(R1); \ 478 SUB $1, R2, R2; \ 479 B -5(PC); \ 480 /* call function */ \ 481 MOVW f+4(FP), R7; \ 482 MOVW (R7), R0; \ 483 PCDATA $PCDATA_StackMapIndex, $0; \ 484 BL (R0); \ 485 /* copy return values back */ \ 486 MOVW argtype+0(FP), R4; \ 487 MOVW argptr+8(FP), R0; \ 488 MOVW argsize+12(FP), R2; \ 489 MOVW retoffset+16(FP), R3; \ 490 ADD $4, R13, R1; \ 491 ADD R3, R1; \ 492 ADD R3, R0; \ 493 SUB R3, R2; \ 494 BL callRet<>(SB); \ 495 RET 496 497 // callRet copies return values back at the end of call*. This is a 498 // separate function so it can allocate stack space for the arguments 499 // to reflectcallmove. It does not follow the Go ABI; it expects its 500 // arguments in registers. 501 TEXT callRet<>(SB), NOSPLIT, $16-0 502 MOVW R4, 4(R13) 503 MOVW R0, 8(R13) 504 MOVW R1, 12(R13) 505 MOVW R2, 16(R13) 506 BL runtime·reflectcallmove(SB) 507 RET 508 509 CALLFN(·call16, 16) 510 CALLFN(·call32, 32) 511 CALLFN(·call64, 64) 512 CALLFN(·call128, 128) 513 CALLFN(·call256, 256) 514 CALLFN(·call512, 512) 515 CALLFN(·call1024, 1024) 516 CALLFN(·call2048, 2048) 517 CALLFN(·call4096, 4096) 518 CALLFN(·call8192, 8192) 519 CALLFN(·call16384, 16384) 520 CALLFN(·call32768, 32768) 521 CALLFN(·call65536, 65536) 522 CALLFN(·call131072, 131072) 523 CALLFN(·call262144, 262144) 524 CALLFN(·call524288, 524288) 525 CALLFN(·call1048576, 1048576) 526 CALLFN(·call2097152, 2097152) 527 CALLFN(·call4194304, 4194304) 528 CALLFN(·call8388608, 8388608) 529 CALLFN(·call16777216, 16777216) 530 CALLFN(·call33554432, 33554432) 531 CALLFN(·call67108864, 67108864) 532 CALLFN(·call134217728, 134217728) 533 CALLFN(·call268435456, 268435456) 534 CALLFN(·call536870912, 536870912) 535 CALLFN(·call1073741824, 1073741824) 536 537 // void jmpdefer(fn, sp); 538 // called from deferreturn. 539 // 1. grab stored LR for caller 540 // 2. sub 4 bytes to get back to BL deferreturn 541 // 3. B to fn 542 // TODO(rsc): Push things on stack and then use pop 543 // to load all registers simultaneously, so that a profiling 544 // interrupt can never see mismatched SP/LR/PC. 545 // (And double-check that pop is atomic in that way.) 546 TEXT runtime·jmpdefer(SB),NOSPLIT,$0-8 547 MOVW 0(R13), LR 548 MOVW $-4(LR), LR // BL deferreturn 549 MOVW fv+0(FP), R7 550 MOVW argp+4(FP), R13 551 MOVW $-4(R13), R13 // SP is 4 below argp, due to saved LR 552 MOVW 0(R7), R1 553 B (R1) 554 555 // Save state of caller into g->sched. Smashes R11. 556 TEXT gosave<>(SB),NOSPLIT|NOFRAME,$0 557 MOVW LR, (g_sched+gobuf_pc)(g) 558 MOVW R13, (g_sched+gobuf_sp)(g) 559 MOVW $0, R11 560 MOVW R11, (g_sched+gobuf_lr)(g) 561 MOVW R11, (g_sched+gobuf_ret)(g) 562 MOVW R11, (g_sched+gobuf_ctxt)(g) 563 // Assert ctxt is zero. See func save. 564 MOVW (g_sched+gobuf_ctxt)(g), R11 565 CMP $0, R11 566 B.EQ 2(PC) 567 CALL runtime·badctxt(SB) 568 RET 569 570 // func asmcgocall(fn, arg unsafe.Pointer) int32 571 // Call fn(arg) on the scheduler stack, 572 // aligned appropriately for the gcc ABI. 573 // See cgocall.go for more details. 574 TEXT ·asmcgocall(SB),NOSPLIT,$0-12 575 MOVW fn+0(FP), R1 576 MOVW arg+4(FP), R0 577 578 MOVW R13, R2 579 CMP $0, g 580 BEQ nosave 581 MOVW g, R4 582 583 // Figure out if we need to switch to m->g0 stack. 584 // We get called to create new OS threads too, and those 585 // come in on the m->g0 stack already. 586 MOVW g_m(g), R8 587 MOVW m_gsignal(R8), R3 588 CMP R3, g 589 BEQ nosave 590 MOVW m_g0(R8), R3 591 CMP R3, g 592 BEQ nosave 593 BL gosave<>(SB) 594 MOVW R0, R5 595 MOVW R3, R0 596 BL setg<>(SB) 597 MOVW R5, R0 598 MOVW (g_sched+gobuf_sp)(g), R13 599 600 // Now on a scheduling stack (a pthread-created stack). 601 SUB $24, R13 602 BIC $0x7, R13 // alignment for gcc ABI 603 MOVW R4, 20(R13) // save old g 604 MOVW (g_stack+stack_hi)(R4), R4 605 SUB R2, R4 606 MOVW R4, 16(R13) // save depth in stack (can't just save SP, as stack might be copied during a callback) 607 BL (R1) 608 609 // Restore registers, g, stack pointer. 610 MOVW R0, R5 611 MOVW 20(R13), R0 612 BL setg<>(SB) 613 MOVW (g_stack+stack_hi)(g), R1 614 MOVW 16(R13), R2 615 SUB R2, R1 616 MOVW R5, R0 617 MOVW R1, R13 618 619 MOVW R0, ret+8(FP) 620 RET 621 622 nosave: 623 // Running on a system stack, perhaps even without a g. 624 // Having no g can happen during thread creation or thread teardown 625 // (see needm/dropm on Solaris, for example). 626 // This code is like the above sequence but without saving/restoring g 627 // and without worrying about the stack moving out from under us 628 // (because we're on a system stack, not a goroutine stack). 629 // The above code could be used directly if already on a system stack, 630 // but then the only path through this code would be a rare case on Solaris. 631 // Using this code for all "already on system stack" calls exercises it more, 632 // which should help keep it correct. 633 SUB $24, R13 634 BIC $0x7, R13 // alignment for gcc ABI 635 // save null g in case someone looks during debugging. 636 MOVW $0, R4 637 MOVW R4, 20(R13) 638 MOVW R2, 16(R13) // Save old stack pointer. 639 BL (R1) 640 // Restore stack pointer. 641 MOVW 16(R13), R2 642 MOVW R2, R13 643 MOVW R0, ret+8(FP) 644 RET 645 646 // cgocallback(fn, frame unsafe.Pointer, ctxt uintptr) 647 // See cgocall.go for more details. 648 TEXT ·cgocallback(SB),NOSPLIT,$12-12 649 NO_LOCAL_POINTERS 650 651 // Load m and g from thread-local storage. 652 MOVB runtime·iscgo(SB), R0 653 CMP $0, R0 654 BL.NE runtime·load_g(SB) 655 656 // If g is nil, Go did not create the current thread. 657 // Call needm to obtain one for temporary use. 658 // In this case, we're running on the thread stack, so there's 659 // lots of space, but the linker doesn't know. Hide the call from 660 // the linker analysis by using an indirect call. 661 CMP $0, g 662 B.EQ needm 663 664 MOVW g_m(g), R8 665 MOVW R8, savedm-4(SP) 666 B havem 667 668 needm: 669 MOVW g, savedm-4(SP) // g is zero, so is m. 670 MOVW $runtime·needm(SB), R0 671 BL (R0) 672 673 // Set m->g0->sched.sp = SP, so that if a panic happens 674 // during the function we are about to execute, it will 675 // have a valid SP to run on the g0 stack. 676 // The next few lines (after the havem label) 677 // will save this SP onto the stack and then write 678 // the same SP back to m->sched.sp. That seems redundant, 679 // but if an unrecovered panic happens, unwindm will 680 // restore the g->sched.sp from the stack location 681 // and then systemstack will try to use it. If we don't set it here, 682 // that restored SP will be uninitialized (typically 0) and 683 // will not be usable. 684 MOVW g_m(g), R8 685 MOVW m_g0(R8), R3 686 MOVW R13, (g_sched+gobuf_sp)(R3) 687 688 havem: 689 // Now there's a valid m, and we're running on its m->g0. 690 // Save current m->g0->sched.sp on stack and then set it to SP. 691 // Save current sp in m->g0->sched.sp in preparation for 692 // switch back to m->curg stack. 693 // NOTE: unwindm knows that the saved g->sched.sp is at 4(R13) aka savedsp-12(SP). 694 MOVW m_g0(R8), R3 695 MOVW (g_sched+gobuf_sp)(R3), R4 696 MOVW R4, savedsp-12(SP) // must match frame size 697 MOVW R13, (g_sched+gobuf_sp)(R3) 698 699 // Switch to m->curg stack and call runtime.cgocallbackg. 700 // Because we are taking over the execution of m->curg 701 // but *not* resuming what had been running, we need to 702 // save that information (m->curg->sched) so we can restore it. 703 // We can restore m->curg->sched.sp easily, because calling 704 // runtime.cgocallbackg leaves SP unchanged upon return. 705 // To save m->curg->sched.pc, we push it onto the curg stack and 706 // open a frame the same size as cgocallback's g0 frame. 707 // Once we switch to the curg stack, the pushed PC will appear 708 // to be the return PC of cgocallback, so that the traceback 709 // will seamlessly trace back into the earlier calls. 710 MOVW m_curg(R8), R0 711 BL setg<>(SB) 712 MOVW (g_sched+gobuf_sp)(g), R4 // prepare stack as R4 713 MOVW (g_sched+gobuf_pc)(g), R5 714 MOVW R5, -(12+4)(R4) // "saved LR"; must match frame size 715 // Gather our arguments into registers. 716 MOVW fn+0(FP), R1 717 MOVW frame+4(FP), R2 718 MOVW ctxt+8(FP), R3 719 MOVW $-(12+4)(R4), R13 // switch stack; must match frame size 720 MOVW R1, 4(R13) 721 MOVW R2, 8(R13) 722 MOVW R3, 12(R13) 723 BL runtime·cgocallbackg(SB) 724 725 // Restore g->sched (== m->curg->sched) from saved values. 726 MOVW 0(R13), R5 727 MOVW R5, (g_sched+gobuf_pc)(g) 728 MOVW $(12+4)(R13), R4 // must match frame size 729 MOVW R4, (g_sched+gobuf_sp)(g) 730 731 // Switch back to m->g0's stack and restore m->g0->sched.sp. 732 // (Unlike m->curg, the g0 goroutine never uses sched.pc, 733 // so we do not have to restore it.) 734 MOVW g_m(g), R8 735 MOVW m_g0(R8), R0 736 BL setg<>(SB) 737 MOVW (g_sched+gobuf_sp)(g), R13 738 MOVW savedsp-12(SP), R4 // must match frame size 739 MOVW R4, (g_sched+gobuf_sp)(g) 740 741 // If the m on entry was nil, we called needm above to borrow an m 742 // for the duration of the call. Since the call is over, return it with dropm. 743 MOVW savedm-4(SP), R6 744 CMP $0, R6 745 B.NE 3(PC) 746 MOVW $runtime·dropm(SB), R0 747 BL (R0) 748 749 // Done! 750 RET 751 752 // void setg(G*); set g. for use by needm. 753 TEXT runtime·setg(SB),NOSPLIT|NOFRAME,$0-4 754 MOVW gg+0(FP), R0 755 B setg<>(SB) 756 757 TEXT setg<>(SB),NOSPLIT|NOFRAME,$0-0 758 MOVW R0, g 759 760 // Save g to thread-local storage. 761 #ifdef GOOS_windows 762 B runtime·save_g(SB) 763 #else 764 MOVB runtime·iscgo(SB), R0 765 CMP $0, R0 766 B.EQ 2(PC) 767 B runtime·save_g(SB) 768 769 MOVW g, R0 770 RET 771 #endif 772 773 TEXT runtime·emptyfunc(SB),0,$0-0 774 RET 775 776 TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0 777 MOVW $0, R0 778 MOVW (R0), R1 779 780 // armPublicationBarrier is a native store/store barrier for ARMv7+. 781 // On earlier ARM revisions, armPublicationBarrier is a no-op. 782 // This will not work on SMP ARMv6 machines, if any are in use. 783 // To implement publicationBarrier in sys_$GOOS_arm.s using the native 784 // instructions, use: 785 // 786 // TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-0 787 // B runtime·armPublicationBarrier(SB) 788 // 789 TEXT runtime·armPublicationBarrier(SB),NOSPLIT|NOFRAME,$0-0 790 MOVB runtime·goarm(SB), R11 791 CMP $7, R11 792 BLT 2(PC) 793 DMB MB_ST 794 RET 795 796 // AES hashing not implemented for ARM 797 TEXT runtime·memhash(SB),NOSPLIT|NOFRAME,$0-16 798 JMP runtime·memhashFallback(SB) 799 TEXT runtime·strhash(SB),NOSPLIT|NOFRAME,$0-12 800 JMP runtime·strhashFallback(SB) 801 TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-12 802 JMP runtime·memhash32Fallback(SB) 803 TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-12 804 JMP runtime·memhash64Fallback(SB) 805 806 TEXT runtime·return0(SB),NOSPLIT,$0 807 MOVW $0, R0 808 RET 809 810 TEXT runtime·procyield(SB),NOSPLIT|NOFRAME,$0 811 MOVW cycles+0(FP), R1 812 MOVW $0, R0 813 yieldloop: 814 WORD $0xe320f001 // YIELD (NOP pre-ARMv6K) 815 CMP R0, R1 816 B.NE 2(PC) 817 RET 818 SUB $1, R1 819 B yieldloop 820 821 // Called from cgo wrappers, this function returns g->m->curg.stack.hi. 822 // Must obey the gcc calling convention. 823 TEXT _cgo_topofstack(SB),NOSPLIT,$8 824 // R11 and g register are clobbered by load_g. They are 825 // callee-save in the gcc calling convention, so save them here. 826 MOVW R11, saveR11-4(SP) 827 MOVW g, saveG-8(SP) 828 829 BL runtime·load_g(SB) 830 MOVW g_m(g), R0 831 MOVW m_curg(R0), R0 832 MOVW (g_stack+stack_hi)(R0), R0 833 834 MOVW saveG-8(SP), g 835 MOVW saveR11-4(SP), R11 836 RET 837 838 // The top-most function running on a goroutine 839 // returns to goexit+PCQuantum. 840 TEXT runtime·goexit(SB),NOSPLIT|NOFRAME|TOPFRAME,$0-0 841 MOVW R0, R0 // NOP 842 BL runtime·goexit1(SB) // does not return 843 // traceback from goexit1 must hit code range of goexit 844 MOVW R0, R0 // NOP 845 846 // x -> x/1000000, x%1000000, called from Go with args, results on stack. 847 TEXT runtime·usplit(SB),NOSPLIT,$0-12 848 MOVW x+0(FP), R0 849 CALL runtime·usplitR0(SB) 850 MOVW R0, q+4(FP) 851 MOVW R1, r+8(FP) 852 RET 853 854 // R0, R1 = R0/1000000, R0%1000000 855 TEXT runtime·usplitR0(SB),NOSPLIT,$0 856 // magic multiply to avoid software divide without available m. 857 // see output of go tool compile -S for x/1000000. 858 MOVW R0, R3 859 MOVW $1125899907, R1 860 MULLU R1, R0, (R0, R1) 861 MOVW R0>>18, R0 862 MOVW $1000000, R1 863 MULU R0, R1 864 SUB R1, R3, R1 865 RET 866 867 // This is called from .init_array and follows the platform, not Go, ABI. 868 TEXT runtime·addmoduledata(SB),NOSPLIT,$0-0 869 MOVW R9, saver9-4(SP) // The access to global variables below implicitly uses R9, which is callee-save 870 MOVW R11, saver11-8(SP) // Likewise, R11 is the temp register, but callee-save in C ABI 871 MOVW runtime·lastmoduledatap(SB), R1 872 MOVW R0, moduledata_next(R1) 873 MOVW R0, runtime·lastmoduledatap(SB) 874 MOVW saver11-8(SP), R11 875 MOVW saver9-4(SP), R9 876 RET 877 878 TEXT ·checkASM(SB),NOSPLIT,$0-1 879 MOVW $1, R3 880 MOVB R3, ret+0(FP) 881 RET 882 883 // gcWriteBarrier performs a heap pointer write and informs the GC. 884 // 885 // gcWriteBarrier does NOT follow the Go ABI. It takes two arguments: 886 // - R2 is the destination of the write 887 // - R3 is the value being written at R2 888 // It clobbers condition codes. 889 // It does not clobber any other general-purpose registers, 890 // but may clobber others (e.g., floating point registers). 891 // The act of CALLing gcWriteBarrier will clobber R14 (LR). 892 TEXT runtime·gcWriteBarrier(SB),NOSPLIT|NOFRAME,$0 893 // Save the registers clobbered by the fast path. 894 MOVM.DB.W [R0,R1], (R13) 895 MOVW g_m(g), R0 896 MOVW m_p(R0), R0 897 MOVW (p_wbBuf+wbBuf_next)(R0), R1 898 // Increment wbBuf.next position. 899 ADD $8, R1 900 MOVW R1, (p_wbBuf+wbBuf_next)(R0) 901 MOVW (p_wbBuf+wbBuf_end)(R0), R0 902 CMP R1, R0 903 // Record the write. 904 MOVW R3, -8(R1) // Record value 905 MOVW (R2), R0 // TODO: This turns bad writes into bad reads. 906 MOVW R0, -4(R1) // Record *slot 907 // Is the buffer full? (flags set in CMP above) 908 B.EQ flush 909 ret: 910 MOVM.IA.W (R13), [R0,R1] 911 // Do the write. 912 MOVW R3, (R2) 913 RET 914 915 flush: 916 // Save all general purpose registers since these could be 917 // clobbered by wbBufFlush and were not saved by the caller. 918 // 919 // R0 and R1 were saved at entry. 920 // R10 is g, so preserved. 921 // R11 is linker temp, so no need to save. 922 // R13 is stack pointer. 923 // R15 is PC. 924 // 925 // This also sets up R2 and R3 as the arguments to wbBufFlush. 926 MOVM.DB.W [R2-R9,R12], (R13) 927 // Save R14 (LR) because the fast path above doesn't save it, 928 // but needs it to RET. This is after the MOVM so it appears below 929 // the arguments in the stack frame. 930 MOVM.DB.W [R14], (R13) 931 932 // This takes arguments R2 and R3. 933 CALL runtime·wbBufFlush(SB) 934 935 MOVM.IA.W (R13), [R14] 936 MOVM.IA.W (R13), [R2-R9,R12] 937 JMP ret 938 939 // Note: these functions use a special calling convention to save generated code space. 940 // Arguments are passed in registers, but the space for those arguments are allocated 941 // in the caller's stack frame. These stubs write the args into that stack space and 942 // then tail call to the corresponding runtime handler. 943 // The tail call makes these stubs disappear in backtraces. 944 TEXT runtime·panicIndex(SB),NOSPLIT,$0-8 945 MOVW R0, x+0(FP) 946 MOVW R1, y+4(FP) 947 JMP runtime·goPanicIndex(SB) 948 TEXT runtime·panicIndexU(SB),NOSPLIT,$0-8 949 MOVW R0, x+0(FP) 950 MOVW R1, y+4(FP) 951 JMP runtime·goPanicIndexU(SB) 952 TEXT runtime·panicSliceAlen(SB),NOSPLIT,$0-8 953 MOVW R1, x+0(FP) 954 MOVW R2, y+4(FP) 955 JMP runtime·goPanicSliceAlen(SB) 956 TEXT runtime·panicSliceAlenU(SB),NOSPLIT,$0-8 957 MOVW R1, x+0(FP) 958 MOVW R2, y+4(FP) 959 JMP runtime·goPanicSliceAlenU(SB) 960 TEXT runtime·panicSliceAcap(SB),NOSPLIT,$0-8 961 MOVW R1, x+0(FP) 962 MOVW R2, y+4(FP) 963 JMP runtime·goPanicSliceAcap(SB) 964 TEXT runtime·panicSliceAcapU(SB),NOSPLIT,$0-8 965 MOVW R1, x+0(FP) 966 MOVW R2, y+4(FP) 967 JMP runtime·goPanicSliceAcapU(SB) 968 TEXT runtime·panicSliceB(SB),NOSPLIT,$0-8 969 MOVW R0, x+0(FP) 970 MOVW R1, y+4(FP) 971 JMP runtime·goPanicSliceB(SB) 972 TEXT runtime·panicSliceBU(SB),NOSPLIT,$0-8 973 MOVW R0, x+0(FP) 974 MOVW R1, y+4(FP) 975 JMP runtime·goPanicSliceBU(SB) 976 TEXT runtime·panicSlice3Alen(SB),NOSPLIT,$0-8 977 MOVW R2, x+0(FP) 978 MOVW R3, y+4(FP) 979 JMP runtime·goPanicSlice3Alen(SB) 980 TEXT runtime·panicSlice3AlenU(SB),NOSPLIT,$0-8 981 MOVW R2, x+0(FP) 982 MOVW R3, y+4(FP) 983 JMP runtime·goPanicSlice3AlenU(SB) 984 TEXT runtime·panicSlice3Acap(SB),NOSPLIT,$0-8 985 MOVW R2, x+0(FP) 986 MOVW R3, y+4(FP) 987 JMP runtime·goPanicSlice3Acap(SB) 988 TEXT runtime·panicSlice3AcapU(SB),NOSPLIT,$0-8 989 MOVW R2, x+0(FP) 990 MOVW R3, y+4(FP) 991 JMP runtime·goPanicSlice3AcapU(SB) 992 TEXT runtime·panicSlice3B(SB),NOSPLIT,$0-8 993 MOVW R1, x+0(FP) 994 MOVW R2, y+4(FP) 995 JMP runtime·goPanicSlice3B(SB) 996 TEXT runtime·panicSlice3BU(SB),NOSPLIT,$0-8 997 MOVW R1, x+0(FP) 998 MOVW R2, y+4(FP) 999 JMP runtime·goPanicSlice3BU(SB) 1000 TEXT runtime·panicSlice3C(SB),NOSPLIT,$0-8 1001 MOVW R0, x+0(FP) 1002 MOVW R1, y+4(FP) 1003 JMP runtime·goPanicSlice3C(SB) 1004 TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-8 1005 MOVW R0, x+0(FP) 1006 MOVW R1, y+4(FP) 1007 JMP runtime·goPanicSlice3CU(SB) 1008 1009 // Extended versions for 64-bit indexes. 1010 TEXT runtime·panicExtendIndex(SB),NOSPLIT,$0-12 1011 MOVW R4, hi+0(FP) 1012 MOVW R0, lo+4(FP) 1013 MOVW R1, y+8(FP) 1014 JMP runtime·goPanicExtendIndex(SB) 1015 TEXT runtime·panicExtendIndexU(SB),NOSPLIT,$0-12 1016 MOVW R4, hi+0(FP) 1017 MOVW R0, lo+4(FP) 1018 MOVW R1, y+8(FP) 1019 JMP runtime·goPanicExtendIndexU(SB) 1020 TEXT runtime·panicExtendSliceAlen(SB),NOSPLIT,$0-12 1021 MOVW R4, hi+0(FP) 1022 MOVW R1, lo+4(FP) 1023 MOVW R2, y+8(FP) 1024 JMP runtime·goPanicExtendSliceAlen(SB) 1025 TEXT runtime·panicExtendSliceAlenU(SB),NOSPLIT,$0-12 1026 MOVW R4, hi+0(FP) 1027 MOVW R1, lo+4(FP) 1028 MOVW R2, y+8(FP) 1029 JMP runtime·goPanicExtendSliceAlenU(SB) 1030 TEXT runtime·panicExtendSliceAcap(SB),NOSPLIT,$0-12 1031 MOVW R4, hi+0(FP) 1032 MOVW R1, lo+4(FP) 1033 MOVW R2, y+8(FP) 1034 JMP runtime·goPanicExtendSliceAcap(SB) 1035 TEXT runtime·panicExtendSliceAcapU(SB),NOSPLIT,$0-12 1036 MOVW R4, hi+0(FP) 1037 MOVW R1, lo+4(FP) 1038 MOVW R2, y+8(FP) 1039 JMP runtime·goPanicExtendSliceAcapU(SB) 1040 TEXT runtime·panicExtendSliceB(SB),NOSPLIT,$0-12 1041 MOVW R4, hi+0(FP) 1042 MOVW R0, lo+4(FP) 1043 MOVW R1, y+8(FP) 1044 JMP runtime·goPanicExtendSliceB(SB) 1045 TEXT runtime·panicExtendSliceBU(SB),NOSPLIT,$0-12 1046 MOVW R4, hi+0(FP) 1047 MOVW R0, lo+4(FP) 1048 MOVW R1, y+8(FP) 1049 JMP runtime·goPanicExtendSliceBU(SB) 1050 TEXT runtime·panicExtendSlice3Alen(SB),NOSPLIT,$0-12 1051 MOVW R4, hi+0(FP) 1052 MOVW R2, lo+4(FP) 1053 MOVW R3, y+8(FP) 1054 JMP runtime·goPanicExtendSlice3Alen(SB) 1055 TEXT runtime·panicExtendSlice3AlenU(SB),NOSPLIT,$0-12 1056 MOVW R4, hi+0(FP) 1057 MOVW R2, lo+4(FP) 1058 MOVW R3, y+8(FP) 1059 JMP runtime·goPanicExtendSlice3AlenU(SB) 1060 TEXT runtime·panicExtendSlice3Acap(SB),NOSPLIT,$0-12 1061 MOVW R4, hi+0(FP) 1062 MOVW R2, lo+4(FP) 1063 MOVW R3, y+8(FP) 1064 JMP runtime·goPanicExtendSlice3Acap(SB) 1065 TEXT runtime·panicExtendSlice3AcapU(SB),NOSPLIT,$0-12 1066 MOVW R4, hi+0(FP) 1067 MOVW R2, lo+4(FP) 1068 MOVW R3, y+8(FP) 1069 JMP runtime·goPanicExtendSlice3AcapU(SB) 1070 TEXT runtime·panicExtendSlice3B(SB),NOSPLIT,$0-12 1071 MOVW R4, hi+0(FP) 1072 MOVW R1, lo+4(FP) 1073 MOVW R2, y+8(FP) 1074 JMP runtime·goPanicExtendSlice3B(SB) 1075 TEXT runtime·panicExtendSlice3BU(SB),NOSPLIT,$0-12 1076 MOVW R4, hi+0(FP) 1077 MOVW R1, lo+4(FP) 1078 MOVW R2, y+8(FP) 1079 JMP runtime·goPanicExtendSlice3BU(SB) 1080 TEXT runtime·panicExtendSlice3C(SB),NOSPLIT,$0-12 1081 MOVW R4, hi+0(FP) 1082 MOVW R0, lo+4(FP) 1083 MOVW R1, y+8(FP) 1084 JMP runtime·goPanicExtendSlice3C(SB) 1085 TEXT runtime·panicExtendSlice3CU(SB),NOSPLIT,$0-12 1086 MOVW R4, hi+0(FP) 1087 MOVW R0, lo+4(FP) 1088 MOVW R1, y+8(FP) 1089 JMP runtime·goPanicExtendSlice3CU(SB)