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