src/runtime/asm_s390x.s 983 lines View on github.com → Search inside
1// Copyright 2016 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_s390x_lib is common startup code for s390x systems when11// using -buildmode=c-archive or -buildmode=c-shared. The linker will12// arrange to invoke this function as a global constructor (for13// c-archive) or when the shared library is loaded (for c-shared).14// We expect argc and argv to be passed in the usual C ABI registers15// R2 and R3.16TEXT _rt0_s390x_lib(SB), NOSPLIT|NOFRAME, $017	STMG	R6, R15, 48(R15)18	MOVD	R2, _rt0_s390x_lib_argc<>(SB)19	MOVD	R3, _rt0_s390x_lib_argv<>(SB)2021	// Save R6-R15 in the register save area of the calling function.22	STMG	R6, R15, 48(R15)2324	// Allocate 80 bytes on the stack.25	MOVD	$-80(R15), R152627	// Save F8-F15 in our stack frame.28	FMOVD	F8, 16(R15)29	FMOVD	F9, 24(R15)30	FMOVD	F10, 32(R15)31	FMOVD	F11, 40(R15)32	FMOVD	F12, 48(R15)33	FMOVD	F13, 56(R15)34	FMOVD	F14, 64(R15)35	FMOVD	F15, 72(R15)3637	// Initialize g as nil in case of using g later e.g. sigaction in cgo_sigaction.go38	XOR	g, g3940	MOVD	$runtime·libInit(SB), R141	BL	R14243	// Restore F8-F15 from our stack frame.44	FMOVD	16(R15), F845	FMOVD	24(R15), F946	FMOVD	32(R15), F1047	FMOVD	40(R15), F1148	FMOVD	48(R15), F1249	FMOVD	56(R15), F1350	FMOVD	64(R15), F1451	FMOVD	72(R15), F1552	MOVD	$80(R15), R155354	// Restore R6-R15.55	LMG	48(R15), R6, R1556	RET5758// rt0_lib_go initializes the Go runtime.59// This is started in a separate thread by _rt0_s390x_lib.60TEXT runtime·rt0_lib_go<ABIInternal>(SB), NOSPLIT|NOFRAME, $061	MOVD	_rt0_s390x_lib_argc<>(SB), R262	MOVD	_rt0_s390x_lib_argv<>(SB), R363	MOVD	$runtime·rt0_go(SB), R164	BR	R16566DATA _rt0_s390x_lib_argc<>(SB)/8, $067GLOBL _rt0_s390x_lib_argc<>(SB), NOPTR, $868DATA _rt0_s390x_lib_argv<>(SB)/8, $069GLOBL _rt0_s390x_lib_argv<>(SB), NOPTR, $87071TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$072	// R2 = argc; R3 = argv; R11 = temp; R13 = g; R15 = stack pointer73	// C TLS base pointer in AR0:AR17475	// initialize essential registers76	XOR	R0, R07778	SUB	$24, R1579	MOVW	R2, 8(R15) // argc80	MOVD	R3, 16(R15) // argv8182	// create istack out of the given (operating system) stack.83	// _cgo_init may update stackguard.84	MOVD	$runtime·g0(SB), g85	MOVD	R15, R1186	SUB	$(64*1024), R1187	MOVD	R11, g_stackguard0(g)88	MOVD	R11, g_stackguard1(g)89	MOVD	R11, (g_stack+stack_lo)(g)90	MOVD	R15, (g_stack+stack_hi)(g)9192	// if there is a _cgo_init, call it using the gcc ABI.93	MOVD	_cgo_init(SB), R1194	CMPBEQ	R11, $0, nocgo95	MOVW	AR0, R4			// (AR0 << 32 | AR1) is the TLS base pointer; MOVD is translated to EAR96	SLD	$32, R4, R497	MOVW	AR1, R4			// arg 2: TLS base pointer98	MOVD	$setg_gcc<>(SB), R3 	// arg 1: setg99	MOVD	g, R2			// arg 0: G100	// C functions expect 160 bytes of space on caller stack frame101	// and an 8-byte aligned stack pointer102	MOVD	R15, R9			// save current stack (R9 is preserved in the Linux ABI)103	SUB	$160, R15		// reserve 160 bytes104	MOVD    $~7, R6105	AND 	R6, R15			// 8-byte align106	BL	R11			// this call clobbers volatile registers according to Linux ABI (R0-R5, R14)107	MOVD	R9, R15			// restore stack108	XOR	R0, R0			// zero R0109110nocgo:111	// update stackguard after _cgo_init112	MOVD	(g_stack+stack_lo)(g), R2113	ADD	$const_stackGuard, R2114	MOVD	R2, g_stackguard0(g)115	MOVD	R2, g_stackguard1(g)116117	// set the per-goroutine and per-mach "registers"118	MOVD	$runtime·m0(SB), R2119120	// save m->g0 = g0121	MOVD	g, m_g0(R2)122	// save m0 to g0->m123	MOVD	R2, g_m(g)124125	BL	runtime·check(SB)126127	// argc/argv are already prepared on stack128	BL	runtime·args(SB)129	BL	runtime·checkS390xCPU(SB)130	BL	runtime·osinit(SB)131	BL	runtime·schedinit(SB)132133	// create a new goroutine to start program134	MOVD	$runtime·mainPC(SB), R2		// entry135	SUB     $16, R15136	MOVD 	R2, 8(R15)137	MOVD 	$0, 0(R15)138	BL	runtime·newproc(SB)139	ADD	$16, R15140141	// start this M142	BL	runtime·mstart(SB)143144	MOVD	$0, 1(R0)145	RET146147DATA	runtime·mainPC+0(SB)/8,$runtime·main<ABIInternal>(SB)148GLOBL	runtime·mainPC(SB),RODATA,$8149150TEXT runtime·breakpoint(SB),NOSPLIT|NOFRAME,$0-0151	BRRK152	RET153154TEXT runtime·asminit(SB),NOSPLIT|NOFRAME,$0-0155	RET156157TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME,$0158	CALL	runtime·mstart0(SB)159	RET // not reached160161/*162 *  go-routine163 */164165// void gogo(Gobuf*)166// restore state from Gobuf; longjmp167TEXT runtime·gogo(SB), NOSPLIT|NOFRAME, $0-8168	MOVD	buf+0(FP), R5169	MOVD	gobuf_g(R5), R6170	MOVD	0(R6), R7	// make sure g != nil171	BR	gogo<>(SB)172173TEXT gogo<>(SB), NOSPLIT|NOFRAME, $0174	MOVD	R6, g175	BL	runtime·save_g(SB)176177	MOVD	0(g), R4178	MOVD	gobuf_sp(R5), R15179	MOVD	gobuf_lr(R5), LR180	MOVD	gobuf_ctxt(R5), R12181	MOVD	$0, gobuf_sp(R5)182	MOVD	$0, gobuf_lr(R5)183	MOVD	$0, gobuf_ctxt(R5)184	CMP	R0, R0 // set condition codes for == test, needed by stack split185	MOVD	gobuf_pc(R5), R6186	BR	(R6)187188// void mcall(fn func(*g))189// Switch to m->g0's stack, call fn(g).190// Fn must never return.  It should gogo(&g->sched)191// to keep running g.192TEXT runtime·mcall<ABIInternal>(SB), NOSPLIT, $-8-8193	MOVD	R2, R12				// context194	// Save caller state in g->sched195	MOVD	R15, (g_sched+gobuf_sp)(g)196	MOVD	LR, (g_sched+gobuf_pc)(g)197	MOVD	$0, (g_sched+gobuf_lr)(g)198199	// Switch to m->g0 & its stack, call fn.200	MOVD	g, R2201	MOVD	g_m(g), R4202	MOVD	m_g0(R4), g203	BL	runtime·save_g(SB)204	CMP	g, R2205	BNE	2(PC)206	BR	runtime·badmcall(SB)207	MOVD	0(R12), R4			// code pointer208	MOVD	(g_sched+gobuf_sp)(g), R15	// sp = m->g0->sched.sp209	SUB	$16, R15210	MOVD	R2, 8(R15)211	MOVD	$0, 0(R15)212	BL	(R4)213	BR	runtime·badmcall2(SB)214215// systemstack_switch is a dummy routine that systemstack leaves at the bottom216// of the G stack.  We need to distinguish the routine that217// lives at the bottom of the G stack from the one that lives218// at the top of the system stack because the one at the top of219// the system stack terminates the stack walk (see topofstack()).220TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0221	UNDEF222	BL	(LR)	// make sure this function is not leaf223	RET224225// func systemstack(fn func())226TEXT runtime·systemstack(SB), NOSPLIT, $0-8227	MOVD	fn+0(FP), R3	// R3 = fn228	MOVD	R3, R12		// context229	MOVD	g_m(g), R4	// R4 = m230231	MOVD	m_gsignal(R4), R5	// R5 = gsignal232	CMPBEQ	g, R5, noswitch233234	MOVD	m_g0(R4), R5	// R5 = g0235	CMPBEQ	g, R5, noswitch236237	MOVD	m_curg(R4), R6238	CMPBEQ	g, R6, switch239240	// Bad: g is not gsignal, not g0, not curg. What is it?241	// Hide call from linker nosplit analysis.242	MOVD	$runtime·badsystemstack(SB), R3243	BL	(R3)244	BL	runtime·abort(SB)245246switch:247	// save our state in g->sched.  Pretend to248	// be systemstack_switch if the G stack is scanned.249	BL	gosave_systemstack_switch<>(SB)250251	// switch to g0252	MOVD	R5, g253	BL	runtime·save_g(SB)254	MOVD	(g_sched+gobuf_sp)(g), R15255256	// call target function257	MOVD	0(R12), R3	// code pointer258	BL	(R3)259260	// switch back to g261	MOVD	g_m(g), R3262	MOVD	m_curg(R3), g263	BL	runtime·save_g(SB)264	MOVD	(g_sched+gobuf_sp)(g), R15265	MOVD	$0, (g_sched+gobuf_sp)(g)266	RET267268noswitch:269	// already on m stack, just call directly270	// Using a tail call here cleans up tracebacks since we won't stop271	// at an intermediate systemstack.272	MOVD	0(R12), R3	// code pointer273	MOVD	0(R15), LR	// restore LR274	ADD	$8, R15275	BR	(R3)276277// func switchToCrashStack0(fn func())278TEXT runtime·switchToCrashStack0<ABIInternal>(SB), NOSPLIT, $0-8279	MOVD	R2, R12		// context280	MOVD	g_m(g), R2	// curm281282	// set g to gcrash283	MOVD	$runtime·gcrash(SB), g	// g = &gcrash284	BL	runtime·save_g(SB)285	MOVD	R2, g_m(g)	// g.m = curm286	MOVD	g, m_g0(R2)	// curm.g0 = g287288	// switch to crashstack289	MOVD	(g_stack+stack_hi)(g), R2290	ADD	$(-4*8), R2, R15291292	// call target function293	MOVD	0(R12), R3	// code pointer294	BL	(R3)295296	// should never return297	BL	runtime·abort(SB)298	UNDEF299300/*301 * support for morestack302 */303304// Called during function prolog when more stack is needed.305// Caller has already loaded:306// R3: framesize, R4: argsize, R5: LR307//308// The traceback routines see morestack on a g0 as being309// the top of a stack (for example, morestack calling newstack310// calling the scheduler calling newm calling gc), so we must311// record an argument size. For that purpose, it has no arguments.312TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0313	// Called from f.314	// Set g->sched to context in f.315	MOVD	R15, (g_sched+gobuf_sp)(g)316	MOVD	LR, R8317	MOVD	R8, (g_sched+gobuf_pc)(g)318	MOVD	R5, (g_sched+gobuf_lr)(g)319	MOVD	R12, (g_sched+gobuf_ctxt)(g)320321	// Cannot grow scheduler stack (m->g0).322	MOVD	g_m(g), R7323	MOVD	m_g0(R7), R8324	CMPBNE	g, R8, 3(PC)325	BL	runtime·badmorestackg0(SB)326	BL	runtime·abort(SB)327328	// Cannot grow signal stack (m->gsignal).329	MOVD	m_gsignal(R7), R8330	CMP	g, R8331	BNE	3(PC)332	BL	runtime·badmorestackgsignal(SB)333	BL	runtime·abort(SB)334335	// Called from f.336	// Set m->morebuf to f's caller.337	MOVD	R5, (m_morebuf+gobuf_pc)(R7)	// f's caller's PC338	MOVD	R15, (m_morebuf+gobuf_sp)(R7)	// f's caller's SP339	MOVD	g, (m_morebuf+gobuf_g)(R7)340341	// Call newstack on m->g0's stack.342	MOVD	m_g0(R7), g343	BL	runtime·save_g(SB)344	MOVD	(g_sched+gobuf_sp)(g), R15345	// Create a stack frame on g0 to call newstack.346	MOVD	$0, -8(R15)	// Zero saved LR in frame347	SUB	$8, R15348	BL	runtime·newstack(SB)349350	// Not reached, but make sure the return PC from the call to newstack351	// is still in this function, and not the beginning of the next.352	UNDEF353354TEXT runtime·morestack_noctxt(SB),NOSPLIT|NOFRAME,$0-0355	// Force SPWRITE. This function doesn't actually write SP,356	// but it is called with a special calling convention where357	// the caller doesn't save LR on stack but passes it as a358	// register (R5), and the unwinder currently doesn't understand.359	// Make it SPWRITE to stop unwinding. (See issue 54332)360	MOVD	R15, R15361362	MOVD	$0, R12363	BR	runtime·morestack(SB)364365// reflectcall: call a function with the given argument list366// func call(stackArgsType *_type, f *FuncVal, stackArgs *byte, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs).367// we don't have variable-sized frames, so we use a small number368// of constant-sized-frame functions to encode a few bits of size in the pc.369// Caution: ugly multiline assembly macros in your future!370371#define DISPATCH(NAME,MAXSIZE)		\372	MOVD	$MAXSIZE, R4;		\373	CMP	R3, R4;		\374	BGT	3(PC);			\375	MOVD	$NAME(SB), R5;	\376	BR	(R5)377// Note: can't just "BR NAME(SB)" - bad inlining results.378379TEXT ·reflectcall(SB), NOSPLIT, $-8-48380	MOVWZ	frameSize+32(FP), R3381	DISPATCH(runtime·call16, 16)382	DISPATCH(runtime·call32, 32)383	DISPATCH(runtime·call64, 64)384	DISPATCH(runtime·call128, 128)385	DISPATCH(runtime·call256, 256)386	DISPATCH(runtime·call512, 512)387	DISPATCH(runtime·call1024, 1024)388	DISPATCH(runtime·call2048, 2048)389	DISPATCH(runtime·call4096, 4096)390	DISPATCH(runtime·call8192, 8192)391	DISPATCH(runtime·call16384, 16384)392	DISPATCH(runtime·call32768, 32768)393	DISPATCH(runtime·call65536, 65536)394	DISPATCH(runtime·call131072, 131072)395	DISPATCH(runtime·call262144, 262144)396	DISPATCH(runtime·call524288, 524288)397	DISPATCH(runtime·call1048576, 1048576)398	DISPATCH(runtime·call2097152, 2097152)399	DISPATCH(runtime·call4194304, 4194304)400	DISPATCH(runtime·call8388608, 8388608)401	DISPATCH(runtime·call16777216, 16777216)402	DISPATCH(runtime·call33554432, 33554432)403	DISPATCH(runtime·call67108864, 67108864)404	DISPATCH(runtime·call134217728, 134217728)405	DISPATCH(runtime·call268435456, 268435456)406	DISPATCH(runtime·call536870912, 536870912)407	DISPATCH(runtime·call1073741824, 1073741824)408	MOVD	$runtime·badreflectcall(SB), R5409	BR	(R5)410411#define CALLFN(NAME,MAXSIZE)			\412TEXT NAME(SB), WRAPPER, $MAXSIZE-48;		\413	NO_LOCAL_POINTERS;			\414	/* copy arguments to stack */		\415	MOVD	stackArgs+16(FP), R4;			\416	MOVWZ	stackArgsSize+24(FP), R5;		\417	MOVD	$stack-MAXSIZE(SP), R6;		\418loopArgs: /* copy 256 bytes at a time */	\419	CMP	R5, $256;			\420	BLT	tailArgs;			\421	SUB	$256, R5;			\422	MVC	$256, 0(R4), 0(R6);		\423	MOVD	$256(R4), R4;			\424	MOVD	$256(R6), R6;			\425	BR	loopArgs;			\426tailArgs: /* copy remaining bytes */		\427	CMP	R5, $0;				\428	BEQ	callFunction;			\429	SUB	$1, R5;				\430	EXRL	$callfnMVC<>(SB), R5;		\431callFunction:					\432	MOVD	f+8(FP), R12;			\433	MOVD    regArgs+40(FP), R10;		\434	BL      ·unspillArgs(SB);		\435	MOVD	(R12), R10;			\436	PCDATA  $PCDATA_StackMapIndex, $0;	\437	BL	(R10);				\438	/* copy return values back */		\439	MOVD    regArgs+40(FP), R10;		\440	BL      ·spillArgs(SB);		\441	MOVD	stackArgsType+0(FP), R7;		\442	MOVD	stackArgs+16(FP), R6;			\443	MOVWZ	stackArgsSize+24(FP), R5;			\444	MOVD	$stack-MAXSIZE(SP), R4;		\445	MOVWZ	stackRetOffset+28(FP), R1;		\446	ADD	R1, R4;				\447	ADD	R1, R6;				\448	SUB	R1, R5;				\449	BL	callRet<>(SB);			\450	RET451452// callRet copies return values back at the end of call*. This is a453// separate function so it can allocate stack space for the arguments454// to reflectcallmove. It does not follow the Go ABI; it expects its455// arguments in registers.456TEXT callRet<>(SB), NOSPLIT, $40-0457	NO_LOCAL_POINTERS;458	MOVD	R7, 8(R15)459	MOVD	R6, 16(R15)460	MOVD	R4, 24(R15)461	MOVD	R5, 32(R15)462	MOVD	R10, 40(R15)463	BL	runtime·reflectcallmove(SB)464	RET465466CALLFNcall16, 16)467CALLFNcall32, 32)468CALLFNcall64, 64)469CALLFNcall128, 128)470CALLFNcall256, 256)471CALLFNcall512, 512)472CALLFNcall1024, 1024)473CALLFNcall2048, 2048)474CALLFNcall4096, 4096)475CALLFNcall8192, 8192)476CALLFNcall16384, 16384)477CALLFNcall32768, 32768)478CALLFNcall65536, 65536)479CALLFNcall131072, 131072)480CALLFNcall262144, 262144)481CALLFNcall524288, 524288)482CALLFNcall1048576, 1048576)483CALLFNcall2097152, 2097152)484CALLFNcall4194304, 4194304)485CALLFNcall8388608, 8388608)486CALLFNcall16777216, 16777216)487CALLFNcall33554432, 33554432)488CALLFNcall67108864, 67108864)489CALLFNcall134217728, 134217728)490CALLFNcall268435456, 268435456)491CALLFNcall536870912, 536870912)492CALLFNcall1073741824, 1073741824)493494// Not a function: target for EXRL (execute relative long) instruction.495TEXT callfnMVC<>(SB),NOSPLIT|NOFRAME,$0-0496	MVC	$1, 0(R4), 0(R6)497498TEXT runtime·procyieldAsm(SB),NOSPLIT,$0-0499	RET500501// Save state of caller into g->sched,502// but using fake PC from systemstack_switch.503// Must only be called from functions with no locals ($0)504// or else unwinding from systemstack_switch is incorrect.505// Smashes R1.506TEXT gosave_systemstack_switch<>(SB),NOSPLIT|NOFRAME,$0507	MOVD	$runtime·systemstack_switch(SB), R1508	ADD	$16, R1	// get past prologue509	MOVD	R1, (g_sched+gobuf_pc)(g)510	MOVD	R15, (g_sched+gobuf_sp)(g)511	MOVD	$0, (g_sched+gobuf_lr)(g)512	// Assert ctxt is zero. See func save.513	MOVD	(g_sched+gobuf_ctxt)(g), R1514	CMPBEQ	R1, $0, 2(PC)515	BL	runtime·abort(SB)516	RET517518// func asmcgocall(fn, arg unsafe.Pointer) int32519// Call fn(arg) on the scheduler stack,520// aligned appropriately for the gcc ABI.521// See cgocall.go for more details.522TEXT ·asmcgocall(SB),NOSPLIT,$0-20523	// R2 = argc; R3 = argv; R11 = temp; R13 = g; R15 = stack pointer524	// C TLS base pointer in AR0:AR1525	MOVD	fn+0(FP), R3526	MOVD	arg+8(FP), R4527528	MOVD	R15, R2		// save original stack pointer529	MOVD	g, R5530531	// Figure out if we need to switch to m->g0 stack.532	// We get called to create new OS threads too, and those533	// come in on the m->g0 stack already. Or we might already534	// be on the m->gsignal stack.535	CMPBEQ	g, $0, nosave536	MOVD	g_m(g), R6537	MOVD	m_gsignal(R6), R7538	CMPBEQ	R7, g, g0539	MOVD	m_g0(R6), R7540	CMPBEQ	R7, g, g0541	BL	gosave_systemstack_switch<>(SB)542	MOVD	R7, g543	BL	runtime·save_g(SB)544	MOVD	(g_sched+gobuf_sp)(g), R15545546	// Now on a scheduling stack (a pthread-created stack).547g0:548	// Save room for two of our pointers, plus 160 bytes of callee549	// save area that lives on the caller stack.550	SUB	$176, R15551	MOVD	$~7, R6552	AND	R6, R15                 // 8-byte alignment for gcc ABI553	MOVD	R5, 168(R15)             // save old g on stack554	MOVD	(g_stack+stack_hi)(R5), R5555	SUB	R2, R5556	MOVD	R5, 160(R15)             // save depth in old g stack (can't just save SP, as stack might be copied during a callback)557	MOVD	$0, 0(R15)              // clear back chain pointer (TODO can we give it real back trace information?)558	MOVD	R4, R2                  // arg in R2559	BL	R3                      // can clobber: R0-R5, R14, F0-F3, F5, F7-F15560561	XOR	R0, R0                  // set R0 back to 0.562	// Restore g, stack pointer.563	MOVD	168(R15), g564	BL	runtime·save_g(SB)565	MOVD	(g_stack+stack_hi)(g), R5566	MOVD	160(R15), R6567	SUB	R6, R5568	MOVD	R5, R15569570	MOVW	R2, ret+16(FP)571	RET572573nosave:574	// Running on a system stack, perhaps even without a g.575	// Having no g can happen during thread creation or thread teardown.576	MOVD	fn+0(FP), R3577	MOVD	arg+8(FP), R4578	MOVD	R15, R2579	SUB	$176, R15580	MOVD	$~7, R6581	AND	R6, R15582	MOVD	$0, 168(R15)	// Where above code stores g, in case someone looks during debugging.583	MOVD	R2, 160(R15)	// Save original stack pointer.584	MOVD	$0, 0(R15)	// clear back chain pointer585	MOVD	R4, R2		// arg in R2586	BL	R3587	XOR	R0, R0588	MOVD	160(R15), R15	// Restore stack pointer.589	MOVW	R2, ret+16(FP)590	RET591592// func asmcgocall_no_g(fn, arg unsafe.Pointer)593// Call fn(arg) aligned appropriately for the gcc ABI.594// Called on a system stack, and there may be no g yet.595TEXT ·asmcgocall_no_g(SB),NOSPLIT,$0-16596	MOVD	fn+0(FP), R3597	MOVD	arg+8(FP), R4598599	MOVD	R15, R2		// Save original stack pointer.600601	// Save room for the stack pointer, plus 160 bytes of callee602	// save area that lives on the caller stack.603	SUB	$168, R15604	MOVD	$~7, R6605	AND	R6, R15606607	MOVD	R2, 160(R15)	// Save original stack pointer.608	MOVD	$0, 0(R15)	// clear back chain pointer609	MOVD	R4, R2		// arg in R2610	BL	R3611	XOR	R0, R0612	MOVD	160(R15), R15	// Restore stack pointer.613	RET614615// cgocallback(fn, frame unsafe.Pointer, ctxt uintptr)616// See cgocall.go for more details.617TEXT ·cgocallback(SB),NOSPLIT,$24-24618	NO_LOCAL_POINTERS619620	// Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g.621	// It is used to dropm while thread is exiting.622	MOVD	fn+0(FP), R1623	CMPBNE	R1, $0, loadg624	// Restore the g from frame.625	MOVD	frame+8(FP), g626	BR	dropm627628loadg:629	// Load m and g from thread-local storage.630	MOVB	runtime·iscgo(SB), R3631	CMPBEQ	R3, $0, nocgo632	BL	runtime·load_g(SB)633634nocgo:635	// If g is nil, Go did not create the current thread,636	// or if this thread never called into Go on pthread platforms.637	// Call needm to obtain one for temporary use.638	// In this case, we're running on the thread stack, so there's639	// lots of space, but the linker doesn't know. Hide the call from640	// the linker analysis by using an indirect call.641	CMPBEQ	g, $0, needm642643	MOVD	g_m(g), R8644	MOVD	R8, savedm-8(SP)645	BR	havem646647needm:648	MOVD	g, savedm-8(SP) // g is zero, so is m.649	MOVD	$runtime·needAndBindM(SB), R3650	BL	(R3)651652	// Set m->sched.sp = SP, so that if a panic happens653	// during the function we are about to execute, it will654	// have a valid SP to run on the g0 stack.655	// The next few lines (after the havem label)656	// will save this SP onto the stack and then write657	// the same SP back to m->sched.sp. That seems redundant,658	// but if an unrecovered panic happens, unwindm will659	// restore the g->sched.sp from the stack location660	// and then systemstack will try to use it. If we don't set it here,661	// that restored SP will be uninitialized (typically 0) and662	// will not be usable.663	MOVD	g_m(g), R8664	MOVD	m_g0(R8), R3665	MOVD	R15, (g_sched+gobuf_sp)(R3)666667havem:668	// Now there's a valid m, and we're running on its m->g0.669	// Save current m->g0->sched.sp on stack and then set it to SP.670	// Save current sp in m->g0->sched.sp in preparation for671	// switch back to m->curg stack.672	// NOTE: unwindm knows that the saved g->sched.sp is at 8(R1) aka savedsp-16(SP).673	MOVD	m_g0(R8), R3674	MOVD	(g_sched+gobuf_sp)(R3), R4675	MOVD	R4, savedsp-24(SP)	// must match frame size676	MOVD	R15, (g_sched+gobuf_sp)(R3)677678	// Switch to m->curg stack and call runtime.cgocallbackg.679	// Because we are taking over the execution of m->curg680	// but *not* resuming what had been running, we need to681	// save that information (m->curg->sched) so we can restore it.682	// We can restore m->curg->sched.sp easily, because calling683	// runtime.cgocallbackg leaves SP unchanged upon return.684	// To save m->curg->sched.pc, we push it onto the curg stack and685	// open a frame the same size as cgocallback's g0 frame.686	// Once we switch to the curg stack, the pushed PC will appear687	// to be the return PC of cgocallback, so that the traceback688	// will seamlessly trace back into the earlier calls.689	MOVD	m_curg(R8), g690	BL	runtime·save_g(SB)691	MOVD	(g_sched+gobuf_sp)(g), R4 // prepare stack as R4692	MOVD	(g_sched+gobuf_pc)(g), R5693	MOVD	R5, -(24+8)(R4)	// "saved LR"; must match frame size694	// Gather our arguments into registers.695	MOVD	fn+0(FP), R1696	MOVD	frame+8(FP), R2697	MOVD	ctxt+16(FP), R3698	MOVD	$-(24+8)(R4), R15	// switch stack; must match frame size699	MOVD	R1, 8(R15)700	MOVD	R2, 16(R15)701	MOVD	R3, 24(R15)702	BL	runtime·cgocallbackg(SB)703704	// Restore g->sched (== m->curg->sched) from saved values.705	MOVD	0(R15), R5706	MOVD	R5, (g_sched+gobuf_pc)(g)707	MOVD	$(24+8)(R15), R4	// must match frame size708	MOVD	R4, (g_sched+gobuf_sp)(g)709710	// Switch back to m->g0's stack and restore m->g0->sched.sp.711	// (Unlike m->curg, the g0 goroutine never uses sched.pc,712	// so we do not have to restore it.)713	MOVD	g_m(g), R8714	MOVD	m_g0(R8), g715	BL	runtime·save_g(SB)716	MOVD	(g_sched+gobuf_sp)(g), R15717	MOVD	savedsp-24(SP), R4	// must match frame size718	MOVD	R4, (g_sched+gobuf_sp)(g)719720	// If the m on entry was nil, we called needm above to borrow an m,721	// 1. for the duration of the call on non-pthread platforms,722	// 2. or the duration of the C thread alive on pthread platforms.723	// If the m on entry wasn't nil,724	// 1. the thread might be a Go thread,725	// 2. or it wasn't the first call from a C thread on pthread platforms,726	//    since then we skip dropm to reuse the m in the first call.727	MOVD	savedm-8(SP), R6728	CMPBNE	R6, $0, droppedm729730	// Skip dropm to reuse it in the next call, when a pthread key has been created.731	MOVD	_cgo_pthread_key_created(SB), R6732	// It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm.733	CMPBEQ	R6, $0, dropm734	MOVD	(R6), R6735	CMPBNE	R6, $0, droppedm736737dropm:738	MOVD	$runtime·dropm(SB), R3739	BL	(R3)740droppedm:741742	// Done!743	RET744745// void setg(G*); set g. for use by needm.746TEXT runtime·setg(SB), NOSPLIT, $0-8747	MOVD	gg+0(FP), g748	// This only happens if iscgo, so jump straight to save_g749	BL	runtime·save_g(SB)750	RET751752// void setg_gcc(G*); set g in C TLS.753// Must obey the gcc calling convention.754TEXT setg_gcc<>(SB),NOSPLIT|NOFRAME,$0-0755	// The standard prologue clobbers LR (R14), which is callee-save in756	// the C ABI, so we have to use NOFRAME and save LR ourselves.757	MOVD	LR, R1758	// Also save g, R10, and R11 since they're callee-save in C ABI759	MOVD	R10, R3760	MOVD	g, R4761	MOVD	R11, R5762763	MOVD	R2, g764	BL	runtime·save_g(SB)765766	MOVD	R5, R11767	MOVD	R4, g768	MOVD	R3, R10769	MOVD	R1, LR770	RET771772TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0773	MOVW	(R0), R0774	UNDEF775776// int64 runtime·cputicks(void)777TEXT runtime·cputicks(SB),NOSPLIT,$0-8778	// The TOD clock on s390 counts from the year 1900 in ~250ps intervals.779	// This means that since about 1972 the msb has been set, making the780	// result of a call to STORE CLOCK (stck) a negative number.781	// We clear the msb to make it positive.782	STCK	ret+0(FP)      // serialises before and after call783	MOVD	ret+0(FP), R3  // R3 will wrap to 0 in the year 2043784	SLD	$1, R3785	SRD	$1, R3786	MOVD	R3, ret+0(FP)787	RET788789// spillArgs stores return values from registers to a *internal/abi.RegArgs in R10.790TEXT runtime·spillArgs(SB),NOSPLIT,$0-0791	MOVD	R2, 0(R10)792	MOVD	R3, 8(R10)793	MOVD	R4, 16(R10)794	MOVD	R5, 24(R10)795	MOVD	R6, 32(R10)796	MOVD	R7, 40(R10)797	MOVD	R8, 48(R10)798	MOVD	R9, 56(R10)799	FMOVD	F0, 64(R10)800	FMOVD	F1, 72(R10)801	FMOVD	F2, 80(R10)802	FMOVD	F3, 88(R10)803	FMOVD	F4, 96(R10)804	FMOVD	F5, 104(R10)805	FMOVD	F6, 112(R10)806	FMOVD	F7, 120(R10)807	FMOVD	F8, 128(R10)808	FMOVD	F9, 136(R10)809	FMOVD	F10, 144(R10)810	FMOVD	F11, 152(R10)811	FMOVD	F12, 160(R10)812	FMOVD	F13, 168(R10)813	FMOVD	F14, 176(R10)814	FMOVD	F15, 184(R10)815	RET816817// unspillArgs loads args into registers from a *internal/abi.RegArgs in R10.818TEXT runtime·unspillArgs(SB),NOSPLIT,$0-0819	MOVD	0(R10), R2820	MOVD	8(R10), R3821	MOVD	16(R10), R4822	MOVD	24(R10), R5823	MOVD	32(R10), R6824	MOVD	40(R10), R7825	MOVD	48(R10), R8826	MOVD	56(R10), R9827	FMOVD	64(R10), F0828	FMOVD	72(R10), F1829	FMOVD	80(R10), F2830	FMOVD	88(R10), F3831	FMOVD	96(R10), F4832	FMOVD	104(R10), F5833	FMOVD	112(R10), F6834	FMOVD	120(R10), F7835	FMOVD	128(R10), F8836	FMOVD	136(R10), F9837	FMOVD	144(R10), F10838	FMOVD	152(R10), F11839	FMOVD	160(R10), F12840	FMOVD	168(R10), F13841	FMOVD	176(R10), F14842	FMOVD	184(R10), F15843	RET844845// Called from cgo wrappers, this function returns g->m->curg.stack.hi.846// Must obey the gcc calling convention.847TEXT _cgo_topofstack(SB),NOSPLIT|NOFRAME,$0848	// g (R13), R10, R11 and LR (R14) are callee-save in the C ABI, so save them849	MOVD	g, R1850	MOVD	R10, R3851	MOVD	LR, R4852	MOVD	R11, R5853854	BL	runtime·load_g(SB)	// clobbers g (R13), R10, R11855	MOVD	g_m(g), R2856	MOVD	m_curg(R2), R2857	MOVD	(g_stack+stack_hi)(R2), R2858859	MOVD	R1, g860	MOVD	R3, R10861	MOVD	R4, LR862	MOVD	R5, R11863	RET864865// The top-most function running on a goroutine866// returns to goexit+PCQuantum.867TEXT runtime·goexit(SB),NOSPLIT|NOFRAME|TOPFRAME,$0-0868	BYTE $0x07; BYTE $0x00; // 2-byte nop869	BL	runtime·goexit1(SB)	// does not return870	// traceback from goexit1 must hit code range of goexit871	BYTE $0x07; BYTE $0x00; // 2-byte nop872873TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-0874	// Stores are already ordered on s390x, so this is just a875	// compile barrier.876	RET877878// This is called from .init_array and follows the platform, not Go, ABI.879// We are overly conservative. We could only save the registers we use.880// However, since this function is only called once per loaded module881// performance is unimportant.882TEXT runtime·addmoduledata(SB),NOSPLIT|NOFRAME,$0-0883	// Save R6-R15 in the register save area of the calling function.884	// Don't bother saving F8-F15 as we aren't doing any calls.885	STMG	R6, R15, 48(R15)886887	// append the argument (passed in R2, as per the ELF ABI) to the888	// moduledata linked list.889	MOVD	runtime·lastmoduledatap(SB), R1890	MOVD	R2, moduledata_next(R1)891	MOVD	R2, runtime·lastmoduledatap(SB)892893	// Restore R6-R15.894	LMG	48(R15), R6, R15895	RET896897// gcWriteBarrier informs the GC about heap pointer writes.898//899// gcWriteBarrier does NOT follow the Go ABI. It accepts the900// number of bytes of buffer needed in R9, and returns a pointer901// to the buffer space in R9.902// It clobbers R10 (the temp register) and R1 (used by PLT stub).903// It does not clobber any other general-purpose registers,904// but may clobber others (e.g., floating point registers).905TEXT gcWriteBarrier<>(SB),NOSPLIT,$96906	// Save the registers clobbered by the fast path.907	MOVD	R4, 96(R15)908retry:909	MOVD	g_m(g), R1910	MOVD	m_p(R1), R1911	// Increment wbBuf.next position.912	MOVD	R9, R4913	ADD	(p_wbBuf+wbBuf_next)(R1), R4914	// Is the buffer full?915	MOVD	(p_wbBuf+wbBuf_end)(R1), R10916	CMPUBGT	R4, R10, flush917	// Commit to the larger buffer.918	MOVD	R4, (p_wbBuf+wbBuf_next)(R1)919	// Make return value (the original next position)920	SUB	R9, R4, R9921	// Restore registers.922	MOVD	96(R15), R4923	RET924925flush:926	// Save all general purpose registers since these could be927	// clobbered by wbBufFlush and were not saved by the caller.928	STMG	R2, R3, 8(R15)929	MOVD	R0, 24(R15)930	// R1 already saved.931	// R4 already saved.932	STMG	R5, R12, 32(R15) // save R5 - R12933	// R13 is g.934	// R14 is LR.935	// R15 is SP.936937	CALL	runtime·wbBufFlush(SB)938939	LMG	8(R15), R2, R3   // restore R2 - R3940	MOVD	24(R15), R0      // restore R0941	LMG	32(R15), R5, R12 // restore R5 - R12942	JMP	retry943944TEXT runtime·gcWriteBarrier1<ABIInternal>(SB),NOSPLIT,$0945	MOVD	$8, R9946	JMP	gcWriteBarrier<>(SB)947TEXT runtime·gcWriteBarrier2<ABIInternal>(SB),NOSPLIT,$0948	MOVD	$16, R9949	JMP	gcWriteBarrier<>(SB)950TEXT runtime·gcWriteBarrier3<ABIInternal>(SB),NOSPLIT,$0951	MOVD	$24, R9952	JMP	gcWriteBarrier<>(SB)953TEXT runtime·gcWriteBarrier4<ABIInternal>(SB),NOSPLIT,$0954	MOVD	$32, R9955	JMP	gcWriteBarrier<>(SB)956TEXT runtime·gcWriteBarrier5<ABIInternal>(SB),NOSPLIT,$0957	MOVD	$40, R9958	JMP	gcWriteBarrier<>(SB)959TEXT runtime·gcWriteBarrier6<ABIInternal>(SB),NOSPLIT,$0960	MOVD	$48, R9961	JMP	gcWriteBarrier<>(SB)962TEXT runtime·gcWriteBarrier7<ABIInternal>(SB),NOSPLIT,$0963	MOVD	$56, R9964	JMP	gcWriteBarrier<>(SB)965TEXT runtime·gcWriteBarrier8<ABIInternal>(SB),NOSPLIT,$0966	MOVD	$64, R9967	JMP	gcWriteBarrier<>(SB)968969TEXT runtime·panicBounds<ABIInternal>(SB),NOSPLIT,$144-0970	NO_LOCAL_POINTERS971	// Save all 16 int registers that could have an index in them.972	// They may be pointers, but if they are they are dead.973	STMG	R0, R12, 24(R15)974	// Note that R10 @ 104 is not needed, it is an assembler temp975	// skip R13 aka G @ 128976	// skip R14 aka LR @ 136977	// skip R15 aka SP @ 144978979	MOVD	R14, R2		// PC immediately after call to panicBounds980	ADD     $24, R15, R3	// pointer to save area981	CALL	runtime·panicBounds64<ABIInternal>(SB)982	RET

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.