github.com/dannin/go@v0.0.0-20161031215817-d35dfd405eaa/src/runtime/asm_arm64.s (about) 1 // Copyright 2015 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 "tls_arm64.h" 8 #include "funcdata.h" 9 #include "textflag.h" 10 11 TEXT runtime·rt0_go(SB),NOSPLIT,$0 12 // SP = stack; R0 = argc; R1 = argv 13 14 SUB $32, RSP 15 MOVW R0, 8(RSP) // argc 16 MOVD R1, 16(RSP) // argv 17 18 // create istack out of the given (operating system) stack. 19 // _cgo_init may update stackguard. 20 MOVD $runtime·g0(SB), g 21 MOVD RSP, R7 22 MOVD $(-64*1024)(R7), R0 23 MOVD R0, g_stackguard0(g) 24 MOVD R0, g_stackguard1(g) 25 MOVD R0, (g_stack+stack_lo)(g) 26 MOVD R7, (g_stack+stack_hi)(g) 27 28 // if there is a _cgo_init, call it using the gcc ABI. 29 MOVD _cgo_init(SB), R12 30 CMP $0, R12 31 BEQ nocgo 32 33 MRS_TPIDR_R0 // load TLS base pointer 34 MOVD R0, R3 // arg 3: TLS base pointer 35 #ifdef TLSG_IS_VARIABLE 36 MOVD $runtime·tls_g(SB), R2 // arg 2: &tls_g 37 #else 38 MOVD $0, R2 // arg 2: not used when using platform's TLS 39 #endif 40 MOVD $setg_gcc<>(SB), R1 // arg 1: setg 41 MOVD g, R0 // arg 0: G 42 BL (R12) 43 MOVD _cgo_init(SB), R12 44 CMP $0, R12 45 BEQ nocgo 46 47 nocgo: 48 // update stackguard after _cgo_init 49 MOVD (g_stack+stack_lo)(g), R0 50 ADD $const__StackGuard, R0 51 MOVD R0, g_stackguard0(g) 52 MOVD R0, g_stackguard1(g) 53 54 // set the per-goroutine and per-mach "registers" 55 MOVD $runtime·m0(SB), R0 56 57 // save m->g0 = g0 58 MOVD g, m_g0(R0) 59 // save m0 to g0->m 60 MOVD R0, g_m(g) 61 62 BL runtime·check(SB) 63 64 MOVW 8(RSP), R0 // copy argc 65 MOVW R0, -8(RSP) 66 MOVD 16(RSP), R0 // copy argv 67 MOVD R0, 0(RSP) 68 BL runtime·args(SB) 69 BL runtime·osinit(SB) 70 BL runtime·schedinit(SB) 71 72 // create a new goroutine to start program 73 MOVD $runtime·mainPC(SB), R0 // entry 74 MOVD RSP, R7 75 MOVD.W $0, -8(R7) 76 MOVD.W R0, -8(R7) 77 MOVD.W $0, -8(R7) 78 MOVD.W $0, -8(R7) 79 MOVD R7, RSP 80 BL runtime·newproc(SB) 81 ADD $32, RSP 82 83 // start this M 84 BL runtime·mstart(SB) 85 86 MOVD $0, R0 87 MOVD R0, (R0) // boom 88 UNDEF 89 90 DATA runtime·mainPC+0(SB)/8,$runtime·main(SB) 91 GLOBL runtime·mainPC(SB),RODATA,$8 92 93 TEXT runtime·breakpoint(SB),NOSPLIT,$-8-0 94 BRK 95 RET 96 97 TEXT runtime·asminit(SB),NOSPLIT,$-8-0 98 RET 99 100 /* 101 * go-routine 102 */ 103 104 // void gosave(Gobuf*) 105 // save state in Gobuf; setjmp 106 TEXT runtime·gosave(SB), NOSPLIT, $-8-8 107 MOVD buf+0(FP), R3 108 MOVD RSP, R0 109 MOVD R0, gobuf_sp(R3) 110 MOVD LR, gobuf_pc(R3) 111 MOVD g, gobuf_g(R3) 112 MOVD ZR, gobuf_lr(R3) 113 MOVD ZR, gobuf_ret(R3) 114 // Assert ctxt is zero. See func save. 115 MOVD gobuf_ctxt(R3), R0 116 CMP $0, R0 117 BEQ 2(PC) 118 CALL runtime·badctxt(SB) 119 RET 120 121 // void gogo(Gobuf*) 122 // restore state from Gobuf; longjmp 123 TEXT runtime·gogo(SB), NOSPLIT, $24-8 124 MOVD buf+0(FP), R5 125 126 // If ctxt is not nil, invoke deletion barrier before overwriting. 127 MOVD gobuf_ctxt(R5), R0 128 CMP $0, R0 129 BEQ nilctxt 130 MOVD $gobuf_ctxt(R5), R0 131 MOVD R0, 8(RSP) 132 MOVD ZR, 16(RSP) 133 BL runtime·writebarrierptr_prewrite(SB) 134 MOVD buf+0(FP), R5 135 136 nilctxt: 137 MOVD gobuf_g(R5), g 138 BL runtime·save_g(SB) 139 140 MOVD 0(g), R4 // make sure g is not nil 141 MOVD gobuf_sp(R5), R0 142 MOVD R0, RSP 143 MOVD gobuf_lr(R5), LR 144 MOVD gobuf_ret(R5), R0 145 MOVD gobuf_ctxt(R5), R26 146 MOVD $0, gobuf_sp(R5) 147 MOVD $0, gobuf_ret(R5) 148 MOVD $0, gobuf_lr(R5) 149 MOVD $0, gobuf_ctxt(R5) 150 CMP ZR, ZR // set condition codes for == test, needed by stack split 151 MOVD gobuf_pc(R5), R6 152 B (R6) 153 154 // void mcall(fn func(*g)) 155 // Switch to m->g0's stack, call fn(g). 156 // Fn must never return. It should gogo(&g->sched) 157 // to keep running g. 158 TEXT runtime·mcall(SB), NOSPLIT, $-8-8 159 // Save caller state in g->sched 160 MOVD RSP, R0 161 MOVD R0, (g_sched+gobuf_sp)(g) 162 MOVD LR, (g_sched+gobuf_pc)(g) 163 MOVD $0, (g_sched+gobuf_lr)(g) 164 MOVD g, (g_sched+gobuf_g)(g) 165 166 // Switch to m->g0 & its stack, call fn. 167 MOVD g, R3 168 MOVD g_m(g), R8 169 MOVD m_g0(R8), g 170 BL runtime·save_g(SB) 171 CMP g, R3 172 BNE 2(PC) 173 B runtime·badmcall(SB) 174 MOVD fn+0(FP), R26 // context 175 MOVD 0(R26), R4 // code pointer 176 MOVD (g_sched+gobuf_sp)(g), R0 177 MOVD R0, RSP // sp = m->g0->sched.sp 178 MOVD R3, -8(RSP) 179 MOVD $0, -16(RSP) 180 SUB $16, RSP 181 BL (R4) 182 B runtime·badmcall2(SB) 183 184 // systemstack_switch is a dummy routine that systemstack leaves at the bottom 185 // of the G stack. We need to distinguish the routine that 186 // lives at the bottom of the G stack from the one that lives 187 // at the top of the system stack because the one at the top of 188 // the system stack terminates the stack walk (see topofstack()). 189 TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0 190 UNDEF 191 BL (LR) // make sure this function is not leaf 192 RET 193 194 // func systemstack(fn func()) 195 TEXT runtime·systemstack(SB), NOSPLIT, $0-8 196 MOVD fn+0(FP), R3 // R3 = fn 197 MOVD R3, R26 // context 198 MOVD g_m(g), R4 // R4 = m 199 200 MOVD m_gsignal(R4), R5 // R5 = gsignal 201 CMP g, R5 202 BEQ noswitch 203 204 MOVD m_g0(R4), R5 // R5 = g0 205 CMP g, R5 206 BEQ noswitch 207 208 MOVD m_curg(R4), R6 209 CMP g, R6 210 BEQ switch 211 212 // Bad: g is not gsignal, not g0, not curg. What is it? 213 // Hide call from linker nosplit analysis. 214 MOVD $runtime·badsystemstack(SB), R3 215 BL (R3) 216 217 switch: 218 // save our state in g->sched. Pretend to 219 // be systemstack_switch if the G stack is scanned. 220 MOVD $runtime·systemstack_switch(SB), R6 221 ADD $8, R6 // get past prologue 222 MOVD R6, (g_sched+gobuf_pc)(g) 223 MOVD RSP, R0 224 MOVD R0, (g_sched+gobuf_sp)(g) 225 MOVD $0, (g_sched+gobuf_lr)(g) 226 MOVD g, (g_sched+gobuf_g)(g) 227 228 // switch to g0 229 MOVD R5, g 230 BL runtime·save_g(SB) 231 MOVD (g_sched+gobuf_sp)(g), R3 232 // make it look like mstart called systemstack on g0, to stop traceback 233 SUB $16, R3 234 AND $~15, R3 235 MOVD $runtime·mstart(SB), R4 236 MOVD R4, 0(R3) 237 MOVD R3, RSP 238 239 // call target function 240 MOVD 0(R26), R3 // code pointer 241 BL (R3) 242 243 // switch back to g 244 MOVD g_m(g), R3 245 MOVD m_curg(R3), g 246 BL runtime·save_g(SB) 247 MOVD (g_sched+gobuf_sp)(g), R0 248 MOVD R0, RSP 249 MOVD $0, (g_sched+gobuf_sp)(g) 250 RET 251 252 noswitch: 253 // already on m stack, just call directly 254 MOVD 0(R26), R3 // code pointer 255 BL (R3) 256 RET 257 258 /* 259 * support for morestack 260 */ 261 262 // Called during function prolog when more stack is needed. 263 // Caller has already loaded: 264 // R3 prolog's LR (R30) 265 // 266 // The traceback routines see morestack on a g0 as being 267 // the top of a stack (for example, morestack calling newstack 268 // calling the scheduler calling newm calling gc), so we must 269 // record an argument size. For that purpose, it has no arguments. 270 TEXT runtime·morestack(SB),NOSPLIT,$-8-0 271 // Cannot grow scheduler stack (m->g0). 272 MOVD g_m(g), R8 273 MOVD m_g0(R8), R4 274 CMP g, R4 275 BNE 3(PC) 276 BL runtime·badmorestackg0(SB) 277 B runtime·abort(SB) 278 279 // Cannot grow signal stack (m->gsignal). 280 MOVD m_gsignal(R8), R4 281 CMP g, R4 282 BNE 3(PC) 283 BL runtime·badmorestackgsignal(SB) 284 B runtime·abort(SB) 285 286 // Called from f. 287 // Set g->sched to context in f 288 MOVD RSP, R0 289 MOVD R0, (g_sched+gobuf_sp)(g) 290 MOVD LR, (g_sched+gobuf_pc)(g) 291 MOVD R3, (g_sched+gobuf_lr)(g) 292 // newstack will fill gobuf.ctxt. 293 294 // Called from f. 295 // Set m->morebuf to f's callers. 296 MOVD R3, (m_morebuf+gobuf_pc)(R8) // f's caller's PC 297 MOVD RSP, R0 298 MOVD R0, (m_morebuf+gobuf_sp)(R8) // f's caller's RSP 299 MOVD g, (m_morebuf+gobuf_g)(R8) 300 301 // Call newstack on m->g0's stack. 302 MOVD m_g0(R8), g 303 BL runtime·save_g(SB) 304 MOVD (g_sched+gobuf_sp)(g), R0 305 MOVD R0, RSP 306 MOVD.W $0, -16(RSP) // create a call frame on g0 307 MOVD R26, 8(RSP) // ctxt argument 308 BL runtime·newstack(SB) 309 310 // Not reached, but make sure the return PC from the call to newstack 311 // is still in this function, and not the beginning of the next. 312 UNDEF 313 314 TEXT runtime·morestack_noctxt(SB),NOSPLIT,$-4-0 315 MOVW $0, R26 316 B runtime·morestack(SB) 317 318 TEXT runtime·stackBarrier(SB),NOSPLIT,$0 319 // We came here via a RET to an overwritten LR. 320 // R0 may be live (see return0). Other registers are available. 321 322 // Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal. 323 MOVD (g_stkbar+slice_array)(g), R4 324 MOVD g_stkbarPos(g), R5 325 MOVD $stkbar__size, R6 326 MUL R5, R6 327 ADD R4, R6 328 MOVD stkbar_savedLRVal(R6), R6 329 // Record that this stack barrier was hit. 330 ADD $1, R5 331 MOVD R5, g_stkbarPos(g) 332 // Jump to the original return PC. 333 B (R6) 334 335 // reflectcall: call a function with the given argument list 336 // func call(argtype *_type, f *FuncVal, arg *byte, argsize, retoffset uint32). 337 // we don't have variable-sized frames, so we use a small number 338 // of constant-sized-frame functions to encode a few bits of size in the pc. 339 // Caution: ugly multiline assembly macros in your future! 340 341 #define DISPATCH(NAME,MAXSIZE) \ 342 MOVD $MAXSIZE, R27; \ 343 CMP R27, R16; \ 344 BGT 3(PC); \ 345 MOVD $NAME(SB), R27; \ 346 B (R27) 347 // Note: can't just "B NAME(SB)" - bad inlining results. 348 349 TEXT reflect·call(SB), NOSPLIT, $0-0 350 B ·reflectcall(SB) 351 352 TEXT ·reflectcall(SB), NOSPLIT, $-8-32 353 MOVWU argsize+24(FP), R16 354 DISPATCH(runtime·call32, 32) 355 DISPATCH(runtime·call64, 64) 356 DISPATCH(runtime·call128, 128) 357 DISPATCH(runtime·call256, 256) 358 DISPATCH(runtime·call512, 512) 359 DISPATCH(runtime·call1024, 1024) 360 DISPATCH(runtime·call2048, 2048) 361 DISPATCH(runtime·call4096, 4096) 362 DISPATCH(runtime·call8192, 8192) 363 DISPATCH(runtime·call16384, 16384) 364 DISPATCH(runtime·call32768, 32768) 365 DISPATCH(runtime·call65536, 65536) 366 DISPATCH(runtime·call131072, 131072) 367 DISPATCH(runtime·call262144, 262144) 368 DISPATCH(runtime·call524288, 524288) 369 DISPATCH(runtime·call1048576, 1048576) 370 DISPATCH(runtime·call2097152, 2097152) 371 DISPATCH(runtime·call4194304, 4194304) 372 DISPATCH(runtime·call8388608, 8388608) 373 DISPATCH(runtime·call16777216, 16777216) 374 DISPATCH(runtime·call33554432, 33554432) 375 DISPATCH(runtime·call67108864, 67108864) 376 DISPATCH(runtime·call134217728, 134217728) 377 DISPATCH(runtime·call268435456, 268435456) 378 DISPATCH(runtime·call536870912, 536870912) 379 DISPATCH(runtime·call1073741824, 1073741824) 380 MOVD $runtime·badreflectcall(SB), R0 381 B (R0) 382 383 #define CALLFN(NAME,MAXSIZE) \ 384 TEXT NAME(SB), WRAPPER, $MAXSIZE-24; \ 385 NO_LOCAL_POINTERS; \ 386 /* copy arguments to stack */ \ 387 MOVD arg+16(FP), R3; \ 388 MOVWU argsize+24(FP), R4; \ 389 MOVD RSP, R5; \ 390 ADD $(8-1), R5; \ 391 SUB $1, R3; \ 392 ADD R5, R4; \ 393 CMP R5, R4; \ 394 BEQ 4(PC); \ 395 MOVBU.W 1(R3), R6; \ 396 MOVBU.W R6, 1(R5); \ 397 B -4(PC); \ 398 /* call function */ \ 399 MOVD f+8(FP), R26; \ 400 MOVD (R26), R0; \ 401 PCDATA $PCDATA_StackMapIndex, $0; \ 402 BL (R0); \ 403 /* copy return values back */ \ 404 MOVD argtype+0(FP), R7; \ 405 MOVD arg+16(FP), R3; \ 406 MOVWU n+24(FP), R4; \ 407 MOVWU retoffset+28(FP), R6; \ 408 ADD $8, RSP, R5; \ 409 ADD R6, R5; \ 410 ADD R6, R3; \ 411 SUB R6, R4; \ 412 BL callRet<>(SB); \ 413 RET 414 415 // callRet copies return values back at the end of call*. This is a 416 // separate function so it can allocate stack space for the arguments 417 // to reflectcallmove. It does not follow the Go ABI; it expects its 418 // arguments in registers. 419 TEXT callRet<>(SB), NOSPLIT, $40-0 420 MOVD R7, 8(RSP) 421 MOVD R3, 16(RSP) 422 MOVD R5, 24(RSP) 423 MOVD R4, 32(RSP) 424 BL runtime·reflectcallmove(SB) 425 RET 426 427 // These have 8 added to make the overall frame size a multiple of 16, 428 // as required by the ABI. (There is another +8 for the saved LR.) 429 CALLFN(·call32, 40 ) 430 CALLFN(·call64, 72 ) 431 CALLFN(·call128, 136 ) 432 CALLFN(·call256, 264 ) 433 CALLFN(·call512, 520 ) 434 CALLFN(·call1024, 1032 ) 435 CALLFN(·call2048, 2056 ) 436 CALLFN(·call4096, 4104 ) 437 CALLFN(·call8192, 8200 ) 438 CALLFN(·call16384, 16392 ) 439 CALLFN(·call32768, 32776 ) 440 CALLFN(·call65536, 65544 ) 441 CALLFN(·call131072, 131080 ) 442 CALLFN(·call262144, 262152 ) 443 CALLFN(·call524288, 524296 ) 444 CALLFN(·call1048576, 1048584 ) 445 CALLFN(·call2097152, 2097160 ) 446 CALLFN(·call4194304, 4194312 ) 447 CALLFN(·call8388608, 8388616 ) 448 CALLFN(·call16777216, 16777224 ) 449 CALLFN(·call33554432, 33554440 ) 450 CALLFN(·call67108864, 67108872 ) 451 CALLFN(·call134217728, 134217736 ) 452 CALLFN(·call268435456, 268435464 ) 453 CALLFN(·call536870912, 536870920 ) 454 CALLFN(·call1073741824, 1073741832 ) 455 456 // AES hashing not implemented for ARM64, issue #10109. 457 TEXT runtime·aeshash(SB),NOSPLIT,$-8-0 458 MOVW $0, R0 459 MOVW (R0), R1 460 TEXT runtime·aeshash32(SB),NOSPLIT,$-8-0 461 MOVW $0, R0 462 MOVW (R0), R1 463 TEXT runtime·aeshash64(SB),NOSPLIT,$-8-0 464 MOVW $0, R0 465 MOVW (R0), R1 466 TEXT runtime·aeshashstr(SB),NOSPLIT,$-8-0 467 MOVW $0, R0 468 MOVW (R0), R1 469 470 TEXT runtime·procyield(SB),NOSPLIT,$0-0 471 MOVWU cycles+0(FP), R0 472 again: 473 YIELD 474 SUBW $1, R0 475 CBNZ R0, again 476 RET 477 478 // void jmpdefer(fv, sp); 479 // called from deferreturn. 480 // 1. grab stored LR for caller 481 // 2. sub 4 bytes to get back to BL deferreturn 482 // 3. BR to fn 483 TEXT runtime·jmpdefer(SB), NOSPLIT, $-8-16 484 MOVD 0(RSP), R0 485 SUB $4, R0 486 MOVD R0, LR 487 488 MOVD fv+0(FP), R26 489 MOVD argp+8(FP), R0 490 MOVD R0, RSP 491 SUB $8, RSP 492 MOVD 0(R26), R3 493 B (R3) 494 495 // Save state of caller into g->sched. Smashes R0. 496 TEXT gosave<>(SB),NOSPLIT,$-8 497 MOVD LR, (g_sched+gobuf_pc)(g) 498 MOVD RSP, R0 499 MOVD R0, (g_sched+gobuf_sp)(g) 500 MOVD $0, (g_sched+gobuf_lr)(g) 501 MOVD $0, (g_sched+gobuf_ret)(g) 502 // Assert ctxt is zero. See func save. 503 MOVD (g_sched+gobuf_ctxt)(g), R0 504 CMP $0, R0 505 BEQ 2(PC) 506 CALL runtime·badctxt(SB) 507 RET 508 509 // func asmcgocall(fn, arg unsafe.Pointer) int32 510 // Call fn(arg) on the scheduler stack, 511 // aligned appropriately for the gcc ABI. 512 // See cgocall.go for more details. 513 TEXT ·asmcgocall(SB),NOSPLIT,$0-20 514 MOVD fn+0(FP), R1 515 MOVD arg+8(FP), R0 516 517 MOVD RSP, R2 // save original stack pointer 518 MOVD g, R4 519 520 // Figure out if we need to switch to m->g0 stack. 521 // We get called to create new OS threads too, and those 522 // come in on the m->g0 stack already. 523 MOVD g_m(g), R8 524 MOVD m_g0(R8), R3 525 CMP R3, g 526 BEQ g0 527 MOVD R0, R9 // gosave<> and save_g might clobber R0 528 BL gosave<>(SB) 529 MOVD R3, g 530 BL runtime·save_g(SB) 531 MOVD (g_sched+gobuf_sp)(g), R0 532 MOVD R0, RSP 533 MOVD R9, R0 534 535 // Now on a scheduling stack (a pthread-created stack). 536 g0: 537 // Save room for two of our pointers /*, plus 32 bytes of callee 538 // save area that lives on the caller stack. */ 539 MOVD RSP, R13 540 SUB $16, R13 541 MOVD R13, RSP 542 MOVD R4, 0(RSP) // save old g on stack 543 MOVD (g_stack+stack_hi)(R4), R4 544 SUB R2, R4 545 MOVD R4, 8(RSP) // save depth in old g stack (can't just save SP, as stack might be copied during a callback) 546 BL (R1) 547 MOVD R0, R9 548 549 // Restore g, stack pointer. R0 is errno, so don't touch it 550 MOVD 0(RSP), g 551 BL runtime·save_g(SB) 552 MOVD (g_stack+stack_hi)(g), R5 553 MOVD 8(RSP), R6 554 SUB R6, R5 555 MOVD R9, R0 556 MOVD R5, RSP 557 558 MOVW R0, ret+16(FP) 559 RET 560 561 // cgocallback(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt) 562 // Turn the fn into a Go func (by taking its address) and call 563 // cgocallback_gofunc. 564 TEXT runtime·cgocallback(SB),NOSPLIT,$40-32 565 MOVD $fn+0(FP), R0 566 MOVD R0, 8(RSP) 567 MOVD frame+8(FP), R0 568 MOVD R0, 16(RSP) 569 MOVD framesize+16(FP), R0 570 MOVD R0, 24(RSP) 571 MOVD ctxt+24(FP), R0 572 MOVD R0, 32(RSP) 573 MOVD $runtime·cgocallback_gofunc(SB), R0 574 BL (R0) 575 RET 576 577 // cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize, uintptr ctxt) 578 // See cgocall.go for more details. 579 TEXT ·cgocallback_gofunc(SB),NOSPLIT,$24-32 580 NO_LOCAL_POINTERS 581 582 // Load g from thread-local storage. 583 MOVB runtime·iscgo(SB), R3 584 CMP $0, R3 585 BEQ nocgo 586 BL runtime·load_g(SB) 587 nocgo: 588 589 // If g is nil, Go did not create the current thread. 590 // Call needm to obtain one for temporary use. 591 // In this case, we're running on the thread stack, so there's 592 // lots of space, but the linker doesn't know. Hide the call from 593 // the linker analysis by using an indirect call. 594 CMP $0, g 595 BEQ needm 596 597 MOVD g_m(g), R8 598 MOVD R8, savedm-8(SP) 599 B havem 600 601 needm: 602 MOVD g, savedm-8(SP) // g is zero, so is m. 603 MOVD $runtime·needm(SB), R0 604 BL (R0) 605 606 // Set m->sched.sp = SP, so that if a panic happens 607 // during the function we are about to execute, it will 608 // have a valid SP to run on the g0 stack. 609 // The next few lines (after the havem label) 610 // will save this SP onto the stack and then write 611 // the same SP back to m->sched.sp. That seems redundant, 612 // but if an unrecovered panic happens, unwindm will 613 // restore the g->sched.sp from the stack location 614 // and then systemstack will try to use it. If we don't set it here, 615 // that restored SP will be uninitialized (typically 0) and 616 // will not be usable. 617 MOVD g_m(g), R8 618 MOVD m_g0(R8), R3 619 MOVD RSP, R0 620 MOVD R0, (g_sched+gobuf_sp)(R3) 621 622 havem: 623 // Now there's a valid m, and we're running on its m->g0. 624 // Save current m->g0->sched.sp on stack and then set it to SP. 625 // Save current sp in m->g0->sched.sp in preparation for 626 // switch back to m->curg stack. 627 // NOTE: unwindm knows that the saved g->sched.sp is at 16(RSP) aka savedsp-16(SP). 628 // Beware that the frame size is actually 32. 629 MOVD m_g0(R8), R3 630 MOVD (g_sched+gobuf_sp)(R3), R4 631 MOVD R4, savedsp-16(SP) 632 MOVD RSP, R0 633 MOVD R0, (g_sched+gobuf_sp)(R3) 634 635 // Switch to m->curg stack and call runtime.cgocallbackg. 636 // Because we are taking over the execution of m->curg 637 // but *not* resuming what had been running, we need to 638 // save that information (m->curg->sched) so we can restore it. 639 // We can restore m->curg->sched.sp easily, because calling 640 // runtime.cgocallbackg leaves SP unchanged upon return. 641 // To save m->curg->sched.pc, we push it onto the stack. 642 // This has the added benefit that it looks to the traceback 643 // routine like cgocallbackg is going to return to that 644 // PC (because the frame we allocate below has the same 645 // size as cgocallback_gofunc's frame declared above) 646 // so that the traceback will seamlessly trace back into 647 // the earlier calls. 648 // 649 // In the new goroutine, -8(SP) is unused (where SP refers to 650 // m->curg's SP while we're setting it up, before we've adjusted it). 651 MOVD m_curg(R8), g 652 BL runtime·save_g(SB) 653 MOVD (g_sched+gobuf_sp)(g), R4 // prepare stack as R4 654 MOVD (g_sched+gobuf_pc)(g), R5 655 MOVD R5, -(24+8)(R4) 656 MOVD ctxt+24(FP), R0 657 MOVD R0, -(16+8)(R4) 658 MOVD $-(24+8)(R4), R0 // maintain 16-byte SP alignment 659 MOVD R0, RSP 660 BL runtime·cgocallbackg(SB) 661 662 // Restore g->sched (== m->curg->sched) from saved values. 663 MOVD 0(RSP), R5 664 MOVD R5, (g_sched+gobuf_pc)(g) 665 MOVD RSP, R4 666 ADD $(24+8), R4, R4 667 MOVD R4, (g_sched+gobuf_sp)(g) 668 669 // Switch back to m->g0's stack and restore m->g0->sched.sp. 670 // (Unlike m->curg, the g0 goroutine never uses sched.pc, 671 // so we do not have to restore it.) 672 MOVD g_m(g), R8 673 MOVD m_g0(R8), g 674 BL runtime·save_g(SB) 675 MOVD (g_sched+gobuf_sp)(g), R0 676 MOVD R0, RSP 677 MOVD savedsp-16(SP), R4 678 MOVD R4, (g_sched+gobuf_sp)(g) 679 680 // If the m on entry was nil, we called needm above to borrow an m 681 // for the duration of the call. Since the call is over, return it with dropm. 682 MOVD savedm-8(SP), R6 683 CMP $0, R6 684 BNE droppedm 685 MOVD $runtime·dropm(SB), R0 686 BL (R0) 687 droppedm: 688 689 // Done! 690 RET 691 692 // Called from cgo wrappers, this function returns g->m->curg.stack.hi. 693 // Must obey the gcc calling convention. 694 TEXT _cgo_topofstack(SB),NOSPLIT,$24 695 // g (R28) and REGTMP (R27) might be clobbered by load_g. They 696 // are callee-save in the gcc calling convention, so save them. 697 MOVD R27, savedR27-8(SP) 698 MOVD g, saveG-16(SP) 699 700 BL runtime·load_g(SB) 701 MOVD g_m(g), R0 702 MOVD m_curg(R0), R0 703 MOVD (g_stack+stack_hi)(R0), R0 704 705 MOVD saveG-16(SP), g 706 MOVD savedR28-8(SP), R27 707 RET 708 709 // void setg(G*); set g. for use by needm. 710 TEXT runtime·setg(SB), NOSPLIT, $0-8 711 MOVD gg+0(FP), g 712 // This only happens if iscgo, so jump straight to save_g 713 BL runtime·save_g(SB) 714 RET 715 716 // void setg_gcc(G*); set g called from gcc 717 TEXT setg_gcc<>(SB),NOSPLIT,$8 718 MOVD R0, g 719 MOVD R27, savedR27-8(SP) 720 BL runtime·save_g(SB) 721 MOVD savedR27-8(SP), R27 722 RET 723 724 TEXT runtime·getcallerpc(SB),NOSPLIT,$8-16 725 MOVD 16(RSP), R0 // LR saved by caller 726 MOVD runtime·stackBarrierPC(SB), R1 727 CMP R0, R1 728 BNE nobar 729 // Get original return PC. 730 BL runtime·nextBarrierPC(SB) 731 MOVD 8(RSP), R0 732 nobar: 733 MOVD R0, ret+8(FP) 734 RET 735 736 TEXT runtime·setcallerpc(SB),NOSPLIT,$8-16 737 MOVD pc+8(FP), R0 738 MOVD 16(RSP), R1 739 MOVD runtime·stackBarrierPC(SB), R2 740 CMP R1, R2 741 BEQ setbar 742 MOVD R0, 16(RSP) // set LR in caller 743 RET 744 setbar: 745 // Set the stack barrier return PC. 746 MOVD R0, 8(RSP) 747 BL runtime·setNextBarrierPC(SB) 748 RET 749 750 TEXT runtime·abort(SB),NOSPLIT,$-8-0 751 B (ZR) 752 UNDEF 753 754 // memhash_varlen(p unsafe.Pointer, h seed) uintptr 755 // redirects to memhash(p, h, size) using the size 756 // stored in the closure. 757 TEXT runtime·memhash_varlen(SB),NOSPLIT,$40-24 758 GO_ARGS 759 NO_LOCAL_POINTERS 760 MOVD p+0(FP), R3 761 MOVD h+8(FP), R4 762 MOVD 8(R26), R5 763 MOVD R3, 8(RSP) 764 MOVD R4, 16(RSP) 765 MOVD R5, 24(RSP) 766 BL runtime·memhash(SB) 767 MOVD 32(RSP), R3 768 MOVD R3, ret+16(FP) 769 RET 770 771 // memequal(p, q unsafe.Pointer, size uintptr) bool 772 TEXT runtime·memequal(SB),NOSPLIT,$-8-25 773 MOVD a+0(FP), R1 774 MOVD b+8(FP), R2 775 MOVD size+16(FP), R3 776 ADD R1, R3, R6 777 MOVD $1, R0 778 MOVB R0, ret+24(FP) 779 CMP R1, R2 780 BEQ done 781 loop: 782 CMP R1, R6 783 BEQ done 784 MOVBU.P 1(R1), R4 785 MOVBU.P 1(R2), R5 786 CMP R4, R5 787 BEQ loop 788 789 MOVB $0, ret+24(FP) 790 done: 791 RET 792 793 // memequal_varlen(a, b unsafe.Pointer) bool 794 TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17 795 MOVD a+0(FP), R3 796 MOVD b+8(FP), R4 797 CMP R3, R4 798 BEQ eq 799 MOVD 8(R26), R5 // compiler stores size at offset 8 in the closure 800 MOVD R3, 8(RSP) 801 MOVD R4, 16(RSP) 802 MOVD R5, 24(RSP) 803 BL runtime·memequal(SB) 804 MOVBU 32(RSP), R3 805 MOVB R3, ret+16(FP) 806 RET 807 eq: 808 MOVD $1, R3 809 MOVB R3, ret+16(FP) 810 RET 811 812 TEXT runtime·cmpstring(SB),NOSPLIT,$-4-40 813 MOVD s1_base+0(FP), R2 814 MOVD s1_len+8(FP), R0 815 MOVD s2_base+16(FP), R3 816 MOVD s2_len+24(FP), R1 817 ADD $40, RSP, R7 818 B runtime·cmpbody<>(SB) 819 820 TEXT bytes·Compare(SB),NOSPLIT,$-4-56 821 MOVD s1+0(FP), R2 822 MOVD s1+8(FP), R0 823 MOVD s2+24(FP), R3 824 MOVD s2+32(FP), R1 825 ADD $56, RSP, R7 826 B runtime·cmpbody<>(SB) 827 828 // On entry: 829 // R0 is the length of s1 830 // R1 is the length of s2 831 // R2 points to the start of s1 832 // R3 points to the start of s2 833 // R7 points to return value (-1/0/1 will be written here) 834 // 835 // On exit: 836 // R4, R5, and R6 are clobbered 837 TEXT runtime·cmpbody<>(SB),NOSPLIT,$-4-0 838 CMP R2, R3 839 BEQ samebytes // same starting pointers; compare lengths 840 CMP R0, R1 841 CSEL LT, R1, R0, R6 // R6 is min(R0, R1) 842 843 ADD R2, R6 // R2 is current byte in s1, R6 is last byte in s1 to compare 844 loop: 845 CMP R2, R6 846 BEQ samebytes // all compared bytes were the same; compare lengths 847 MOVBU.P 1(R2), R4 848 MOVBU.P 1(R3), R5 849 CMP R4, R5 850 BEQ loop 851 // bytes differed 852 MOVD $1, R4 853 CSNEG LT, R4, R4, R4 854 MOVD R4, (R7) 855 RET 856 samebytes: 857 MOVD $1, R4 858 CMP R0, R1 859 CSNEG LT, R4, R4, R4 860 CSEL EQ, ZR, R4, R4 861 MOVD R4, (R7) 862 RET 863 864 // eqstring tests whether two strings are equal. 865 // The compiler guarantees that strings passed 866 // to eqstring have equal length. 867 // See runtime_test.go:eqstring_generic for 868 // equivalent Go code. 869 TEXT runtime·eqstring(SB),NOSPLIT,$0-33 870 MOVD s1_base+0(FP), R0 871 MOVD s1_len+8(FP), R1 872 MOVD s2_base+16(FP), R2 873 ADD R0, R1 // end 874 loop: 875 CMP R0, R1 876 BEQ equal // reaches the end 877 MOVBU.P 1(R0), R4 878 MOVBU.P 1(R2), R5 879 CMP R4, R5 880 BEQ loop 881 notequal: 882 MOVB ZR, ret+32(FP) 883 RET 884 equal: 885 MOVD $1, R0 886 MOVB R0, ret+32(FP) 887 RET 888 889 // 890 // functions for other packages 891 // 892 TEXT bytes·IndexByte(SB),NOSPLIT,$0-40 893 MOVD b+0(FP), R0 894 MOVD b_len+8(FP), R1 895 MOVBU c+24(FP), R2 // byte to find 896 MOVD R0, R4 // store base for later 897 ADD R0, R1 // end 898 loop: 899 CMP R0, R1 900 BEQ notfound 901 MOVBU.P 1(R0), R3 902 CMP R2, R3 903 BNE loop 904 905 SUB $1, R0 // R0 will be one beyond the position we want 906 SUB R4, R0 // remove base 907 MOVD R0, ret+32(FP) 908 RET 909 910 notfound: 911 MOVD $-1, R0 912 MOVD R0, ret+32(FP) 913 RET 914 915 TEXT strings·IndexByte(SB),NOSPLIT,$0-32 916 MOVD s+0(FP), R0 917 MOVD s_len+8(FP), R1 918 MOVBU c+16(FP), R2 // byte to find 919 MOVD R0, R4 // store base for later 920 ADD R0, R1 // end 921 loop: 922 CMP R0, R1 923 BEQ notfound 924 MOVBU.P 1(R0), R3 925 CMP R2, R3 926 BNE loop 927 928 SUB $1, R0 // R0 will be one beyond the position we want 929 SUB R4, R0 // remove base 930 MOVD R0, ret+24(FP) 931 RET 932 933 notfound: 934 MOVD $-1, R0 935 MOVD R0, ret+24(FP) 936 RET 937 938 // TODO: share code with memequal? 939 TEXT bytes·Equal(SB),NOSPLIT,$0-49 940 MOVD a_len+8(FP), R1 941 MOVD b_len+32(FP), R3 942 CMP R1, R3 // unequal lengths are not equal 943 BNE notequal 944 MOVD a+0(FP), R0 945 MOVD b+24(FP), R2 946 ADD R0, R1 // end 947 loop: 948 CMP R0, R1 949 BEQ equal // reaches the end 950 MOVBU.P 1(R0), R4 951 MOVBU.P 1(R2), R5 952 CMP R4, R5 953 BEQ loop 954 notequal: 955 MOVB ZR, ret+48(FP) 956 RET 957 equal: 958 MOVD $1, R0 959 MOVB R0, ret+48(FP) 960 RET 961 962 TEXT runtime·fastrand(SB),NOSPLIT,$-8-4 963 MOVD g_m(g), R1 964 MOVWU m_fastrand(R1), R0 965 ADD R0, R0 966 CMPW $0, R0 967 BGE notneg 968 EOR $0x88888eef, R0 969 notneg: 970 MOVW R0, m_fastrand(R1) 971 MOVW R0, ret+0(FP) 972 RET 973 974 TEXT runtime·return0(SB), NOSPLIT, $0 975 MOVW $0, R0 976 RET 977 978 // The top-most function running on a goroutine 979 // returns to goexit+PCQuantum. 980 TEXT runtime·goexit(SB),NOSPLIT,$-8-0 981 MOVD R0, R0 // NOP 982 BL runtime·goexit1(SB) // does not return 983 984 // TODO(aram): use PRFM here. 985 TEXT runtime·prefetcht0(SB),NOSPLIT,$0-8 986 RET 987 988 TEXT runtime·prefetcht1(SB),NOSPLIT,$0-8 989 RET 990 991 TEXT runtime·prefetcht2(SB),NOSPLIT,$0-8 992 RET 993 994 TEXT runtime·prefetchnta(SB),NOSPLIT,$0-8 995 RET 996 997 TEXT runtime·sigreturn(SB),NOSPLIT,$0-0 998 RET 999 1000 // This is called from .init_array and follows the platform, not Go, ABI. 1001 TEXT runtime·addmoduledata(SB),NOSPLIT,$0-0 1002 SUB $0x10, RSP 1003 MOVD R27, 8(RSP) // The access to global variables below implicitly uses R27, which is callee-save 1004 MOVD runtime·lastmoduledatap(SB), R1 1005 MOVD R0, moduledata_next(R1) 1006 MOVD R0, runtime·lastmoduledatap(SB) 1007 MOVD 8(RSP), R27 1008 ADD $0x10, RSP 1009 RET 1010 1011 TEXT ·checkASM(SB),NOSPLIT,$0-1 1012 MOVW $1, R3 1013 MOVB R3, ret+0(FP) 1014 RET