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