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