1// Copyright 2009 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.45#include "go_asm.h"6#include "go_tls.h"7#include "funcdata.h"8#include "textflag.h"910// _rt0_386 is common startup code for most 386 systems when using11// internal linking. This is the entry point for the program from the12// kernel for an ordinary -buildmode=exe program. The stack holds the13// number of arguments and the C-style argv.14TEXT _rt0_386(SB),NOSPLIT,$815 MOVL 8(SP), AX // argc16 LEAL 12(SP), BX // argv17 MOVL AX, 0(SP)18 MOVL BX, 4(SP)19 JMP runtime·rt0_go(SB)2021// _rt0_386_lib is common startup code for most 386 systems when22// using -buildmode=c-archive or -buildmode=c-shared. The linker will23// arrange to invoke this function as a global constructor (for24// c-archive) or when the shared library is loaded (for c-shared).25// We expect argc and argv to be passed on the stack following the26// usual C ABI.27TEXT _rt0_386_lib(SB),NOSPLIT,$028 PUSHL BP29 MOVL SP, BP30 PUSHL BX31 PUSHL SI32 PUSHL DI3334 MOVL 8(BP), AX35 MOVL AX, _rt0_386_lib_argc<>(SB)36 MOVL 12(BP), AX37 MOVL AX, _rt0_386_lib_argv<>(SB)3839 CALL runtime·libInit(SB)4041 POPL DI42 POPL SI43 POPL BX44 POPL BP45 RET4647// rt0_lib_go initializes the Go runtime.48// This is started in a separate thread by _rt0_386_lib.49TEXT runtime·rt0_lib_go<ABIInternal>(SB),NOSPLIT,$850 MOVL _rt0_386_lib_argc<>(SB), AX51 MOVL AX, 0(SP)52 MOVL _rt0_386_lib_argv<>(SB), AX53 MOVL AX, 4(SP)54 JMP runtime·rt0_go(SB)5556DATA _rt0_386_lib_argc<>(SB)/4, $057GLOBL _rt0_386_lib_argc<>(SB),NOPTR, $458DATA _rt0_386_lib_argv<>(SB)/4, $059GLOBL _rt0_386_lib_argv<>(SB),NOPTR, $46061TEXT runtime·rt0_go(SB),NOSPLIT|NOFRAME|TOPFRAME,$062 // Copy arguments forward on an even stack.63 // Users of this function jump to it, they don't call it.64 MOVL 0(SP), AX65 MOVL 4(SP), BX66 SUBL $128, SP // plenty of scratch67 ANDL $~15, SP68 MOVL AX, 120(SP) // save argc, argv away69 MOVL BX, 124(SP)7071 // set default stack bounds.72 // _cgo_init may update stackguard.73 MOVL $runtime·g0(SB), BP74 LEAL (-64*1024+104)(SP), BX75 MOVL BX, g_stackguard0(BP)76 MOVL BX, g_stackguard1(BP)77 MOVL BX, (g_stack+stack_lo)(BP)78 MOVL SP, (g_stack+stack_hi)(BP)7980 // find out information about the processor we're on81 // first see if CPUID instruction is supported.82 PUSHFL83 PUSHFL84 XORL $(1<<21), 0(SP) // flip ID bit85 POPFL86 PUSHFL87 POPL AX88 XORL 0(SP), AX89 POPFL // restore EFLAGS90 TESTL $(1<<21), AX91 JNE has_cpuid9293bad_proc: // show that the program requires MMX.94 MOVL $2, 0(SP)95 MOVL $bad_proc_msg<>(SB), 4(SP)96 MOVL $0x3d, 8(SP)97 CALL runtime·write(SB)98 MOVL $1, 0(SP)99 CALL runtime·exit(SB)100 CALL runtime·abort(SB)101102has_cpuid:103 MOVL $0, AX104 CPUID105 MOVL AX, SI106 CMPL AX, $0107 JE nocpuinfo108109 CMPL BX, $0x756E6547 // "Genu"110 JNE notintel111 CMPL DX, $0x49656E69 // "ineI"112 JNE notintel113 CMPL CX, $0x6C65746E // "ntel"114 JNE notintel115 MOVB $1, runtime·isIntel(SB)116notintel:117118 // Load EAX=1 cpuid flags119 MOVL $1, AX120 CPUID121 MOVL CX, DI // Move to global variable clobbers CX when generating PIC122 MOVL AX, runtime·processorVersionInfo(SB)123124 // Check for MMX support125 TESTL $(1<<23), DX // MMX126 JZ bad_proc127128nocpuinfo:129 // if there is an _cgo_init, call it to let it130 // initialize and to set up GS. if not,131 // we set up GS ourselves.132 MOVL _cgo_init(SB), AX133 TESTL AX, AX134 JZ needtls135#ifdef GOOS_android136 // arg 4: TLS base, stored in slot 0 (Android's TLS_SLOT_SELF).137 // Compensate for tls_g (+8).138 MOVL -8(TLS), BX139 MOVL BX, 12(SP)140 MOVL $runtime·tls_g(SB), 8(SP) // arg 3: &tls_g141#else142 MOVL $0, BX143 MOVL BX, 12(SP) // arg 4: not used when using platform's TLS144#ifdef GOOS_windows145 MOVL $runtime·tls_g(SB), 8(SP) // arg 3: &tls_g146#else147 MOVL BX, 8(SP) // arg 3: not used when using platform's TLS148#endif149#endif150 MOVL $setg_gcc<>(SB), BX151 MOVL BX, 4(SP) // arg 2: setg_gcc152 MOVL BP, 0(SP) // arg 1: g0153 CALL AX154155 // update stackguard after _cgo_init156 MOVL $runtime·g0(SB), CX157 MOVL (g_stack+stack_lo)(CX), AX158 ADDL $const_stackGuard, AX159 MOVL AX, g_stackguard0(CX)160 MOVL AX, g_stackguard1(CX)161162#ifndef GOOS_windows163 // skip runtime·ldt0setup(SB) and tls test after _cgo_init for non-windows164 JMP ok165#endif166needtls:167#ifdef GOOS_openbsd168 // skip runtime·ldt0setup(SB) and tls test on OpenBSD in all cases169 JMP ok170#endif171#ifdef GOOS_plan9172 // skip runtime·ldt0setup(SB) and tls test on Plan 9 in all cases173 JMP ok174#endif175176 // set up %gs177 CALL ldt0setup<>(SB)178179 // store through it, to make sure it works180 get_tls(BX)181 MOVL $0x123, g(BX)182 MOVL runtime·m0+m_tls(SB), AX183 CMPL AX, $0x123184 JEQ ok185 MOVL AX, 0 // abort186ok:187 // set up m and g "registers"188 get_tls(BX)189 LEAL runtime·g0(SB), DX190 MOVL DX, g(BX)191 LEAL runtime·m0(SB), AX192193 // save m->g0 = g0194 MOVL DX, m_g0(AX)195 // save g0->m = m0196 MOVL AX, g_m(DX)197198 CALL runtime·emptyfunc(SB) // fault if stack check is wrong199200 // convention is D is always cleared201 CLD202203 CALL runtime·check(SB)204205 // saved argc, argv206 MOVL 120(SP), AX207 MOVL AX, 0(SP)208 MOVL 124(SP), AX209 MOVL AX, 4(SP)210 CALL runtime·args(SB)211 CALL runtime·osinit(SB)212 CALL runtime·schedinit(SB)213214 // create a new goroutine to start program215 PUSHL $runtime·mainPC(SB) // entry216 CALL runtime·newproc(SB)217 POPL AX218219 // start this M220 CALL runtime·mstart(SB)221222 CALL runtime·abort(SB)223 RET224225DATA bad_proc_msg<>+0x00(SB)/61, $"This program can only be run on processors with MMX support.\n"226GLOBL bad_proc_msg<>(SB), RODATA, $61227228DATA runtime·mainPC+0(SB)/4,$runtime·main(SB)229GLOBL runtime·mainPC(SB),RODATA,$4230231TEXT runtime·breakpoint(SB),NOSPLIT,$0-0232 INT $3233 RET234235TEXT runtime·asminit(SB),NOSPLIT,$0-0236 // Linux and MinGW start the FPU in extended double precision.237 // Other operating systems use double precision.238 // Change to double precision to match them,239 // and to match other hardware that only has double.240 FLDCW runtime·controlWord64(SB)241 RET242243TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME,$0244 CALL runtime·mstart0(SB)245 RET // not reached246247/*248 * go-routine249 */250251// void gogo(Gobuf*)252// restore state from Gobuf; longjmp253TEXT runtime·gogo(SB), NOSPLIT, $0-4254 MOVL buf+0(FP), BX // gobuf255 MOVL gobuf_g(BX), DX256 MOVL 0(DX), CX // make sure g != nil257 JMP gogo<>(SB)258259TEXT gogo<>(SB), NOSPLIT, $0260 get_tls(CX)261 MOVL DX, g(CX)262 MOVL gobuf_sp(BX), SP // restore SP263 MOVL gobuf_ctxt(BX), DX264 MOVL $0, gobuf_sp(BX) // clear to help garbage collector265 MOVL $0, gobuf_ctxt(BX)266 MOVL gobuf_pc(BX), BX267 JMP BX268269// func mcall(fn func(*g))270// Switch to m->g0's stack, call fn(g).271// Fn must never return. It should gogo(&g->sched)272// to keep running g.273TEXT runtime·mcall(SB), NOSPLIT, $0-4274 MOVL fn+0(FP), DI275276 get_tls(DX)277 MOVL g(DX), AX // save state in g->sched278 MOVL 0(SP), BX // caller's PC279 MOVL BX, (g_sched+gobuf_pc)(AX)280 LEAL fn+0(FP), BX // caller's SP281 MOVL BX, (g_sched+gobuf_sp)(AX)282283 // switch to m->g0 & its stack, call fn284 MOVL g(DX), BX285 MOVL g_m(BX), BX286 MOVL m_g0(BX), SI287 CMPL SI, AX // if g == m->g0 call badmcall288 JNE 3(PC)289 MOVL $runtime·badmcall(SB), AX290 JMP AX291 MOVL SI, g(DX) // g = m->g0292 MOVL (g_sched+gobuf_sp)(SI), SP // sp = m->g0->sched.sp293 PUSHL AX294 MOVL DI, DX295 MOVL 0(DI), DI296 CALL DI297 POPL AX298 MOVL $runtime·badmcall2(SB), AX299 JMP AX300 RET301302// systemstack_switch is a dummy routine that systemstack leaves at the bottom303// of the G stack. We need to distinguish the routine that304// lives at the bottom of the G stack from the one that lives305// at the top of the system stack because the one at the top of306// the system stack terminates the stack walk (see topofstack()).307TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0308 RET309310// func systemstack(fn func())311TEXT runtime·systemstack(SB), NOSPLIT, $0-4312 MOVL fn+0(FP), DI // DI = fn313 get_tls(CX)314 MOVL g(CX), AX // AX = g315 MOVL g_m(AX), BX // BX = m316317 CMPL AX, m_gsignal(BX)318 JEQ noswitch319320 MOVL m_g0(BX), DX // DX = g0321 CMPL AX, DX322 JEQ noswitch323324 CMPL AX, m_curg(BX)325 JNE bad326327 // switch stacks328 // save our state in g->sched. Pretend to329 // be systemstack_switch if the G stack is scanned.330 CALL gosave_systemstack_switch<>(SB)331332 // switch to g0333 get_tls(CX)334 MOVL DX, g(CX)335 MOVL (g_sched+gobuf_sp)(DX), BX336 MOVL BX, SP337338 // call target function339 MOVL DI, DX340 MOVL 0(DI), DI341 CALL DI342343 // switch back to g344 get_tls(CX)345 MOVL g(CX), AX346 MOVL g_m(AX), BX347 MOVL m_curg(BX), AX348 MOVL AX, g(CX)349 MOVL (g_sched+gobuf_sp)(AX), SP350 MOVL $0, (g_sched+gobuf_sp)(AX)351 RET352353noswitch:354 // already on system stack; tail call the function355 // Using a tail call here cleans up tracebacks since we won't stop356 // at an intermediate systemstack.357 MOVL DI, DX358 MOVL 0(DI), DI359 JMP DI360361bad:362 // Bad: g is not gsignal, not g0, not curg. What is it?363 // Hide call from linker nosplit analysis.364 MOVL $runtime·badsystemstack(SB), AX365 CALL AX366 INT $3367368// func switchToCrashStack0(fn func())369TEXT runtime·switchToCrashStack0(SB), NOSPLIT, $0-4370 MOVL fn+0(FP), AX371372 get_tls(CX)373 MOVL g(CX), BX // BX = g374 MOVL g_m(BX), DX // DX = curm375376 // set g to gcrash377 LEAL runtime·gcrash(SB), BX // g = &gcrash378 MOVL DX, g_m(BX) // g.m = curm379 MOVL BX, m_g0(DX) // curm.g0 = g380 get_tls(CX)381 MOVL BX, g(CX)382383 // switch to crashstack384 MOVL (g_stack+stack_hi)(BX), DX385 SUBL $(4*8), DX386 MOVL DX, SP387388 // call target function389 MOVL AX, DX390 MOVL 0(AX), AX391 CALL AX392393 // should never return394 CALL runtime·abort(SB)395 UNDEF396397/*398 * support for morestack399 */400401// Called during function prolog when more stack is needed.402//403// The traceback routines see morestack on a g0 as being404// the top of a stack (for example, morestack calling newstack405// calling the scheduler calling newm calling gc), so we must406// record an argument size. For that purpose, it has no arguments.407TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0408 // Cannot grow scheduler stack (m->g0).409 get_tls(CX)410 MOVL g(CX), DI411 MOVL g_m(DI), BX412413 // Set g->sched to context in f.414 MOVL 0(SP), AX // f's PC415 MOVL AX, (g_sched+gobuf_pc)(DI)416 LEAL 4(SP), AX // f's SP417 MOVL AX, (g_sched+gobuf_sp)(DI)418 MOVL DX, (g_sched+gobuf_ctxt)(DI)419420 MOVL m_g0(BX), SI421 CMPL g(CX), SI422 JNE 3(PC)423 CALL runtime·badmorestackg0(SB)424 CALL runtime·abort(SB)425426 // Cannot grow signal stack.427 MOVL m_gsignal(BX), SI428 CMPL g(CX), SI429 JNE 3(PC)430 CALL runtime·badmorestackgsignal(SB)431 CALL runtime·abort(SB)432433 // Called from f.434 // Set m->morebuf to f's caller.435 NOP SP // tell vet SP changed - stop checking offsets436 MOVL 4(SP), DI // f's caller's PC437 MOVL DI, (m_morebuf+gobuf_pc)(BX)438 LEAL 8(SP), CX // f's caller's SP439 MOVL CX, (m_morebuf+gobuf_sp)(BX)440 get_tls(CX)441 MOVL g(CX), SI442 MOVL SI, (m_morebuf+gobuf_g)(BX)443444 // Call newstack on m->g0's stack.445 MOVL m_g0(BX), BP446 MOVL BP, g(CX)447 MOVL (g_sched+gobuf_sp)(BP), AX448 MOVL -4(AX), BX // fault if CALL would, before smashing SP449 MOVL AX, SP450 CALL runtime·newstack(SB)451 CALL runtime·abort(SB) // crash if newstack returns452 RET453454TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0-0455 MOVL $0, DX456 JMP runtime·morestack(SB)457458// reflectcall: call a function with the given argument list459// func call(stackArgsType *_type, f *FuncVal, stackArgs *byte, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs).460// we don't have variable-sized frames, so we use a small number461// of constant-sized-frame functions to encode a few bits of size in the pc.462// Caution: ugly multiline assembly macros in your future!463464#define DISPATCH(NAME,MAXSIZE) \465 CMPL CX, $MAXSIZE; \466 JA 3(PC); \467 MOVL $NAME(SB), AX; \468 JMP AX469// Note: can't just "JMP NAME(SB)" - bad inlining results.470471TEXT ·reflectcall(SB), NOSPLIT, $0-28472 MOVL frameSize+20(FP), CX473 DISPATCH(runtime·call16, 16)474 DISPATCH(runtime·call32, 32)475 DISPATCH(runtime·call64, 64)476 DISPATCH(runtime·call128, 128)477 DISPATCH(runtime·call256, 256)478 DISPATCH(runtime·call512, 512)479 DISPATCH(runtime·call1024, 1024)480 DISPATCH(runtime·call2048, 2048)481 DISPATCH(runtime·call4096, 4096)482 DISPATCH(runtime·call8192, 8192)483 DISPATCH(runtime·call16384, 16384)484 DISPATCH(runtime·call32768, 32768)485 DISPATCH(runtime·call65536, 65536)486 DISPATCH(runtime·call131072, 131072)487 DISPATCH(runtime·call262144, 262144)488 DISPATCH(runtime·call524288, 524288)489 DISPATCH(runtime·call1048576, 1048576)490 DISPATCH(runtime·call2097152, 2097152)491 DISPATCH(runtime·call4194304, 4194304)492 DISPATCH(runtime·call8388608, 8388608)493 DISPATCH(runtime·call16777216, 16777216)494 DISPATCH(runtime·call33554432, 33554432)495 DISPATCH(runtime·call67108864, 67108864)496 DISPATCH(runtime·call134217728, 134217728)497 DISPATCH(runtime·call268435456, 268435456)498 DISPATCH(runtime·call536870912, 536870912)499 DISPATCH(runtime·call1073741824, 1073741824)500 MOVL $runtime·badreflectcall(SB), AX501 JMP AX502503#define CALLFN(NAME,MAXSIZE) \504TEXT NAME(SB), WRAPPER, $MAXSIZE-28; \505 NO_LOCAL_POINTERS; \506 /* copy arguments to stack */ \507 MOVL stackArgs+8(FP), SI; \508 MOVL stackArgsSize+12(FP), CX; \509 MOVL SP, DI; \510 REP;MOVSB; \511 /* call function */ \512 MOVL f+4(FP), DX; \513 MOVL (DX), AX; \514 PCDATA $PCDATA_StackMapIndex, $0; \515 CALL AX; \516 /* copy return values back */ \517 MOVL stackArgsType+0(FP), DX; \518 MOVL stackArgs+8(FP), DI; \519 MOVL stackArgsSize+12(FP), CX; \520 MOVL stackRetOffset+16(FP), BX; \521 MOVL SP, SI; \522 ADDL BX, DI; \523 ADDL BX, SI; \524 SUBL BX, CX; \525 CALL callRet<>(SB); \526 RET527528// callRet copies return values back at the end of call*. This is a529// separate function so it can allocate stack space for the arguments530// to reflectcallmove. It does not follow the Go ABI; it expects its531// arguments in registers.532TEXT callRet<>(SB), NOSPLIT, $20-0533 MOVL DX, 0(SP)534 MOVL DI, 4(SP)535 MOVL SI, 8(SP)536 MOVL CX, 12(SP)537 MOVL $0, 16(SP)538 CALL runtime·reflectcallmove(SB)539 RET540541CALLFN(·call16, 16)542CALLFN(·call32, 32)543CALLFN(·call64, 64)544CALLFN(·call128, 128)545CALLFN(·call256, 256)546CALLFN(·call512, 512)547CALLFN(·call1024, 1024)548CALLFN(·call2048, 2048)549CALLFN(·call4096, 4096)550CALLFN(·call8192, 8192)551CALLFN(·call16384, 16384)552CALLFN(·call32768, 32768)553CALLFN(·call65536, 65536)554CALLFN(·call131072, 131072)555CALLFN(·call262144, 262144)556CALLFN(·call524288, 524288)557CALLFN(·call1048576, 1048576)558CALLFN(·call2097152, 2097152)559CALLFN(·call4194304, 4194304)560CALLFN(·call8388608, 8388608)561CALLFN(·call16777216, 16777216)562CALLFN(·call33554432, 33554432)563CALLFN(·call67108864, 67108864)564CALLFN(·call134217728, 134217728)565CALLFN(·call268435456, 268435456)566CALLFN(·call536870912, 536870912)567CALLFN(·call1073741824, 1073741824)568569TEXT runtime·procyieldAsm(SB),NOSPLIT,$0-0570 MOVL cycles+0(FP), AX571 TESTL AX, AX572 JZ done573again:574 PAUSE575 SUBL $1, AX576 JNZ again577done:578 RET579580TEXT ·publicationBarrier(SB),NOSPLIT,$0-0581 // Stores are already ordered on x86, so this is just a582 // compile barrier.583 RET584585// Save state of caller into g->sched,586// but using fake PC from systemstack_switch.587// Must only be called from functions with no locals ($0)588// or else unwinding from systemstack_switch is incorrect.589TEXT gosave_systemstack_switch<>(SB),NOSPLIT,$0590 PUSHL AX591 PUSHL BX592 get_tls(BX)593 MOVL g(BX), BX594 LEAL arg+0(FP), AX595 MOVL AX, (g_sched+gobuf_sp)(BX)596 MOVL $runtime·systemstack_switch(SB), AX597 MOVL AX, (g_sched+gobuf_pc)(BX)598 // Assert ctxt is zero. See func save.599 MOVL (g_sched+gobuf_ctxt)(BX), AX600 TESTL AX, AX601 JZ 2(PC)602 CALL runtime·abort(SB)603 POPL BX604 POPL AX605 RET606607// func asmcgocall_no_g(fn, arg unsafe.Pointer)608// Call fn(arg) aligned appropriately for the gcc ABI.609// Called on a system stack, and there may be no g yet (during needm).610TEXT ·asmcgocall_no_g(SB),NOSPLIT,$0-8611 MOVL fn+0(FP), AX612 MOVL arg+4(FP), BX613 MOVL SP, DX614 SUBL $32, SP615 ANDL $~15, SP // alignment, perhaps unnecessary616 MOVL DX, 8(SP) // save old SP617 MOVL BX, 0(SP) // first argument in x86-32 ABI618 CALL AX619 MOVL 8(SP), DX620 MOVL DX, SP621 RET622623// func asmcgocall(fn, arg unsafe.Pointer) int32624// Call fn(arg) on the scheduler stack,625// aligned appropriately for the gcc ABI.626// See cgocall.go for more details.627TEXT ·asmcgocall(SB),NOSPLIT,$0-12628 MOVL fn+0(FP), AX629 MOVL arg+4(FP), BX630631 MOVL SP, DX632633 // Figure out if we need to switch to m->g0 stack.634 // We get called to create new OS threads too, and those635 // come in on the m->g0 stack already. Or we might already636 // be on the m->gsignal stack.637#ifdef GOOS_windows638 // On Windows, get_tls might return garbage if the thread639 // has never called into Go, so check tls_g directly.640 MOVL runtime·tls_g(SB), CX641 CMPL CX, $0642 JEQ nosave643#endif644 get_tls(CX)645 MOVL g(CX), DI646 CMPL DI, $0647 JEQ nosave // Don't even have a G yet.648 MOVL g_m(DI), BP649 CMPL DI, m_gsignal(BP)650 JEQ noswitch651 MOVL m_g0(BP), SI652 CMPL DI, SI653 JEQ noswitch654 CALL gosave_systemstack_switch<>(SB)655 get_tls(CX)656 MOVL SI, g(CX)657 MOVL (g_sched+gobuf_sp)(SI), SP658659noswitch:660 // Now on a scheduling stack (a pthread-created stack).661 SUBL $32, SP662 ANDL $~15, SP // alignment, perhaps unnecessary663 MOVL DI, 8(SP) // save g664 MOVL (g_stack+stack_hi)(DI), DI665 SUBL DX, DI666 MOVL DI, 4(SP) // save depth in stack (can't just save SP, as stack might be copied during a callback)667 MOVL BX, 0(SP) // first argument in x86-32 ABI668 CALL AX669670 // Restore registers, g, stack pointer.671 get_tls(CX)672 MOVL 8(SP), DI673 MOVL (g_stack+stack_hi)(DI), SI674 SUBL 4(SP), SI675 MOVL DI, g(CX)676 MOVL SI, SP677678 MOVL AX, ret+8(FP)679 RET680nosave:681 // Now on a scheduling stack (a pthread-created stack).682 SUBL $32, SP683 ANDL $~15, SP // alignment, perhaps unnecessary684 MOVL DX, 4(SP) // save original stack pointer685 MOVL BX, 0(SP) // first argument in x86-32 ABI686 CALL AX687688 MOVL 4(SP), CX // restore original stack pointer689 MOVL CX, SP690 MOVL AX, ret+8(FP)691 RET692693// cgocallback(fn, frame unsafe.Pointer, ctxt uintptr)694// See cgocall.go for more details.695TEXT ·cgocallback(SB),NOSPLIT,$12-12 // Frame size must match commented places below696 NO_LOCAL_POINTERS697698 // Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g.699 // It is used to dropm while thread is exiting.700 MOVL fn+0(FP), AX701 CMPL AX, $0702 JNE loadg703 // Restore the g from frame.704 get_tls(CX)705 MOVL frame+4(FP), BX706 MOVL BX, g(CX)707 JMP dropm708709loadg:710 // If g is nil, Go did not create the current thread,711 // or if this thread never called into Go on pthread platforms.712 // Call needm to obtain one for temporary use.713 // In this case, we're running on the thread stack, so there's714 // lots of space, but the linker doesn't know. Hide the call from715 // the linker analysis by using an indirect call through AX.716 get_tls(CX)717#ifdef GOOS_windows718 MOVL $0, BP719 CMPL CX, $0720 JEQ needm721#endif722 MOVL g(CX), BP723 CMPL BP, $0724 JEQ needm725 MOVL g_m(BP), BP726 MOVL BP, savedm-4(SP) // saved copy of oldm727 JMP havem728needm:729 MOVL $runtime·needAndBindM(SB), AX730 CALL AX731 MOVL $0, savedm-4(SP)732 get_tls(CX)733 MOVL g(CX), BP734 MOVL g_m(BP), BP735736 // Set m->sched.sp = SP, so that if a panic happens737 // during the function we are about to execute, it will738 // have a valid SP to run on the g0 stack.739 // The next few lines (after the havem label)740 // will save this SP onto the stack and then write741 // the same SP back to m->sched.sp. That seems redundant,742 // but if an unrecovered panic happens, unwindm will743 // restore the g->sched.sp from the stack location744 // and then systemstack will try to use it. If we don't set it here,745 // that restored SP will be uninitialized (typically 0) and746 // will not be usable.747 MOVL m_g0(BP), SI748 MOVL SP, (g_sched+gobuf_sp)(SI)749750havem:751 // Now there's a valid m, and we're running on its m->g0.752 // Save current m->g0->sched.sp on stack and then set it to SP.753 // Save current sp in m->g0->sched.sp in preparation for754 // switch back to m->curg stack.755 // NOTE: unwindm knows that the saved g->sched.sp is at 0(SP).756 MOVL m_g0(BP), SI757 MOVL (g_sched+gobuf_sp)(SI), AX758 MOVL AX, 0(SP)759 MOVL SP, (g_sched+gobuf_sp)(SI)760761 // Switch to m->curg stack and call runtime.cgocallbackg.762 // Because we are taking over the execution of m->curg763 // but *not* resuming what had been running, we need to764 // save that information (m->curg->sched) so we can restore it.765 // We can restore m->curg->sched.sp easily, because calling766 // runtime.cgocallbackg leaves SP unchanged upon return.767 // To save m->curg->sched.pc, we push it onto the curg stack and768 // open a frame the same size as cgocallback's g0 frame.769 // Once we switch to the curg stack, the pushed PC will appear770 // to be the return PC of cgocallback, so that the traceback771 // will seamlessly trace back into the earlier calls.772 MOVL m_curg(BP), SI773 MOVL SI, g(CX)774 MOVL (g_sched+gobuf_sp)(SI), DI // prepare stack as DI775 MOVL (g_sched+gobuf_pc)(SI), BP776 MOVL BP, -4(DI) // "push" return PC on the g stack777 // Gather our arguments into registers.778 MOVL fn+0(FP), AX779 MOVL frame+4(FP), BX780 MOVL ctxt+8(FP), CX781 LEAL -(4+12)(DI), SP // Must match declared frame size782 MOVL AX, 0(SP)783 MOVL BX, 4(SP)784 MOVL CX, 8(SP)785 CALL runtime·cgocallbackg(SB)786787 // Restore g->sched (== m->curg->sched) from saved values.788 get_tls(CX)789 MOVL g(CX), SI790 MOVL 12(SP), BP // Must match declared frame size791 MOVL BP, (g_sched+gobuf_pc)(SI)792 LEAL (12+4)(SP), DI // Must match declared frame size793 MOVL DI, (g_sched+gobuf_sp)(SI)794795 // Switch back to m->g0's stack and restore m->g0->sched.sp.796 // (Unlike m->curg, the g0 goroutine never uses sched.pc,797 // so we do not have to restore it.)798 MOVL g(CX), BP799 MOVL g_m(BP), BP800 MOVL m_g0(BP), SI801 MOVL SI, g(CX)802 MOVL (g_sched+gobuf_sp)(SI), SP803 MOVL 0(SP), AX804 MOVL AX, (g_sched+gobuf_sp)(SI)805806 // If the m on entry was nil, we called needm above to borrow an m,807 // 1. for the duration of the call on non-pthread platforms,808 // 2. or the duration of the C thread alive on pthread platforms.809 // If the m on entry wasn't nil,810 // 1. the thread might be a Go thread,811 // 2. or it wasn't the first call from a C thread on pthread platforms,812 // since then we skip dropm to reuse the m in the first call.813 MOVL savedm-4(SP), DX814 CMPL DX, $0815 JNE droppedm816817 // Skip dropm to reuse it in the next call, when a pthread key has been created.818 MOVL _cgo_pthread_key_created(SB), DX819 // It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm.820 CMPL DX, $0821 JEQ dropm822 CMPL (DX), $0823 JNE droppedm824825dropm:826 MOVL $runtime·dropm(SB), AX827 CALL AX828droppedm:829830 // Done!831 RET832833// void setg(G*); set g. for use by needm.834TEXT runtime·setg(SB), NOSPLIT, $0-4835 MOVL gg+0(FP), BX836#ifdef GOOS_windows837 MOVL runtime·tls_g(SB), CX838 CMPL BX, $0839 JNE settls840 MOVL $0, 0(CX)(FS)841 RET842settls:843 MOVL g_m(BX), AX844 LEAL m_tls(AX), AX845 MOVL AX, 0(CX)(FS)846#endif847 get_tls(CX)848 MOVL BX, g(CX)849 RET850851// void setg_gcc(G*); set g. for use by gcc852TEXT setg_gcc<>(SB), NOSPLIT, $0853 get_tls(AX)854 MOVL gg+0(FP), DX855 MOVL DX, g(AX)856 RET857858TEXT runtime·abort(SB),NOSPLIT,$0-0859 INT $3860loop:861 JMP loop862863// check that SP is in range [g->stack.lo, g->stack.hi)864TEXT runtime·stackcheck(SB), NOSPLIT, $0-0865 get_tls(CX)866 MOVL g(CX), AX867 CMPL (g_stack+stack_hi)(AX), SP868 JHI 2(PC)869 CALL runtime·abort(SB)870 CMPL SP, (g_stack+stack_lo)(AX)871 JHI 2(PC)872 CALL runtime·abort(SB)873 RET874875// func cputicks() int64876TEXT runtime·cputicks(SB),NOSPLIT,$0-8877 // LFENCE/MFENCE instruction support is dependent on SSE2.878 // When no SSE2 support is present do not enforce any serialization879 // since using CPUID to serialize the instruction stream is880 // very costly.881#ifdef GO386_softfloat882 JMP rdtsc // no fence instructions available883#endif884 CMPB internal∕cpu·X86+const_offsetX86HasRDTSCP(SB), $1885 JNE fences886 // Instruction stream serializing RDTSCP is supported.887 // RDTSCP is supported by Intel Nehalem (2008) and888 // AMD K8 Rev. F (2006) and newer.889 RDTSCP890done:891 MOVL AX, ret_lo+0(FP)892 MOVL DX, ret_hi+4(FP)893 RET894fences:895 // MFENCE is instruction stream serializing and flushes the896 // store buffers on AMD. The serialization semantics of LFENCE on AMD897 // are dependent on MSR C001_1029 and CPU generation.898 // LFENCE on Intel does wait for all previous instructions to have executed.899 // Intel recommends MFENCE;LFENCE in its manuals before RDTSC to have all900 // previous instructions executed and all previous loads and stores to globally visible.901 // Using MFENCE;LFENCE here aligns the serializing properties without902 // runtime detection of CPU manufacturer.903 MFENCE904 LFENCE905rdtsc:906 RDTSC907 JMP done908909TEXT ldt0setup<>(SB),NOSPLIT,$16-0910#ifdef GOOS_windows911 CALL runtime·wintls(SB)912#endif913 // set up ldt 7 to point at m0.tls914 // ldt 1 would be fine on Linux, but on OS X, 7 is as low as we can go.915 // the entry number is just a hint. setldt will set up GS with what it used.916 MOVL $7, 0(SP)917 LEAL runtime·m0+m_tls(SB), AX918 MOVL AX, 4(SP)919 MOVL $32, 8(SP) // sizeof(tls array)920 CALL runtime·setldt(SB)921 RET922923TEXT runtime·emptyfunc(SB),0,$0-0924 RET925926// Called from cgo wrappers, this function returns g->m->curg.stack.hi.927// Must obey the gcc calling convention.928TEXT _cgo_topofstack(SB),NOSPLIT,$0929 get_tls(CX)930 MOVL g(CX), AX931 MOVL g_m(AX), AX932 MOVL m_curg(AX), AX933 MOVL (g_stack+stack_hi)(AX), AX934 RET935936// The top-most function running on a goroutine937// returns to goexit+PCQuantum.938TEXT runtime·goexit(SB),NOSPLIT|TOPFRAME,$0-0939 BYTE $0x90 // NOP940 CALL runtime·goexit1(SB) // does not return941 // traceback from goexit1 must hit code range of goexit942 BYTE $0x90 // NOP943944// Add a module's moduledata to the linked list of moduledata objects. This945// is called from .init_array by a function generated in the linker and so946// follows the platform ABI wrt register preservation -- it only touches AX,947// CX (implicitly) and DX, but it does not follow the ABI wrt arguments:948// instead the pointer to the moduledata is passed in AX.949TEXT runtime·addmoduledata(SB),NOSPLIT,$0-0950 MOVL runtime·lastmoduledatap(SB), DX951 MOVL AX, moduledata_next(DX)952 MOVL AX, runtime·lastmoduledatap(SB)953 RET954955TEXT runtime·uint32tofloat64(SB),NOSPLIT,$8-12956 MOVL a+0(FP), AX957 MOVL AX, 0(SP)958 MOVL $0, 4(SP)959 FMOVV 0(SP), F0960 FMOVDP F0, ret+4(FP)961 RET962963TEXT runtime·float64touint32(SB),NOSPLIT,$12-12964 FMOVD a+0(FP), F0965 FSTCW 0(SP)966 FLDCW runtime·controlWord64trunc(SB)967 FMOVVP F0, 4(SP)968 FLDCW 0(SP)969 MOVL 4(SP), AX970 MOVL AX, ret+8(FP)971 RET972973// gcWriteBarrier informs the GC about heap pointer writes.974//975// gcWriteBarrier returns space in a write barrier buffer which976// should be filled in by the caller.977// gcWriteBarrier does NOT follow the Go ABI. It accepts the978// number of bytes of buffer needed in DI, and returns a pointer979// to the buffer space in DI.980// It clobbers FLAGS. It does not clobber any general-purpose registers,981// but may clobber others (e.g., SSE registers).982// Typical use would be, when doing *(CX+88) = AX983// CMPL $0, runtime.writeBarrier(SB)984// JEQ dowrite985// CALL runtime.gcBatchBarrier2(SB)986// MOVL AX, (DI)987// MOVL 88(CX), DX988// MOVL DX, 4(DI)989// dowrite:990// MOVL AX, 88(CX)991TEXT gcWriteBarrier<>(SB),NOSPLIT,$28992 // Save the registers clobbered by the fast path. This is slightly993 // faster than having the caller spill these.994 MOVL CX, 20(SP)995 MOVL BX, 24(SP)996retry:997 // TODO: Consider passing g.m.p in as an argument so they can be shared998 // across a sequence of write barriers.999 get_tls(BX)1000 MOVL g(BX), BX1001 MOVL g_m(BX), BX1002 MOVL m_p(BX), BX1003 // Get current buffer write position.1004 MOVL (p_wbBuf+wbBuf_next)(BX), CX // original next position1005 ADDL DI, CX // new next position1006 // Is the buffer full?1007 CMPL CX, (p_wbBuf+wbBuf_end)(BX)1008 JA flush1009 // Commit to the larger buffer.1010 MOVL CX, (p_wbBuf+wbBuf_next)(BX)1011 // Make return value (the original next position)1012 SUBL DI, CX1013 MOVL CX, DI1014 // Restore registers.1015 MOVL 20(SP), CX1016 MOVL 24(SP), BX1017 RET10181019flush:1020 // Save all general purpose registers since these could be1021 // clobbered by wbBufFlush and were not saved by the caller.1022 MOVL DI, 0(SP)1023 MOVL AX, 4(SP)1024 // BX already saved1025 // CX already saved1026 MOVL DX, 8(SP)1027 MOVL BP, 12(SP)1028 MOVL SI, 16(SP)1029 // DI already saved10301031 CALL runtime·wbBufFlush(SB)10321033 MOVL 0(SP), DI1034 MOVL 4(SP), AX1035 MOVL 8(SP), DX1036 MOVL 12(SP), BP1037 MOVL 16(SP), SI1038 JMP retry10391040TEXT runtime·gcWriteBarrier1<ABIInternal>(SB),NOSPLIT,$01041 MOVL $4, DI1042 JMP gcWriteBarrier<>(SB)1043TEXT runtime·gcWriteBarrier2<ABIInternal>(SB),NOSPLIT,$01044 MOVL $8, DI1045 JMP gcWriteBarrier<>(SB)1046TEXT runtime·gcWriteBarrier3<ABIInternal>(SB),NOSPLIT,$01047 MOVL $12, DI1048 JMP gcWriteBarrier<>(SB)1049TEXT runtime·gcWriteBarrier4<ABIInternal>(SB),NOSPLIT,$01050 MOVL $16, DI1051 JMP gcWriteBarrier<>(SB)1052TEXT runtime·gcWriteBarrier5<ABIInternal>(SB),NOSPLIT,$01053 MOVL $20, DI1054 JMP gcWriteBarrier<>(SB)1055TEXT runtime·gcWriteBarrier6<ABIInternal>(SB),NOSPLIT,$01056 MOVL $24, DI1057 JMP gcWriteBarrier<>(SB)1058TEXT runtime·gcWriteBarrier7<ABIInternal>(SB),NOSPLIT,$01059 MOVL $28, DI1060 JMP gcWriteBarrier<>(SB)1061TEXT runtime·gcWriteBarrier8<ABIInternal>(SB),NOSPLIT,$01062 MOVL $32, DI1063 JMP gcWriteBarrier<>(SB)10641065TEXT runtime·panicBounds<ABIInternal>(SB),NOSPLIT,$40-01066 NO_LOCAL_POINTERS1067 // Save all int registers that could have an index in them.1068 // They may be pointers, but if they are they are dead.1069 MOVL AX, 8(SP)1070 MOVL CX, 12(SP)1071 MOVL DX, 16(SP)1072 MOVL BX, 20(SP)1073 // skip SP @ 24(SP)1074 MOVL BP, 28(SP)1075 MOVL SI, 32(SP)1076 MOVL DI, 36(SP)10771078 MOVL SP, AX // hide SP read from vet1079 MOVL 40(AX), AX // PC immediately after call to panicBounds1080 MOVL AX, 0(SP)1081 LEAL 8(SP), AX1082 MOVL AX, 4(SP)1083 CALL runtime·panicBounds32<ABIInternal>(SB)1084 RET10851086TEXT runtime·panicExtend<ABIInternal>(SB),NOSPLIT,$40-01087 NO_LOCAL_POINTERS1088 // Save all int registers that could have an index in them.1089 // They may be pointers, but if they are they are dead.1090 MOVL AX, 8(SP)1091 MOVL CX, 12(SP)1092 MOVL DX, 16(SP)1093 MOVL BX, 20(SP)1094 // skip SP @ 24(SP)1095 MOVL BP, 28(SP)1096 MOVL SI, 32(SP)1097 MOVL DI, 36(SP)10981099 MOVL SP, AX // hide SP read from vet1100 MOVL 40(AX), AX // PC immediately after call to panicExtend1101 MOVL AX, 0(SP)1102 LEAL 8(SP), AX1103 MOVL AX, 4(SP)1104 CALL runtime·panicBounds32X<ABIInternal>(SB)1105 RET11061107#ifdef GOOS_android1108// Use the free TLS_SLOT_APP slot #2 on Android Q.1109// Earlier androids are set up in gcc_android.c.1110DATA runtime·tls_g+0(SB)/4, $81111GLOBL runtime·tls_g+0(SB), NOPTR, $41112#endif1113#ifdef GOOS_windows1114GLOBL runtime·tls_g+0(SB), NOPTR, $41115#endif
Findings
✓ No findings reported for this file.