github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/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|NOFRAME,$0 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|NOFRAME,$0 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 g, 32(R13) 40 MOVW R11, 36(R13) 41 42 // Skip floating point registers on GOARM < 6. 43 MOVB runtime·goarm(SB), R11 44 CMP $6, R11 45 BLT skipfpsave 46 MOVD F8, (40+8*0)(R13) 47 MOVD F9, (40+8*1)(R13) 48 MOVD F10, (40+8*2)(R13) 49 MOVD F11, (40+8*3)(R13) 50 MOVD F12, (40+8*4)(R13) 51 MOVD F13, (40+8*5)(R13) 52 MOVD F14, (40+8*6)(R13) 53 MOVD F15, (40+8*7)(R13) 54 skipfpsave: 55 // Save argc/argv. 56 MOVW R0, _rt0_arm_lib_argc<>(SB) 57 MOVW R1, _rt0_arm_lib_argv<>(SB) 58 59 MOVW $0, g // Initialize g. 60 61 // Synchronous initialization. 62 CALL runtime·libpreinit(SB) 63 64 // Create a new thread to do the runtime initialization. 65 MOVW _cgo_sys_thread_create(SB), R2 66 CMP $0, R2 67 BEQ nocgo 68 MOVW $_rt0_arm_lib_go<>(SB), R0 69 MOVW $0, R1 70 BL (R2) 71 B rr 72 nocgo: 73 MOVW $0x800000, R0 // stacksize = 8192KB 74 MOVW $_rt0_arm_lib_go<>(SB), R1 // fn 75 MOVW R0, 4(R13) 76 MOVW R1, 8(R13) 77 BL runtime·newosproc0(SB) 78 rr: 79 // Restore callee-save registers and return. 80 MOVB runtime·goarm(SB), R11 81 CMP $6, R11 82 BLT skipfprest 83 MOVD (40+8*0)(R13), F8 84 MOVD (40+8*1)(R13), F9 85 MOVD (40+8*2)(R13), F10 86 MOVD (40+8*3)(R13), F11 87 MOVD (40+8*4)(R13), F12 88 MOVD (40+8*5)(R13), F13 89 MOVD (40+8*6)(R13), F14 90 MOVD (40+8*7)(R13), F15 91 skipfprest: 92 MOVW 12(R13), R4 93 MOVW 16(R13), R5 94 MOVW 20(R13), R6 95 MOVW 24(R13), R7 96 MOVW 28(R13), R8 97 MOVW 32(R13), g 98 MOVW 36(R13), R11 99 RET 100 101 // _rt0_arm_lib_go initializes the Go runtime. 102 // This is started in a separate thread by _rt0_arm_lib. 103 TEXT _rt0_arm_lib_go<>(SB),NOSPLIT,$8 104 MOVW _rt0_arm_lib_argc<>(SB), R0 105 MOVW _rt0_arm_lib_argv<>(SB), R1 106 B runtime·rt0_go(SB) 107 108 DATA _rt0_arm_lib_argc<>(SB)/4,$0 109 GLOBL _rt0_arm_lib_argc<>(SB),NOPTR,$4 110 DATA _rt0_arm_lib_argv<>(SB)/4,$0 111 GLOBL _rt0_arm_lib_argv<>(SB),NOPTR,$4 112 113 // using NOFRAME means do not save LR on stack. 114 // argc is in R0, argv is in R1. 115 TEXT runtime·rt0_go(SB),NOSPLIT|NOFRAME|TOPFRAME,$0 116 MOVW $0xcafebabe, R12 117 118 // copy arguments forward on an even stack 119 // use R13 instead of SP to avoid linker rewriting the offsets 120 SUB $64, R13 // plenty of scratch 121 AND $~7, R13 122 MOVW R0, 60(R13) // save argc, argv away 123 MOVW R1, 64(R13) 124 125 // set up g register 126 // g is R10 127 MOVW $runtime·g0(SB), g 128 MOVW $runtime·m0(SB), R8 129 130 // save m->g0 = g0 131 MOVW g, m_g0(R8) 132 // save g->m = m0 133 MOVW R8, g_m(g) 134 135 // create istack out of the OS stack 136 // (1MB of system stack is available on iOS and Android) 137 MOVW $(-64*1024+104)(R13), R0 138 MOVW R0, g_stackguard0(g) 139 MOVW R0, g_stackguard1(g) 140 MOVW R0, (g_stack+stack_lo)(g) 141 MOVW R13, (g_stack+stack_hi)(g) 142 143 BL runtime·emptyfunc(SB) // fault if stack check is wrong 144 145 #ifdef GOOS_openbsd 146 // Save g to TLS so that it is available from signal trampoline. 147 BL runtime·save_g(SB) 148 #endif 149 150 BL runtime·_initcgo(SB) // will clobber R0-R3 151 152 // update stackguard after _cgo_init 153 MOVW (g_stack+stack_lo)(g), R0 154 ADD $const_stackGuard, R0 155 MOVW R0, g_stackguard0(g) 156 MOVW R0, g_stackguard1(g) 157 158 BL runtime·check(SB) 159 160 // saved argc, argv 161 MOVW 60(R13), R0 162 MOVW R0, 4(R13) 163 MOVW 64(R13), R1 164 MOVW R1, 8(R13) 165 BL runtime·args(SB) 166 BL runtime·checkgoarm(SB) 167 BL runtime·osinit(SB) 168 BL runtime·schedinit(SB) 169 170 // create a new goroutine to start program 171 SUB $8, R13 172 MOVW $runtime·mainPC(SB), R0 173 MOVW R0, 4(R13) // arg 1: fn 174 MOVW $0, R0 175 MOVW R0, 0(R13) // dummy LR 176 BL runtime·newproc(SB) 177 ADD $8, R13 // pop args and LR 178 179 // start this M 180 BL runtime·mstart(SB) 181 182 MOVW $1234, R0 183 MOVW $1000, R1 184 MOVW R0, (R1) // fail hard 185 186 DATA runtime·mainPC+0(SB)/4,$runtime·main(SB) 187 GLOBL runtime·mainPC(SB),RODATA,$4 188 189 TEXT runtime·breakpoint(SB),NOSPLIT,$0-0 190 // gdb won't skip this breakpoint instruction automatically, 191 // so you must manually "set $pc+=4" to skip it and continue. 192 #ifdef GOOS_plan9 193 WORD $0xD1200070 // undefined instruction used as armv5 breakpoint in Plan 9 194 #else 195 WORD $0xe7f001f0 // undefined instruction that gdb understands is a software breakpoint 196 #endif 197 RET 198 199 TEXT runtime·asminit(SB),NOSPLIT,$0-0 200 // disable runfast (flush-to-zero) mode of vfp if runtime.goarm > 5 201 MOVB runtime·goarm(SB), R11 202 CMP $5, R11 203 BLE 4(PC) 204 WORD $0xeef1ba10 // vmrs r11, fpscr 205 BIC $(1<<24), R11 206 WORD $0xeee1ba10 // vmsr fpscr, r11 207 RET 208 209 TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME,$0 210 BL runtime·mstart0(SB) 211 RET // not reached 212 213 /* 214 * go-routine 215 */ 216 217 // void gogo(Gobuf*) 218 // restore state from Gobuf; longjmp 219 TEXT runtime·gogo(SB),NOSPLIT|NOFRAME,$0-4 220 MOVW buf+0(FP), R1 221 MOVW gobuf_g(R1), R0 222 MOVW 0(R0), R2 // make sure g != nil 223 B gogo<>(SB) 224 225 TEXT gogo<>(SB),NOSPLIT|NOFRAME,$0 226 BL setg<>(SB) 227 MOVW gobuf_sp(R1), R13 // restore SP==R13 228 MOVW gobuf_lr(R1), LR 229 MOVW gobuf_ret(R1), R0 230 MOVW gobuf_ctxt(R1), R7 231 MOVW $0, R11 232 MOVW R11, gobuf_sp(R1) // clear to help garbage collector 233 MOVW R11, gobuf_ret(R1) 234 MOVW R11, gobuf_lr(R1) 235 MOVW R11, gobuf_ctxt(R1) 236 MOVW gobuf_pc(R1), R11 237 CMP R11, R11 // set condition codes for == test, needed by stack split 238 B (R11) 239 240 // func mcall(fn func(*g)) 241 // Switch to m->g0's stack, call fn(g). 242 // Fn must never return. It should gogo(&g->sched) 243 // to keep running g. 244 TEXT runtime·mcall(SB),NOSPLIT|NOFRAME,$0-4 245 // Save caller state in g->sched. 246 MOVW R13, (g_sched+gobuf_sp)(g) 247 MOVW LR, (g_sched+gobuf_pc)(g) 248 MOVW $0, R11 249 MOVW R11, (g_sched+gobuf_lr)(g) 250 251 // Switch to m->g0 & its stack, call fn. 252 MOVW g, R1 253 MOVW g_m(g), R8 254 MOVW m_g0(R8), R0 255 BL setg<>(SB) 256 CMP g, R1 257 B.NE 2(PC) 258 B runtime·badmcall(SB) 259 MOVW fn+0(FP), R0 260 MOVW (g_sched+gobuf_sp)(g), R13 261 SUB $8, R13 262 MOVW R1, 4(R13) 263 MOVW R0, R7 264 MOVW 0(R0), R0 265 BL (R0) 266 B runtime·badmcall2(SB) 267 RET 268 269 // systemstack_switch is a dummy routine that systemstack leaves at the bottom 270 // of the G stack. We need to distinguish the routine that 271 // lives at the bottom of the G stack from the one that lives 272 // at the top of the system stack because the one at the top of 273 // the system stack terminates the stack walk (see topofstack()). 274 TEXT runtime·systemstack_switch(SB),NOSPLIT,$0-0 275 MOVW $0, R0 276 BL (R0) // clobber lr to ensure push {lr} is kept 277 RET 278 279 // func systemstack(fn func()) 280 TEXT runtime·systemstack(SB),NOSPLIT,$0-4 281 MOVW fn+0(FP), R0 // R0 = fn 282 MOVW g_m(g), R1 // R1 = m 283 284 MOVW m_gsignal(R1), R2 // R2 = gsignal 285 CMP g, R2 286 B.EQ noswitch 287 288 MOVW m_g0(R1), R2 // R2 = g0 289 CMP g, R2 290 B.EQ noswitch 291 292 MOVW m_curg(R1), R3 293 CMP g, R3 294 B.EQ switch 295 296 // Bad: g is not gsignal, not g0, not curg. What is it? 297 // Hide call from linker nosplit analysis. 298 MOVW $runtime·badsystemstack(SB), R0 299 BL (R0) 300 B runtime·abort(SB) 301 302 switch: 303 // save our state in g->sched. Pretend to 304 // be systemstack_switch if the G stack is scanned. 305 BL gosave_systemstack_switch<>(SB) 306 307 // switch to g0 308 MOVW R0, R5 309 MOVW R2, R0 310 BL setg<>(SB) 311 MOVW R5, R0 312 MOVW (g_sched+gobuf_sp)(R2), R13 313 314 // call target function 315 MOVW R0, R7 316 MOVW 0(R0), R0 317 BL (R0) 318 319 // switch back to g 320 MOVW g_m(g), R1 321 MOVW m_curg(R1), R0 322 BL setg<>(SB) 323 MOVW (g_sched+gobuf_sp)(g), R13 324 MOVW $0, R3 325 MOVW R3, (g_sched+gobuf_sp)(g) 326 RET 327 328 noswitch: 329 // Using a tail call here cleans up tracebacks since we won't stop 330 // at an intermediate systemstack. 331 MOVW R0, R7 332 MOVW 0(R0), R0 333 MOVW.P 4(R13), R14 // restore LR 334 B (R0) 335 336 /* 337 * support for morestack 338 */ 339 340 // Called during function prolog when more stack is needed. 341 // R3 prolog's LR 342 // using NOFRAME means do not save LR on stack. 343 // 344 // The traceback routines see morestack on a g0 as being 345 // the top of a stack (for example, morestack calling newstack 346 // calling the scheduler calling newm calling gc), so we must 347 // record an argument size. For that purpose, it has no arguments. 348 TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 349 // Cannot grow scheduler stack (m->g0). 350 MOVW g_m(g), R8 351 MOVW m_g0(R8), R4 352 CMP g, R4 353 BNE 3(PC) 354 BL runtime·badmorestackg0(SB) 355 B runtime·abort(SB) 356 357 // Cannot grow signal stack (m->gsignal). 358 MOVW m_gsignal(R8), R4 359 CMP g, R4 360 BNE 3(PC) 361 BL runtime·badmorestackgsignal(SB) 362 B runtime·abort(SB) 363 364 // Called from f. 365 // Set g->sched to context in f. 366 MOVW R13, (g_sched+gobuf_sp)(g) 367 MOVW LR, (g_sched+gobuf_pc)(g) 368 MOVW R3, (g_sched+gobuf_lr)(g) 369 MOVW R7, (g_sched+gobuf_ctxt)(g) 370 371 // Called from f. 372 // Set m->morebuf to f's caller. 373 MOVW R3, (m_morebuf+gobuf_pc)(R8) // f's caller's PC 374 MOVW R13, (m_morebuf+gobuf_sp)(R8) // f's caller's SP 375 MOVW g, (m_morebuf+gobuf_g)(R8) 376 377 // Call newstack on m->g0's stack. 378 MOVW m_g0(R8), R0 379 BL setg<>(SB) 380 MOVW (g_sched+gobuf_sp)(g), R13 381 MOVW $0, R0 382 MOVW.W R0, -4(R13) // create a call frame on g0 (saved LR) 383 BL runtime·newstack(SB) 384 385 // Not reached, but make sure the return PC from the call to newstack 386 // is still in this function, and not the beginning of the next. 387 RET 388 389 TEXT runtime·morestack_noctxt(SB),NOSPLIT|NOFRAME,$0-0 390 // Force SPWRITE. This function doesn't actually write SP, 391 // but it is called with a special calling convention where 392 // the caller doesn't save LR on stack but passes it as a 393 // register (R3), and the unwinder currently doesn't understand. 394 // Make it SPWRITE to stop unwinding. (See issue 54332) 395 MOVW R13, R13 396 397 MOVW $0, R7 398 B runtime·morestack(SB) 399 400 // reflectcall: call a function with the given argument list 401 // func call(stackArgsType *_type, f *FuncVal, stackArgs *byte, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs). 402 // we don't have variable-sized frames, so we use a small number 403 // of constant-sized-frame functions to encode a few bits of size in the pc. 404 // Caution: ugly multiline assembly macros in your future! 405 406 #define DISPATCH(NAME,MAXSIZE) \ 407 CMP $MAXSIZE, R0; \ 408 B.HI 3(PC); \ 409 MOVW $NAME(SB), R1; \ 410 B (R1) 411 412 TEXT ·reflectcall(SB),NOSPLIT|NOFRAME,$0-28 413 MOVW frameSize+20(FP), R0 414 DISPATCH(runtime·call16, 16) 415 DISPATCH(runtime·call32, 32) 416 DISPATCH(runtime·call64, 64) 417 DISPATCH(runtime·call128, 128) 418 DISPATCH(runtime·call256, 256) 419 DISPATCH(runtime·call512, 512) 420 DISPATCH(runtime·call1024, 1024) 421 DISPATCH(runtime·call2048, 2048) 422 DISPATCH(runtime·call4096, 4096) 423 DISPATCH(runtime·call8192, 8192) 424 DISPATCH(runtime·call16384, 16384) 425 DISPATCH(runtime·call32768, 32768) 426 DISPATCH(runtime·call65536, 65536) 427 DISPATCH(runtime·call131072, 131072) 428 DISPATCH(runtime·call262144, 262144) 429 DISPATCH(runtime·call524288, 524288) 430 DISPATCH(runtime·call1048576, 1048576) 431 DISPATCH(runtime·call2097152, 2097152) 432 DISPATCH(runtime·call4194304, 4194304) 433 DISPATCH(runtime·call8388608, 8388608) 434 DISPATCH(runtime·call16777216, 16777216) 435 DISPATCH(runtime·call33554432, 33554432) 436 DISPATCH(runtime·call67108864, 67108864) 437 DISPATCH(runtime·call134217728, 134217728) 438 DISPATCH(runtime·call268435456, 268435456) 439 DISPATCH(runtime·call536870912, 536870912) 440 DISPATCH(runtime·call1073741824, 1073741824) 441 MOVW $runtime·badreflectcall(SB), R1 442 B (R1) 443 444 #define CALLFN(NAME,MAXSIZE) \ 445 TEXT NAME(SB), WRAPPER, $MAXSIZE-28; \ 446 NO_LOCAL_POINTERS; \ 447 /* copy arguments to stack */ \ 448 MOVW stackArgs+8(FP), R0; \ 449 MOVW stackArgsSize+12(FP), R2; \ 450 ADD $4, R13, R1; \ 451 CMP $0, R2; \ 452 B.EQ 5(PC); \ 453 MOVBU.P 1(R0), R5; \ 454 MOVBU.P R5, 1(R1); \ 455 SUB $1, R2, R2; \ 456 B -5(PC); \ 457 /* call function */ \ 458 MOVW f+4(FP), R7; \ 459 MOVW (R7), R0; \ 460 PCDATA $PCDATA_StackMapIndex, $0; \ 461 BL (R0); \ 462 /* copy return values back */ \ 463 MOVW stackArgsType+0(FP), R4; \ 464 MOVW stackArgs+8(FP), R0; \ 465 MOVW stackArgsSize+12(FP), R2; \ 466 MOVW stackArgsRetOffset+16(FP), R3; \ 467 ADD $4, R13, R1; \ 468 ADD R3, R1; \ 469 ADD R3, R0; \ 470 SUB R3, R2; \ 471 BL callRet<>(SB); \ 472 RET 473 474 // callRet copies return values back at the end of call*. This is a 475 // separate function so it can allocate stack space for the arguments 476 // to reflectcallmove. It does not follow the Go ABI; it expects its 477 // arguments in registers. 478 TEXT callRet<>(SB), NOSPLIT, $20-0 479 MOVW R4, 4(R13) 480 MOVW R0, 8(R13) 481 MOVW R1, 12(R13) 482 MOVW R2, 16(R13) 483 MOVW $0, R7 484 MOVW R7, 20(R13) 485 BL runtime·reflectcallmove(SB) 486 RET 487 488 CALLFN(·call16, 16) 489 CALLFN(·call32, 32) 490 CALLFN(·call64, 64) 491 CALLFN(·call128, 128) 492 CALLFN(·call256, 256) 493 CALLFN(·call512, 512) 494 CALLFN(·call1024, 1024) 495 CALLFN(·call2048, 2048) 496 CALLFN(·call4096, 4096) 497 CALLFN(·call8192, 8192) 498 CALLFN(·call16384, 16384) 499 CALLFN(·call32768, 32768) 500 CALLFN(·call65536, 65536) 501 CALLFN(·call131072, 131072) 502 CALLFN(·call262144, 262144) 503 CALLFN(·call524288, 524288) 504 CALLFN(·call1048576, 1048576) 505 CALLFN(·call2097152, 2097152) 506 CALLFN(·call4194304, 4194304) 507 CALLFN(·call8388608, 8388608) 508 CALLFN(·call16777216, 16777216) 509 CALLFN(·call33554432, 33554432) 510 CALLFN(·call67108864, 67108864) 511 CALLFN(·call134217728, 134217728) 512 CALLFN(·call268435456, 268435456) 513 CALLFN(·call536870912, 536870912) 514 CALLFN(·call1073741824, 1073741824) 515 516 // Save state of caller into g->sched, 517 // but using fake PC from systemstack_switch. 518 // Must only be called from functions with no locals ($0) 519 // or else unwinding from systemstack_switch is incorrect. 520 // Smashes R11. 521 TEXT gosave_systemstack_switch<>(SB),NOSPLIT|NOFRAME,$0 522 MOVW $runtime·systemstack_switch(SB), R11 523 ADD $4, R11 // get past push {lr} 524 MOVW R11, (g_sched+gobuf_pc)(g) 525 MOVW R13, (g_sched+gobuf_sp)(g) 526 MOVW $0, R11 527 MOVW R11, (g_sched+gobuf_lr)(g) 528 MOVW R11, (g_sched+gobuf_ret)(g) 529 // Assert ctxt is zero. See func save. 530 MOVW (g_sched+gobuf_ctxt)(g), R11 531 TST R11, R11 532 B.EQ 2(PC) 533 BL runtime·abort(SB) 534 RET 535 536 // func asmcgocall_no_g(fn, arg unsafe.Pointer) 537 // Call fn(arg) aligned appropriately for the gcc ABI. 538 // Called on a system stack, and there may be no g yet (during needm). 539 TEXT ·asmcgocall_no_g(SB),NOSPLIT,$0-8 540 MOVW fn+0(FP), R1 541 MOVW arg+4(FP), R0 542 MOVW R13, R2 543 SUB $32, R13 544 BIC $0x7, R13 // alignment for gcc ABI 545 MOVW R2, 8(R13) 546 BL (R1) 547 MOVW 8(R13), R2 548 MOVW R2, R13 549 RET 550 551 // func asmcgocall(fn, arg unsafe.Pointer) int32 552 // Call fn(arg) on the scheduler stack, 553 // aligned appropriately for the gcc ABI. 554 // See cgocall.go for more details. 555 TEXT ·asmcgocall(SB),NOSPLIT,$0-12 556 MOVW fn+0(FP), R1 557 MOVW arg+4(FP), R0 558 559 MOVW R13, R2 560 CMP $0, g 561 BEQ nosave 562 MOVW g, R4 563 564 // Figure out if we need to switch to m->g0 stack. 565 // We get called to create new OS threads too, and those 566 // come in on the m->g0 stack already. Or we might already 567 // be on the m->gsignal stack. 568 MOVW g_m(g), R8 569 MOVW m_gsignal(R8), R3 570 CMP R3, g 571 BEQ nosave 572 MOVW m_g0(R8), R3 573 CMP R3, g 574 BEQ nosave 575 BL gosave_systemstack_switch<>(SB) 576 MOVW R0, R5 577 MOVW R3, R0 578 BL setg<>(SB) 579 MOVW R5, R0 580 MOVW (g_sched+gobuf_sp)(g), R13 581 582 // Now on a scheduling stack (a pthread-created stack). 583 SUB $24, R13 584 BIC $0x7, R13 // alignment for gcc ABI 585 MOVW R4, 20(R13) // save old g 586 MOVW (g_stack+stack_hi)(R4), R4 587 SUB R2, R4 588 MOVW R4, 16(R13) // save depth in stack (can't just save SP, as stack might be copied during a callback) 589 BL (R1) 590 591 // Restore registers, g, stack pointer. 592 MOVW R0, R5 593 MOVW 20(R13), R0 594 BL setg<>(SB) 595 MOVW (g_stack+stack_hi)(g), R1 596 MOVW 16(R13), R2 597 SUB R2, R1 598 MOVW R5, R0 599 MOVW R1, R13 600 601 MOVW R0, ret+8(FP) 602 RET 603 604 nosave: 605 // Running on a system stack, perhaps even without a g. 606 // Having no g can happen during thread creation or thread teardown 607 // (see needm/dropm on Solaris, for example). 608 // This code is like the above sequence but without saving/restoring g 609 // and without worrying about the stack moving out from under us 610 // (because we're on a system stack, not a goroutine stack). 611 // The above code could be used directly if already on a system stack, 612 // but then the only path through this code would be a rare case on Solaris. 613 // Using this code for all "already on system stack" calls exercises it more, 614 // which should help keep it correct. 615 SUB $24, R13 616 BIC $0x7, R13 // alignment for gcc ABI 617 // save null g in case someone looks during debugging. 618 MOVW $0, R4 619 MOVW R4, 20(R13) 620 MOVW R2, 16(R13) // Save old stack pointer. 621 BL (R1) 622 // Restore stack pointer. 623 MOVW 16(R13), R2 624 MOVW R2, R13 625 MOVW R0, ret+8(FP) 626 RET 627 628 // cgocallback(fn, frame unsafe.Pointer, ctxt uintptr) 629 // See cgocall.go for more details. 630 TEXT ·cgocallback(SB),NOSPLIT,$12-12 631 NO_LOCAL_POINTERS 632 633 // Load m and g from thread-local storage. 634 #ifdef GOOS_openbsd 635 BL runtime·load_g(SB) 636 #else 637 MOVB runtime·iscgo(SB), R0 638 CMP $0, R0 639 BL.NE runtime·load_g(SB) 640 #endif 641 642 // If g is nil, Go did not create the current thread. 643 // Call needm to obtain one for temporary use. 644 // In this case, we're running on the thread stack, so there's 645 // lots of space, but the linker doesn't know. Hide the call from 646 // the linker analysis by using an indirect call. 647 CMP $0, g 648 B.EQ needm 649 650 MOVW g_m(g), R8 651 MOVW R8, savedm-4(SP) 652 B havem 653 654 needm: 655 MOVW g, savedm-4(SP) // g is zero, so is m. 656 MOVW $runtime·needm(SB), R0 657 BL (R0) 658 659 // Set m->g0->sched.sp = SP, so that if a panic happens 660 // during the function we are about to execute, it will 661 // have a valid SP to run on the g0 stack. 662 // The next few lines (after the havem label) 663 // will save this SP onto the stack and then write 664 // the same SP back to m->sched.sp. That seems redundant, 665 // but if an unrecovered panic happens, unwindm will 666 // restore the g->sched.sp from the stack location 667 // and then systemstack will try to use it. If we don't set it here, 668 // that restored SP will be uninitialized (typically 0) and 669 // will not be usable. 670 MOVW g_m(g), R8 671 MOVW m_g0(R8), R3 672 MOVW R13, (g_sched+gobuf_sp)(R3) 673 674 havem: 675 // Now there's a valid m, and we're running on its m->g0. 676 // Save current m->g0->sched.sp on stack and then set it to SP. 677 // Save current sp in m->g0->sched.sp in preparation for 678 // switch back to m->curg stack. 679 // NOTE: unwindm knows that the saved g->sched.sp is at 4(R13) aka savedsp-12(SP). 680 MOVW m_g0(R8), R3 681 MOVW (g_sched+gobuf_sp)(R3), R4 682 MOVW R4, savedsp-12(SP) // must match frame size 683 MOVW R13, (g_sched+gobuf_sp)(R3) 684 685 // Switch to m->curg stack and call runtime.cgocallbackg. 686 // Because we are taking over the execution of m->curg 687 // but *not* resuming what had been running, we need to 688 // save that information (m->curg->sched) so we can restore it. 689 // We can restore m->curg->sched.sp easily, because calling 690 // runtime.cgocallbackg leaves SP unchanged upon return. 691 // To save m->curg->sched.pc, we push it onto the curg stack and 692 // open a frame the same size as cgocallback's g0 frame. 693 // Once we switch to the curg stack, the pushed PC will appear 694 // to be the return PC of cgocallback, so that the traceback 695 // will seamlessly trace back into the earlier calls. 696 MOVW m_curg(R8), R0 697 BL setg<>(SB) 698 MOVW (g_sched+gobuf_sp)(g), R4 // prepare stack as R4 699 MOVW (g_sched+gobuf_pc)(g), R5 700 MOVW R5, -(12+4)(R4) // "saved LR"; must match frame size 701 // Gather our arguments into registers. 702 MOVW fn+0(FP), R1 703 MOVW frame+4(FP), R2 704 MOVW ctxt+8(FP), R3 705 MOVW $-(12+4)(R4), R13 // switch stack; must match frame size 706 MOVW R1, 4(R13) 707 MOVW R2, 8(R13) 708 MOVW R3, 12(R13) 709 BL runtime·cgocallbackg(SB) 710 711 // Restore g->sched (== m->curg->sched) from saved values. 712 MOVW 0(R13), R5 713 MOVW R5, (g_sched+gobuf_pc)(g) 714 MOVW $(12+4)(R13), R4 // must match frame size 715 MOVW R4, (g_sched+gobuf_sp)(g) 716 717 // Switch back to m->g0's stack and restore m->g0->sched.sp. 718 // (Unlike m->curg, the g0 goroutine never uses sched.pc, 719 // so we do not have to restore it.) 720 MOVW g_m(g), R8 721 MOVW m_g0(R8), R0 722 BL setg<>(SB) 723 MOVW (g_sched+gobuf_sp)(g), R13 724 MOVW savedsp-12(SP), R4 // must match frame size 725 MOVW R4, (g_sched+gobuf_sp)(g) 726 727 // If the m on entry was nil, we called needm above to borrow an m 728 // for the duration of the call. Since the call is over, return it with dropm. 729 MOVW savedm-4(SP), R6 730 CMP $0, R6 731 B.NE 3(PC) 732 MOVW $runtime·dropm(SB), R0 733 BL (R0) 734 735 // Done! 736 RET 737 738 // void setg(G*); set g. for use by needm. 739 TEXT runtime·setg(SB),NOSPLIT|NOFRAME,$0-4 740 MOVW gg+0(FP), R0 741 B setg<>(SB) 742 743 TEXT setg<>(SB),NOSPLIT|NOFRAME,$0-0 744 MOVW R0, g 745 746 // Save g to thread-local storage. 747 #ifdef GOOS_windows 748 B runtime·save_g(SB) 749 #else 750 #ifdef GOOS_openbsd 751 B runtime·save_g(SB) 752 #else 753 MOVB runtime·iscgo(SB), R0 754 CMP $0, R0 755 B.EQ 2(PC) 756 B runtime·save_g(SB) 757 758 MOVW g, R0 759 RET 760 #endif 761 #endif 762 763 TEXT runtime·emptyfunc(SB),0,$0-0 764 RET 765 766 TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0 767 MOVW $0, R0 768 MOVW (R0), R1 769 770 // armPublicationBarrier is a native store/store barrier for ARMv7+. 771 // On earlier ARM revisions, armPublicationBarrier is a no-op. 772 // This will not work on SMP ARMv6 machines, if any are in use. 773 // To implement publicationBarrier in sys_$GOOS_arm.s using the native 774 // instructions, use: 775 // 776 // TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-0 777 // B runtime·armPublicationBarrier(SB) 778 // 779 TEXT runtime·armPublicationBarrier(SB),NOSPLIT|NOFRAME,$0-0 780 MOVB runtime·goarm(SB), R11 781 CMP $7, R11 782 BLT 2(PC) 783 DMB MB_ST 784 RET 785 786 // AES hashing not implemented for ARM 787 TEXT runtime·memhash(SB),NOSPLIT|NOFRAME,$0-16 788 JMP runtime·memhashFallback(SB) 789 TEXT runtime·strhash(SB),NOSPLIT|NOFRAME,$0-12 790 JMP runtime·strhashFallback(SB) 791 TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-12 792 JMP runtime·memhash32Fallback(SB) 793 TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-12 794 JMP runtime·memhash64Fallback(SB) 795 796 TEXT runtime·return0(SB),NOSPLIT,$0 797 MOVW $0, R0 798 RET 799 800 TEXT runtime·procyield(SB),NOSPLIT|NOFRAME,$0 801 MOVW cycles+0(FP), R1 802 MOVW $0, R0 803 yieldloop: 804 WORD $0xe320f001 // YIELD (NOP pre-ARMv6K) 805 CMP R0, R1 806 B.NE 2(PC) 807 RET 808 SUB $1, R1 809 B yieldloop 810 811 // Called from cgo wrappers, this function returns g->m->curg.stack.hi. 812 // Must obey the gcc calling convention. 813 TEXT _cgo_topofstack(SB),NOSPLIT,$8 814 // R11 and g register are clobbered by load_g. They are 815 // callee-save in the gcc calling convention, so save them here. 816 MOVW R11, saveR11-4(SP) 817 MOVW g, saveG-8(SP) 818 819 BL runtime·load_g(SB) 820 MOVW g_m(g), R0 821 MOVW m_curg(R0), R0 822 MOVW (g_stack+stack_hi)(R0), R0 823 824 MOVW saveG-8(SP), g 825 MOVW saveR11-4(SP), R11 826 RET 827 828 // The top-most function running on a goroutine 829 // returns to goexit+PCQuantum. 830 TEXT runtime·goexit(SB),NOSPLIT|NOFRAME|TOPFRAME,$0-0 831 MOVW R0, R0 // NOP 832 BL runtime·goexit1(SB) // does not return 833 // traceback from goexit1 must hit code range of goexit 834 MOVW R0, R0 // NOP 835 836 // x -> x/1000000, x%1000000, called from Go with args, results on stack. 837 TEXT runtime·usplit(SB),NOSPLIT,$0-12 838 MOVW x+0(FP), R0 839 CALL runtime·usplitR0(SB) 840 MOVW R0, q+4(FP) 841 MOVW R1, r+8(FP) 842 RET 843 844 // R0, R1 = R0/1000000, R0%1000000 845 TEXT runtime·usplitR0(SB),NOSPLIT,$0 846 // magic multiply to avoid software divide without available m. 847 // see output of go tool compile -S for x/1000000. 848 MOVW R0, R3 849 MOVW $1125899907, R1 850 MULLU R1, R0, (R0, R1) 851 MOVW R0>>18, R0 852 MOVW $1000000, R1 853 MULU R0, R1 854 SUB R1, R3, R1 855 RET 856 857 // This is called from .init_array and follows the platform, not Go, ABI. 858 TEXT runtime·addmoduledata(SB),NOSPLIT,$0-0 859 MOVW R9, saver9-4(SP) // The access to global variables below implicitly uses R9, which is callee-save 860 MOVW R11, saver11-8(SP) // Likewise, R11 is the temp register, but callee-save in C ABI 861 MOVW runtime·lastmoduledatap(SB), R1 862 MOVW R0, moduledata_next(R1) 863 MOVW R0, runtime·lastmoduledatap(SB) 864 MOVW saver11-8(SP), R11 865 MOVW saver9-4(SP), R9 866 RET 867 868 TEXT ·checkASM(SB),NOSPLIT,$0-1 869 MOVW $1, R3 870 MOVB R3, ret+0(FP) 871 RET 872 873 // gcWriteBarrier informs the GC about heap pointer writes. 874 // 875 // gcWriteBarrier does NOT follow the Go ABI. It accepts the 876 // number of bytes of buffer needed in R8, and returns a pointer 877 // to the buffer space in R8. 878 // It clobbers condition codes. 879 // It does not clobber any other general-purpose registers, 880 // but may clobber others (e.g., floating point registers). 881 // The act of CALLing gcWriteBarrier will clobber R14 (LR). 882 TEXT gcWriteBarrier<>(SB),NOSPLIT|NOFRAME,$0 883 // Save the registers clobbered by the fast path. 884 MOVM.DB.W [R0,R1], (R13) 885 retry: 886 MOVW g_m(g), R0 887 MOVW m_p(R0), R0 888 MOVW (p_wbBuf+wbBuf_next)(R0), R1 889 MOVW (p_wbBuf+wbBuf_end)(R0), R11 890 // Increment wbBuf.next position. 891 ADD R8, R1 892 // Is the buffer full? 893 CMP R11, R1 894 BHI flush 895 // Commit to the larger buffer. 896 MOVW R1, (p_wbBuf+wbBuf_next)(R0) 897 // Make return value (the original next position) 898 SUB R8, R1, R8 899 // Restore registers. 900 MOVM.IA.W (R13), [R0,R1] 901 RET 902 903 flush: 904 // Save all general purpose registers since these could be 905 // clobbered by wbBufFlush and were not saved by the caller. 906 // 907 // R0 and R1 were saved at entry. 908 // R10 is g, so preserved. 909 // R11 is linker temp, so no need to save. 910 // R13 is stack pointer. 911 // R15 is PC. 912 MOVM.DB.W [R2-R9,R12], (R13) 913 // Save R14 (LR) because the fast path above doesn't save it, 914 // but needs it to RET. 915 MOVM.DB.W [R14], (R13) 916 917 CALL runtime·wbBufFlush(SB) 918 919 MOVM.IA.W (R13), [R14] 920 MOVM.IA.W (R13), [R2-R9,R12] 921 JMP retry 922 923 TEXT runtime·gcWriteBarrier1<ABIInternal>(SB),NOSPLIT,$0 924 MOVW $4, R8 925 JMP gcWriteBarrier<>(SB) 926 TEXT runtime·gcWriteBarrier2<ABIInternal>(SB),NOSPLIT,$0 927 MOVW $8, R8 928 JMP gcWriteBarrier<>(SB) 929 TEXT runtime·gcWriteBarrier3<ABIInternal>(SB),NOSPLIT,$0 930 MOVW $12, R8 931 JMP gcWriteBarrier<>(SB) 932 TEXT runtime·gcWriteBarrier4<ABIInternal>(SB),NOSPLIT,$0 933 MOVW $16, R8 934 JMP gcWriteBarrier<>(SB) 935 TEXT runtime·gcWriteBarrier5<ABIInternal>(SB),NOSPLIT,$0 936 MOVW $20, R8 937 JMP gcWriteBarrier<>(SB) 938 TEXT runtime·gcWriteBarrier6<ABIInternal>(SB),NOSPLIT,$0 939 MOVW $24, R8 940 JMP gcWriteBarrier<>(SB) 941 TEXT runtime·gcWriteBarrier7<ABIInternal>(SB),NOSPLIT,$0 942 MOVW $28, R8 943 JMP gcWriteBarrier<>(SB) 944 TEXT runtime·gcWriteBarrier8<ABIInternal>(SB),NOSPLIT,$0 945 MOVW $32, R8 946 JMP gcWriteBarrier<>(SB) 947 948 // Note: these functions use a special calling convention to save generated code space. 949 // Arguments are passed in registers, but the space for those arguments are allocated 950 // in the caller's stack frame. These stubs write the args into that stack space and 951 // then tail call to the corresponding runtime handler. 952 // The tail call makes these stubs disappear in backtraces. 953 TEXT runtime·panicIndex(SB),NOSPLIT,$0-8 954 MOVW R0, x+0(FP) 955 MOVW R1, y+4(FP) 956 JMP runtime·goPanicIndex(SB) 957 TEXT runtime·panicIndexU(SB),NOSPLIT,$0-8 958 MOVW R0, x+0(FP) 959 MOVW R1, y+4(FP) 960 JMP runtime·goPanicIndexU(SB) 961 TEXT runtime·panicSliceAlen(SB),NOSPLIT,$0-8 962 MOVW R1, x+0(FP) 963 MOVW R2, y+4(FP) 964 JMP runtime·goPanicSliceAlen(SB) 965 TEXT runtime·panicSliceAlenU(SB),NOSPLIT,$0-8 966 MOVW R1, x+0(FP) 967 MOVW R2, y+4(FP) 968 JMP runtime·goPanicSliceAlenU(SB) 969 TEXT runtime·panicSliceAcap(SB),NOSPLIT,$0-8 970 MOVW R1, x+0(FP) 971 MOVW R2, y+4(FP) 972 JMP runtime·goPanicSliceAcap(SB) 973 TEXT runtime·panicSliceAcapU(SB),NOSPLIT,$0-8 974 MOVW R1, x+0(FP) 975 MOVW R2, y+4(FP) 976 JMP runtime·goPanicSliceAcapU(SB) 977 TEXT runtime·panicSliceB(SB),NOSPLIT,$0-8 978 MOVW R0, x+0(FP) 979 MOVW R1, y+4(FP) 980 JMP runtime·goPanicSliceB(SB) 981 TEXT runtime·panicSliceBU(SB),NOSPLIT,$0-8 982 MOVW R0, x+0(FP) 983 MOVW R1, y+4(FP) 984 JMP runtime·goPanicSliceBU(SB) 985 TEXT runtime·panicSlice3Alen(SB),NOSPLIT,$0-8 986 MOVW R2, x+0(FP) 987 MOVW R3, y+4(FP) 988 JMP runtime·goPanicSlice3Alen(SB) 989 TEXT runtime·panicSlice3AlenU(SB),NOSPLIT,$0-8 990 MOVW R2, x+0(FP) 991 MOVW R3, y+4(FP) 992 JMP runtime·goPanicSlice3AlenU(SB) 993 TEXT runtime·panicSlice3Acap(SB),NOSPLIT,$0-8 994 MOVW R2, x+0(FP) 995 MOVW R3, y+4(FP) 996 JMP runtime·goPanicSlice3Acap(SB) 997 TEXT runtime·panicSlice3AcapU(SB),NOSPLIT,$0-8 998 MOVW R2, x+0(FP) 999 MOVW R3, y+4(FP) 1000 JMP runtime·goPanicSlice3AcapU(SB) 1001 TEXT runtime·panicSlice3B(SB),NOSPLIT,$0-8 1002 MOVW R1, x+0(FP) 1003 MOVW R2, y+4(FP) 1004 JMP runtime·goPanicSlice3B(SB) 1005 TEXT runtime·panicSlice3BU(SB),NOSPLIT,$0-8 1006 MOVW R1, x+0(FP) 1007 MOVW R2, y+4(FP) 1008 JMP runtime·goPanicSlice3BU(SB) 1009 TEXT runtime·panicSlice3C(SB),NOSPLIT,$0-8 1010 MOVW R0, x+0(FP) 1011 MOVW R1, y+4(FP) 1012 JMP runtime·goPanicSlice3C(SB) 1013 TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-8 1014 MOVW R0, x+0(FP) 1015 MOVW R1, y+4(FP) 1016 JMP runtime·goPanicSlice3CU(SB) 1017 TEXT runtime·panicSliceConvert(SB),NOSPLIT,$0-8 1018 MOVW R2, x+0(FP) 1019 MOVW R3, y+4(FP) 1020 JMP runtime·goPanicSliceConvert(SB) 1021 1022 // Extended versions for 64-bit indexes. 1023 TEXT runtime·panicExtendIndex(SB),NOSPLIT,$0-12 1024 MOVW R4, hi+0(FP) 1025 MOVW R0, lo+4(FP) 1026 MOVW R1, y+8(FP) 1027 JMP runtime·goPanicExtendIndex(SB) 1028 TEXT runtime·panicExtendIndexU(SB),NOSPLIT,$0-12 1029 MOVW R4, hi+0(FP) 1030 MOVW R0, lo+4(FP) 1031 MOVW R1, y+8(FP) 1032 JMP runtime·goPanicExtendIndexU(SB) 1033 TEXT runtime·panicExtendSliceAlen(SB),NOSPLIT,$0-12 1034 MOVW R4, hi+0(FP) 1035 MOVW R1, lo+4(FP) 1036 MOVW R2, y+8(FP) 1037 JMP runtime·goPanicExtendSliceAlen(SB) 1038 TEXT runtime·panicExtendSliceAlenU(SB),NOSPLIT,$0-12 1039 MOVW R4, hi+0(FP) 1040 MOVW R1, lo+4(FP) 1041 MOVW R2, y+8(FP) 1042 JMP runtime·goPanicExtendSliceAlenU(SB) 1043 TEXT runtime·panicExtendSliceAcap(SB),NOSPLIT,$0-12 1044 MOVW R4, hi+0(FP) 1045 MOVW R1, lo+4(FP) 1046 MOVW R2, y+8(FP) 1047 JMP runtime·goPanicExtendSliceAcap(SB) 1048 TEXT runtime·panicExtendSliceAcapU(SB),NOSPLIT,$0-12 1049 MOVW R4, hi+0(FP) 1050 MOVW R1, lo+4(FP) 1051 MOVW R2, y+8(FP) 1052 JMP runtime·goPanicExtendSliceAcapU(SB) 1053 TEXT runtime·panicExtendSliceB(SB),NOSPLIT,$0-12 1054 MOVW R4, hi+0(FP) 1055 MOVW R0, lo+4(FP) 1056 MOVW R1, y+8(FP) 1057 JMP runtime·goPanicExtendSliceB(SB) 1058 TEXT runtime·panicExtendSliceBU(SB),NOSPLIT,$0-12 1059 MOVW R4, hi+0(FP) 1060 MOVW R0, lo+4(FP) 1061 MOVW R1, y+8(FP) 1062 JMP runtime·goPanicExtendSliceBU(SB) 1063 TEXT runtime·panicExtendSlice3Alen(SB),NOSPLIT,$0-12 1064 MOVW R4, hi+0(FP) 1065 MOVW R2, lo+4(FP) 1066 MOVW R3, y+8(FP) 1067 JMP runtime·goPanicExtendSlice3Alen(SB) 1068 TEXT runtime·panicExtendSlice3AlenU(SB),NOSPLIT,$0-12 1069 MOVW R4, hi+0(FP) 1070 MOVW R2, lo+4(FP) 1071 MOVW R3, y+8(FP) 1072 JMP runtime·goPanicExtendSlice3AlenU(SB) 1073 TEXT runtime·panicExtendSlice3Acap(SB),NOSPLIT,$0-12 1074 MOVW R4, hi+0(FP) 1075 MOVW R2, lo+4(FP) 1076 MOVW R3, y+8(FP) 1077 JMP runtime·goPanicExtendSlice3Acap(SB) 1078 TEXT runtime·panicExtendSlice3AcapU(SB),NOSPLIT,$0-12 1079 MOVW R4, hi+0(FP) 1080 MOVW R2, lo+4(FP) 1081 MOVW R3, y+8(FP) 1082 JMP runtime·goPanicExtendSlice3AcapU(SB) 1083 TEXT runtime·panicExtendSlice3B(SB),NOSPLIT,$0-12 1084 MOVW R4, hi+0(FP) 1085 MOVW R1, lo+4(FP) 1086 MOVW R2, y+8(FP) 1087 JMP runtime·goPanicExtendSlice3B(SB) 1088 TEXT runtime·panicExtendSlice3BU(SB),NOSPLIT,$0-12 1089 MOVW R4, hi+0(FP) 1090 MOVW R1, lo+4(FP) 1091 MOVW R2, y+8(FP) 1092 JMP runtime·goPanicExtendSlice3BU(SB) 1093 TEXT runtime·panicExtendSlice3C(SB),NOSPLIT,$0-12 1094 MOVW R4, hi+0(FP) 1095 MOVW R0, lo+4(FP) 1096 MOVW R1, y+8(FP) 1097 JMP runtime·goPanicExtendSlice3C(SB) 1098 TEXT runtime·panicExtendSlice3CU(SB),NOSPLIT,$0-12 1099 MOVW R4, hi+0(FP) 1100 MOVW R0, lo+4(FP) 1101 MOVW R1, y+8(FP) 1102 JMP runtime·goPanicExtendSlice3CU(SB)