github.com/gidoBOSSftw5731/go/src@v0.0.0-20210226122457-d24b0edbf019/runtime/sys_windows_arm.s (about) 1 // Copyright 2018 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 "textflag.h" 8 9 // Note: For system ABI, R0-R3 are args, R4-R11 are callee-save. 10 11 // void runtime·asmstdcall(void *c); 12 TEXT runtime·asmstdcall(SB),NOSPLIT|NOFRAME,$0 13 MOVM.DB.W [R4, R5, R14], (R13) // push {r4, r5, lr} 14 MOVW R0, R4 // put libcall * in r4 15 MOVW R13, R5 // save stack pointer in r5 16 17 // SetLastError(0) 18 MOVW $0, R0 19 MRC 15, 0, R1, C13, C0, 2 20 MOVW R0, 0x34(R1) 21 22 MOVW 8(R4), R12 // libcall->args 23 24 // Do we have more than 4 arguments? 25 MOVW 4(R4), R0 // libcall->n 26 SUB.S $4, R0, R2 27 BLE loadregs 28 29 // Reserve stack space for remaining args 30 SUB R2<<2, R13 31 BIC $0x7, R13 // alignment for ABI 32 33 // R0: count of arguments 34 // R1: 35 // R2: loop counter, from 0 to (n-4) 36 // R3: scratch 37 // R4: pointer to libcall struct 38 // R12: libcall->args 39 MOVW $0, R2 40 stackargs: 41 ADD $4, R2, R3 // r3 = args[4 + i] 42 MOVW R3<<2(R12), R3 43 MOVW R3, R2<<2(R13) // stack[i] = r3 44 45 ADD $1, R2 // i++ 46 SUB $4, R0, R3 // while (i < (n - 4)) 47 CMP R3, R2 48 BLT stackargs 49 50 loadregs: 51 CMP $3, R0 52 MOVW.GT 12(R12), R3 53 54 CMP $2, R0 55 MOVW.GT 8(R12), R2 56 57 CMP $1, R0 58 MOVW.GT 4(R12), R1 59 60 CMP $0, R0 61 MOVW.GT 0(R12), R0 62 63 BIC $0x7, R13 // alignment for ABI 64 MOVW 0(R4), R12 // branch to libcall->fn 65 BL (R12) 66 67 MOVW R5, R13 // free stack space 68 MOVW R0, 12(R4) // save return value to libcall->r1 69 MOVW R1, 16(R4) 70 71 // GetLastError 72 MRC 15, 0, R1, C13, C0, 2 73 MOVW 0x34(R1), R0 74 MOVW R0, 20(R4) // store in libcall->err 75 76 MOVM.IA.W (R13), [R4, R5, R15] 77 78 TEXT runtime·badsignal2(SB),NOSPLIT|NOFRAME,$0 79 MOVM.DB.W [R4, R14], (R13) // push {r4, lr} 80 MOVW R13, R4 // save original stack pointer 81 SUB $8, R13 // space for 2 variables 82 BIC $0x7, R13 // alignment for ABI 83 84 // stderr 85 MOVW runtime·_GetStdHandle(SB), R1 86 MOVW $-12, R0 87 BL (R1) 88 89 MOVW $runtime·badsignalmsg(SB), R1 // lpBuffer 90 MOVW $runtime·badsignallen(SB), R2 // lpNumberOfBytesToWrite 91 MOVW (R2), R2 92 ADD $0x4, R13, R3 // lpNumberOfBytesWritten 93 MOVW $0, R12 // lpOverlapped 94 MOVW R12, (R13) 95 96 MOVW runtime·_WriteFile(SB), R12 97 BL (R12) 98 99 MOVW R4, R13 // restore SP 100 MOVM.IA.W (R13), [R4, R15] // pop {r4, pc} 101 102 TEXT runtime·getlasterror(SB),NOSPLIT,$0 103 MRC 15, 0, R0, C13, C0, 2 104 MOVW 0x34(R0), R0 105 MOVW R0, ret+0(FP) 106 RET 107 108 // Called by Windows as a Vectored Exception Handler (VEH). 109 // First argument is pointer to struct containing 110 // exception record and context pointers. 111 // Handler function is stored in R1 112 // Return 0 for 'not handled', -1 for handled. 113 // int32_t sigtramp( 114 // PEXCEPTION_POINTERS ExceptionInfo, 115 // func *GoExceptionHandler); 116 TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0 117 MOVM.DB.W [R0, R4-R11, R14], (R13) // push {r0, r4-r11, lr} (SP-=40) 118 SUB $(8+20), R13 // reserve space for g, sp, and 119 // parameters/retval to go call 120 121 MOVW R0, R6 // Save param0 122 MOVW R1, R7 // Save param1 123 124 BL runtime·load_g(SB) 125 CMP $0, g // is there a current g? 126 BL.EQ runtime·badsignal2(SB) 127 128 // save g and SP in case of stack switch 129 MOVW R13, 24(R13) 130 MOVW g, 20(R13) 131 132 // do we need to switch to the g0 stack? 133 MOVW g, R5 // R5 = g 134 MOVW g_m(R5), R2 // R2 = m 135 MOVW m_g0(R2), R4 // R4 = g0 136 CMP R5, R4 // if curg == g0 137 BEQ g0 138 139 // switch to g0 stack 140 MOVW R4, g // g = g0 141 MOVW (g_sched+gobuf_sp)(g), R3 // R3 = g->gobuf.sp 142 BL runtime·save_g(SB) 143 144 // make room for sighandler arguments 145 // and re-save old SP for restoring later. 146 // (note that the 24(R3) here must match the 24(R13) above.) 147 SUB $40, R3 148 MOVW R13, 24(R3) // save old stack pointer 149 MOVW R3, R13 // switch stack 150 151 g0: 152 MOVW 0(R6), R2 // R2 = ExceptionPointers->ExceptionRecord 153 MOVW 4(R6), R3 // R3 = ExceptionPointers->ContextRecord 154 155 MOVW $0, R4 156 MOVW R4, 0(R13) // No saved link register. 157 MOVW R2, 4(R13) // Move arg0 (ExceptionRecord) into position 158 MOVW R3, 8(R13) // Move arg1 (ContextRecord) into position 159 MOVW R5, 12(R13) // Move arg2 (original g) into position 160 BL (R7) // Call the go routine 161 MOVW 16(R13), R4 // Fetch return value from stack 162 163 // Save system stack pointer for sigresume setup below. 164 // The exact value does not matter - nothing is read or written 165 // from this address. It just needs to be on the system stack. 166 MOVW R13, R12 167 168 // switch back to original stack and g 169 MOVW 24(R13), R13 170 MOVW 20(R13), g 171 BL runtime·save_g(SB) 172 173 done: 174 MOVW R4, R0 // move retval into position 175 ADD $(8 + 20), R13 // free locals 176 MOVM.IA.W (R13), [R3, R4-R11, R14] // pop {r3, r4-r11, lr} 177 178 // if return value is CONTINUE_SEARCH, do not set up control 179 // flow guard workaround 180 CMP $0, R0 181 BEQ return 182 183 // Check if we need to set up the control flow guard workaround. 184 // On Windows, the stack pointer in the context must lie within 185 // system stack limits when we resume from exception. 186 // Store the resume SP and PC on the g0 stack, 187 // and return to sigresume on the g0 stack. sigresume 188 // pops the saved PC and SP from the g0 stack, resuming execution 189 // at the desired location. 190 // If sigresume has already been set up by a previous exception 191 // handler, don't clobber the stored SP and PC on the stack. 192 MOVW 4(R3), R3 // PEXCEPTION_POINTERS->Context 193 MOVW context_pc(R3), R2 // load PC from context record 194 MOVW $sigresume<>(SB), R1 195 CMP R1, R2 196 B.EQ return // do not clobber saved SP/PC 197 198 // Save resume SP and PC into R0, R1. 199 MOVW context_spr(R3), R2 200 MOVW R2, context_r0(R3) 201 MOVW context_pc(R3), R2 202 MOVW R2, context_r1(R3) 203 204 // Set up context record to return to sigresume on g0 stack 205 MOVW R12, context_spr(R3) 206 MOVW $sigresume<>(SB), R2 207 MOVW R2, context_pc(R3) 208 209 return: 210 B (R14) // return 211 212 // Trampoline to resume execution from exception handler. 213 // This is part of the control flow guard workaround. 214 // It switches stacks and jumps to the continuation address. 215 // R0 and R1 are set above at the end of sigtramp<> 216 // in the context that starts executing at sigresume<>. 217 TEXT sigresume<>(SB),NOSPLIT|NOFRAME,$0 218 // Important: do not smash LR, 219 // which is set to a live value when handling 220 // a signal by pushing a call to sigpanic onto the stack. 221 MOVW R0, R13 222 B (R1) 223 224 TEXT runtime·exceptiontramp(SB),NOSPLIT|NOFRAME,$0 225 MOVW $runtime·exceptionhandler(SB), R1 226 B sigtramp<>(SB) 227 228 TEXT runtime·firstcontinuetramp(SB),NOSPLIT|NOFRAME,$0 229 MOVW $runtime·firstcontinuehandler(SB), R1 230 B sigtramp<>(SB) 231 232 TEXT runtime·lastcontinuetramp(SB),NOSPLIT|NOFRAME,$0 233 MOVW $runtime·lastcontinuehandler(SB), R1 234 B sigtramp<>(SB) 235 236 TEXT runtime·ctrlhandler(SB),NOSPLIT|NOFRAME,$0 237 MOVW $runtime·ctrlhandler1(SB), R1 238 B runtime·externalthreadhandler(SB) 239 240 TEXT runtime·profileloop(SB),NOSPLIT|NOFRAME,$0 241 MOVW $runtime·profileloop1(SB), R1 242 B runtime·externalthreadhandler(SB) 243 244 // int32 externalthreadhandler(uint32 arg, int (*func)(uint32)) 245 // stack layout: 246 // +----------------+ 247 // | callee-save | 248 // | registers | 249 // +----------------+ 250 // | m | 251 // +----------------+ 252 // 20| g | 253 // +----------------+ 254 // 16| func ptr (r1) | 255 // +----------------+ 256 // 12| argument (r0) | 257 //---+----------------+ 258 // 8 | param1 | (also return value for called Go function) 259 // +----------------+ 260 // 4 | param0 | 261 // +----------------+ 262 // 0 | slot for LR | 263 // +----------------+ 264 // 265 TEXT runtime·externalthreadhandler(SB),NOSPLIT|NOFRAME|TOPFRAME,$0 266 MOVM.DB.W [R4-R11, R14], (R13) // push {r4-r11, lr} 267 SUB $(m__size + g__size + 20), R13 // space for locals 268 MOVW R14, 0(R13) // push LR again for anything unwinding the stack 269 MOVW R0, 12(R13) 270 MOVW R1, 16(R13) 271 272 // zero out m and g structures 273 ADD $20, R13, R0 // compute pointer to g 274 MOVW R0, 4(R13) 275 MOVW $(m__size + g__size), R0 276 MOVW R0, 8(R13) 277 BL runtime·memclrNoHeapPointers(SB) 278 279 // initialize m and g structures 280 ADD $20, R13, R2 // R2 = g 281 ADD $(20 + g__size), R13, R3 // R3 = m 282 MOVW R2, m_g0(R3) // m->g0 = g 283 MOVW R3, g_m(R2) // g->m = m 284 MOVW R2, m_curg(R3) // m->curg = g 285 286 MOVW R2, g 287 BL runtime·save_g(SB) 288 289 // set up stackguard stuff 290 MOVW R13, R0 291 MOVW R0, g_stack+stack_hi(g) 292 SUB $(32*1024), R0 293 MOVW R0, (g_stack+stack_lo)(g) 294 MOVW R0, g_stackguard0(g) 295 MOVW R0, g_stackguard1(g) 296 297 // move argument into position and call function 298 MOVW 12(R13), R0 299 MOVW R0, 4(R13) 300 MOVW 16(R13), R1 301 BL (R1) 302 303 // clear g 304 MOVW $0, g 305 BL runtime·save_g(SB) 306 307 MOVW 8(R13), R0 // load return value 308 ADD $(m__size + g__size + 20), R13 // free locals 309 MOVM.IA.W (R13), [R4-R11, R15] // pop {r4-r11, pc} 310 311 GLOBL runtime·cbctxts(SB), NOPTR, $4 312 313 TEXT runtime·callbackasm1(SB),NOSPLIT|NOFRAME,$0 314 // On entry, the trampoline in zcallback_windows_arm.s left 315 // the callback index in R12 (which is volatile in the C ABI). 316 317 // Push callback register arguments r0-r3. We do this first so 318 // they're contiguous with stack arguments. 319 MOVM.DB.W [R0-R3], (R13) 320 // Push C callee-save registers r4-r11 and lr. 321 MOVM.DB.W [R4-R11, R14], (R13) 322 SUB $(16 + callbackArgs__size), R13 // space for locals 323 324 // Create a struct callbackArgs on our stack. 325 MOVW R12, (16+callbackArgs_index)(R13) // callback index 326 MOVW $(16+callbackArgs__size+4*9)(R13), R0 327 MOVW R0, (16+callbackArgs_args)(R13) // address of args vector 328 MOVW $0, R0 329 MOVW R0, (16+callbackArgs_result)(R13) // result 330 331 // Prepare for entry to Go. 332 BL runtime·load_g(SB) 333 334 // Call cgocallback, which will call callbackWrap(frame). 335 MOVW $0, R0 336 MOVW R0, 12(R13) // context 337 MOVW $16(R13), R1 // R1 = &callbackArgs{...} 338 MOVW R1, 8(R13) // frame (address of callbackArgs) 339 MOVW $·callbackWrap(SB), R1 340 MOVW R1, 4(R13) // PC of function to call 341 BL runtime·cgocallback(SB) 342 343 // Get callback result. 344 MOVW (16+callbackArgs_result)(R13), R0 345 346 ADD $(16 + callbackArgs__size), R13 // free locals 347 MOVM.IA.W (R13), [R4-R11, R12] // pop {r4-r11, lr=>r12} 348 ADD $(4*4), R13 // skip r0-r3 349 B (R12) // return 350 351 // uint32 tstart_stdcall(M *newm); 352 TEXT runtime·tstart_stdcall(SB),NOSPLIT|NOFRAME,$0 353 MOVM.DB.W [R4-R11, R14], (R13) // push {r4-r11, lr} 354 355 MOVW m_g0(R0), g 356 MOVW R0, g_m(g) 357 BL runtime·save_g(SB) 358 359 // Layout new m scheduler stack on os stack. 360 MOVW R13, R0 361 MOVW R0, g_stack+stack_hi(g) 362 SUB $(64*1024), R0 363 MOVW R0, (g_stack+stack_lo)(g) 364 MOVW R0, g_stackguard0(g) 365 MOVW R0, g_stackguard1(g) 366 367 BL runtime·emptyfunc(SB) // fault if stack check is wrong 368 BL runtime·mstart(SB) 369 370 // Exit the thread. 371 MOVW $0, R0 372 MOVM.IA.W (R13), [R4-R11, R15] // pop {r4-r11, pc} 373 374 // Runs on OS stack. 375 // duration (in -100ns units) is in dt+0(FP). 376 // g may be nil. 377 TEXT runtime·usleep2(SB),NOSPLIT|NOFRAME,$0-4 378 MOVW dt+0(FP), R3 379 MOVM.DB.W [R4, R14], (R13) // push {r4, lr} 380 MOVW R13, R4 // Save SP 381 SUB $8, R13 // R13 = R13 - 8 382 BIC $0x7, R13 // Align SP for ABI 383 MOVW $0, R1 // R1 = FALSE (alertable) 384 MOVW $-1, R0 // R0 = handle 385 MOVW R13, R2 // R2 = pTime 386 MOVW R3, 0(R2) // time_lo 387 MOVW R0, 4(R2) // time_hi 388 MOVW runtime·_NtWaitForSingleObject(SB), R3 389 BL (R3) 390 MOVW R4, R13 // Restore SP 391 MOVM.IA.W (R13), [R4, R15] // pop {R4, pc} 392 393 // Runs on OS stack. 394 // duration (in -100ns units) is in dt+0(FP). 395 // g is valid. 396 // TODO: neeeds to be implemented properly. 397 TEXT runtime·usleep2HighRes(SB),NOSPLIT|NOFRAME,$0-4 398 B runtime·abort(SB) 399 400 // Runs on OS stack. 401 TEXT runtime·switchtothread(SB),NOSPLIT|NOFRAME,$0 402 MOVM.DB.W [R4, R14], (R13) // push {R4, lr} 403 MOVW R13, R4 404 BIC $0x7, R13 // alignment for ABI 405 MOVW runtime·_SwitchToThread(SB), R0 406 BL (R0) 407 MOVW R4, R13 // restore stack pointer 408 MOVM.IA.W (R13), [R4, R15] // pop {R4, pc} 409 410 TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-0 411 B runtime·armPublicationBarrier(SB) 412 413 // never called (cgo not supported) 414 TEXT runtime·read_tls_fallback(SB),NOSPLIT|NOFRAME,$0 415 MOVW $0xabcd, R0 416 MOVW R0, (R0) 417 RET 418 419 // See http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/ 420 // Must read hi1, then lo, then hi2. The snapshot is valid if hi1 == hi2. 421 #define _INTERRUPT_TIME 0x7ffe0008 422 #define _SYSTEM_TIME 0x7ffe0014 423 #define time_lo 0 424 #define time_hi1 4 425 #define time_hi2 8 426 427 TEXT runtime·nanotime1(SB),NOSPLIT|NOFRAME,$0-8 428 MOVW $0, R0 429 MOVB runtime·useQPCTime(SB), R0 430 CMP $0, R0 431 BNE useQPC 432 MOVW $_INTERRUPT_TIME, R3 433 loop: 434 MOVW time_hi1(R3), R1 435 MOVW time_lo(R3), R0 436 MOVW time_hi2(R3), R2 437 CMP R1, R2 438 BNE loop 439 440 // wintime = R1:R0, multiply by 100 441 MOVW $100, R2 442 MULLU R0, R2, (R4, R3) // R4:R3 = R1:R0 * R2 443 MULA R1, R2, R4, R4 444 445 // wintime*100 = R4:R3 446 MOVW R3, ret_lo+0(FP) 447 MOVW R4, ret_hi+4(FP) 448 RET 449 useQPC: 450 B runtime·nanotimeQPC(SB) // tail call 451 452 TEXT time·now(SB),NOSPLIT|NOFRAME,$0-20 453 MOVW $0, R0 454 MOVB runtime·useQPCTime(SB), R0 455 CMP $0, R0 456 BNE useQPC 457 MOVW $_INTERRUPT_TIME, R3 458 loop: 459 MOVW time_hi1(R3), R1 460 MOVW time_lo(R3), R0 461 MOVW time_hi2(R3), R2 462 CMP R1, R2 463 BNE loop 464 465 // wintime = R1:R0, multiply by 100 466 MOVW $100, R2 467 MULLU R0, R2, (R4, R3) // R4:R3 = R1:R0 * R2 468 MULA R1, R2, R4, R4 469 470 // wintime*100 = R4:R3 471 MOVW R3, mono+12(FP) 472 MOVW R4, mono+16(FP) 473 474 MOVW $_SYSTEM_TIME, R3 475 wall: 476 MOVW time_hi1(R3), R1 477 MOVW time_lo(R3), R0 478 MOVW time_hi2(R3), R2 479 CMP R1, R2 480 BNE wall 481 482 // w = R1:R0 in 100ns untis 483 // convert to Unix epoch (but still 100ns units) 484 #define delta 116444736000000000 485 SUB.S $(delta & 0xFFFFFFFF), R0 486 SBC $(delta >> 32), R1 487 488 // Convert to nSec 489 MOVW $100, R2 490 MULLU R0, R2, (R4, R3) // R4:R3 = R1:R0 * R2 491 MULA R1, R2, R4, R4 492 // w = R2:R1 in nSec 493 MOVW R3, R1 // R4:R3 -> R2:R1 494 MOVW R4, R2 495 496 // multiply nanoseconds by reciprocal of 10**9 (scaled by 2**61) 497 // to get seconds (96 bit scaled result) 498 MOVW $0x89705f41, R3 // 2**61 * 10**-9 499 MULLU R1,R3,(R6,R5) // R7:R6:R5 = R2:R1 * R3 500 MOVW $0,R7 501 MULALU R2,R3,(R7,R6) 502 503 // unscale by discarding low 32 bits, shifting the rest by 29 504 MOVW R6>>29,R6 // R7:R6 = (R7:R6:R5 >> 61) 505 ORR R7<<3,R6 506 MOVW R7>>29,R7 507 508 // subtract (10**9 * sec) from nsec to get nanosecond remainder 509 MOVW $1000000000, R5 // 10**9 510 MULLU R6,R5,(R9,R8) // R9:R8 = R7:R6 * R5 511 MULA R7,R5,R9,R9 512 SUB.S R8,R1 // R2:R1 -= R9:R8 513 SBC R9,R2 514 515 // because reciprocal was a truncated repeating fraction, quotient 516 // may be slightly too small -- adjust to make remainder < 10**9 517 CMP R5,R1 // if remainder > 10**9 518 SUB.HS R5,R1 // remainder -= 10**9 519 ADD.HS $1,R6 // sec += 1 520 521 MOVW R6,sec_lo+0(FP) 522 MOVW R7,sec_hi+4(FP) 523 MOVW R1,nsec+8(FP) 524 RET 525 useQPC: 526 B runtime·nowQPC(SB) // tail call 527 528 // save_g saves the g register (R10) into thread local memory 529 // so that we can call externally compiled 530 // ARM code that will overwrite those registers. 531 // NOTE: runtime.gogo assumes that R1 is preserved by this function. 532 // runtime.mcall assumes this function only clobbers R0 and R11. 533 // Returns with g in R0. 534 // Save the value in the _TEB->TlsSlots array. 535 // Effectively implements TlsSetValue(). 536 // tls_g stores the TLS slot allocated TlsAlloc(). 537 TEXT runtime·save_g(SB),NOSPLIT|NOFRAME,$0 538 MRC 15, 0, R0, C13, C0, 2 539 ADD $0xe10, R0 540 MOVW $runtime·tls_g(SB), R11 541 MOVW (R11), R11 542 MOVW g, R11<<2(R0) 543 MOVW g, R0 // preserve R0 across call to setg<> 544 RET 545 546 // load_g loads the g register from thread-local memory, 547 // for use after calling externally compiled 548 // ARM code that overwrote those registers. 549 // Get the value from the _TEB->TlsSlots array. 550 // Effectively implements TlsGetValue(). 551 TEXT runtime·load_g(SB),NOSPLIT|NOFRAME,$0 552 MRC 15, 0, R0, C13, C0, 2 553 ADD $0xe10, R0 554 MOVW $runtime·tls_g(SB), g 555 MOVW (g), g 556 MOVW g<<2(R0), g 557 RET 558 559 // This is called from rt0_go, which runs on the system stack 560 // using the initial stack allocated by the OS. 561 // It calls back into standard C using the BL below. 562 // To do that, the stack pointer must be 8-byte-aligned. 563 TEXT runtime·_initcgo(SB),NOSPLIT|NOFRAME,$0 564 MOVM.DB.W [R4, R14], (R13) // push {r4, lr} 565 566 // Ensure stack is 8-byte aligned before calling C code 567 MOVW R13, R4 568 BIC $0x7, R13 569 570 // Allocate a TLS slot to hold g across calls to external code 571 MOVW $runtime·_TlsAlloc(SB), R0 572 MOVW (R0), R0 573 BL (R0) 574 575 // Assert that slot is less than 64 so we can use _TEB->TlsSlots 576 CMP $64, R0 577 MOVW $runtime·abort(SB), R1 578 BL.GE (R1) 579 580 // Save Slot into tls_g 581 MOVW $runtime·tls_g(SB), R1 582 MOVW R0, (R1) 583 584 MOVW R4, R13 585 MOVM.IA.W (R13), [R4, R15] // pop {r4, pc} 586 587 // Holds the TLS Slot, which was allocated by TlsAlloc() 588 GLOBL runtime·tls_g+0(SB), NOPTR, $4