src/runtime/asm_386.s 1,116 lines View on github.com → Search inside
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	RET540541CALLFNcall16, 16)542CALLFNcall32, 32)543CALLFNcall64, 64)544CALLFNcall128, 128)545CALLFNcall256, 256)546CALLFNcall512, 512)547CALLFNcall1024, 1024)548CALLFNcall2048, 2048)549CALLFNcall4096, 4096)550CALLFNcall8192, 8192)551CALLFNcall16384, 16384)552CALLFNcall32768, 32768)553CALLFNcall65536, 65536)554CALLFNcall131072, 131072)555CALLFNcall262144, 262144)556CALLFNcall524288, 524288)557CALLFNcall1048576, 1048576)558CALLFNcall2097152, 2097152)559CALLFNcall4194304, 4194304)560CALLFNcall8388608, 8388608)561CALLFNcall16777216, 16777216)562CALLFNcall33554432, 33554432)563CALLFNcall67108864, 67108864)564CALLFNcall134217728, 134217728)565CALLFNcall268435456, 268435456)566CALLFNcall536870912, 536870912)567CALLFNcall1073741824, 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	internalcpu·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.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.