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