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