summaryrefslogtreecommitdiffstats
path: root/src/runtime/cgo
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/cgo')
-rw-r--r--src/runtime/cgo/abi_amd64.h99
-rw-r--r--src/runtime/cgo/abi_arm64.h43
-rw-r--r--src/runtime/cgo/abi_loong64.h60
-rw-r--r--src/runtime/cgo/abi_ppc64x.h195
-rw-r--r--src/runtime/cgo/asm_386.s42
-rw-r--r--src/runtime/cgo/asm_amd64.s47
-rw-r--r--src/runtime/cgo/asm_arm.s69
-rw-r--r--src/runtime/cgo/asm_arm64.s50
-rw-r--r--src/runtime/cgo/asm_loong64.s53
-rw-r--r--src/runtime/cgo/asm_mips64x.s95
-rw-r--r--src/runtime/cgo/asm_mipsx.s88
-rw-r--r--src/runtime/cgo/asm_ppc64x.s70
-rw-r--r--src/runtime/cgo/asm_riscv64.s91
-rw-r--r--src/runtime/cgo/asm_s390x.s68
-rw-r--r--src/runtime/cgo/asm_wasm.s11
-rw-r--r--src/runtime/cgo/callbacks.go152
-rw-r--r--src/runtime/cgo/callbacks_aix.go12
-rw-r--r--src/runtime/cgo/callbacks_traceback.go17
-rw-r--r--src/runtime/cgo/cgo.go40
-rw-r--r--src/runtime/cgo/dragonfly.go19
-rw-r--r--src/runtime/cgo/freebsd.go22
-rw-r--r--src/runtime/cgo/gcc_386.S48
-rw-r--r--src/runtime/cgo/gcc_aix_ppc64.S132
-rw-r--r--src/runtime/cgo/gcc_aix_ppc64.c35
-rw-r--r--src/runtime/cgo/gcc_amd64.S55
-rw-r--r--src/runtime/cgo/gcc_android.c90
-rw-r--r--src/runtime/cgo/gcc_arm.S31
-rw-r--r--src/runtime/cgo/gcc_arm64.S84
-rw-r--r--src/runtime/cgo/gcc_context.c20
-rw-r--r--src/runtime/cgo/gcc_darwin_amd64.c60
-rw-r--r--src/runtime/cgo/gcc_darwin_arm64.c139
-rw-r--r--src/runtime/cgo/gcc_dragonfly_amd64.c60
-rw-r--r--src/runtime/cgo/gcc_fatalf.c23
-rw-r--r--src/runtime/cgo/gcc_freebsd.c71
-rw-r--r--src/runtime/cgo/gcc_freebsd_amd64.c71
-rw-r--r--src/runtime/cgo/gcc_freebsd_sigaction.c80
-rw-r--r--src/runtime/cgo/gcc_libinit.c171
-rw-r--r--src/runtime/cgo/gcc_libinit_windows.c158
-rw-r--r--src/runtime/cgo/gcc_linux.c66
-rw-r--r--src/runtime/cgo/gcc_linux_amd64.c91
-rw-r--r--src/runtime/cgo/gcc_linux_arm64.c87
-rw-r--r--src/runtime/cgo/gcc_linux_ppc64x.S86
-rw-r--r--src/runtime/cgo/gcc_linux_s390x.c63
-rw-r--r--src/runtime/cgo/gcc_loong64.S67
-rw-r--r--src/runtime/cgo/gcc_mips64x.S89
-rw-r--r--src/runtime/cgo/gcc_mipsx.S77
-rw-r--r--src/runtime/cgo/gcc_mmap.c39
-rw-r--r--src/runtime/cgo/gcc_netbsd.c73
-rw-r--r--src/runtime/cgo/gcc_openbsd.c61
-rw-r--r--src/runtime/cgo/gcc_ppc64x.c67
-rw-r--r--src/runtime/cgo/gcc_riscv64.S82
-rw-r--r--src/runtime/cgo/gcc_s390x.S58
-rw-r--r--src/runtime/cgo/gcc_setenv.c27
-rw-r--r--src/runtime/cgo/gcc_sigaction.c82
-rw-r--r--src/runtime/cgo/gcc_signal2_ios_arm64.c11
-rw-r--r--src/runtime/cgo/gcc_signal_ios_arm64.c213
-rw-r--r--src/runtime/cgo/gcc_signal_ios_nolldb.c10
-rw-r--r--src/runtime/cgo/gcc_solaris_amd64.c83
-rw-r--r--src/runtime/cgo/gcc_stack_darwin.c20
-rw-r--r--src/runtime/cgo/gcc_stack_unix.c40
-rw-r--r--src/runtime/cgo/gcc_stack_windows.c7
-rw-r--r--src/runtime/cgo/gcc_traceback.c46
-rw-r--r--src/runtime/cgo/gcc_util.c69
-rw-r--r--src/runtime/cgo/gcc_windows_386.c53
-rw-r--r--src/runtime/cgo/gcc_windows_amd64.c52
-rw-r--r--src/runtime/cgo/gcc_windows_arm64.c40
-rw-r--r--src/runtime/cgo/handle.go144
-rw-r--r--src/runtime/cgo/handle_test.go103
-rw-r--r--src/runtime/cgo/iscgo.go17
-rw-r--r--src/runtime/cgo/libcgo.h151
-rw-r--r--src/runtime/cgo/libcgo_unix.h20
-rw-r--r--src/runtime/cgo/libcgo_windows.h6
-rw-r--r--src/runtime/cgo/linux.go74
-rw-r--r--src/runtime/cgo/linux_syscall.c85
-rw-r--r--src/runtime/cgo/mmap.go31
-rw-r--r--src/runtime/cgo/netbsd.go21
-rw-r--r--src/runtime/cgo/openbsd.go21
-rw-r--r--src/runtime/cgo/setenv.go21
-rw-r--r--src/runtime/cgo/sigaction.go22
-rw-r--r--src/runtime/cgo/signal_ios_arm64.go10
-rw-r--r--src/runtime/cgo/signal_ios_arm64.s56
81 files changed, 5212 insertions, 0 deletions
diff --git a/src/runtime/cgo/abi_amd64.h b/src/runtime/cgo/abi_amd64.h
new file mode 100644
index 0000000..9949435
--- /dev/null
+++ b/src/runtime/cgo/abi_amd64.h
@@ -0,0 +1,99 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Macros for transitioning from the host ABI to Go ABI0.
+//
+// These save the frame pointer, so in general, functions that use
+// these should have zero frame size to suppress the automatic frame
+// pointer, though it's harmless to not do this.
+
+#ifdef GOOS_windows
+
+// REGS_HOST_TO_ABI0_STACK is the stack bytes used by
+// PUSH_REGS_HOST_TO_ABI0.
+#define REGS_HOST_TO_ABI0_STACK (28*8 + 8)
+
+// PUSH_REGS_HOST_TO_ABI0 prepares for transitioning from
+// the host ABI to Go ABI0 code. It saves all registers that are
+// callee-save in the host ABI and caller-save in Go ABI0 and prepares
+// for entry to Go.
+//
+// Save DI SI BP BX R12 R13 R14 R15 X6-X15 registers and the DF flag.
+// Clear the DF flag for the Go ABI.
+// MXCSR matches the Go ABI, so we don't have to set that,
+// and Go doesn't modify it, so we don't have to save it.
+#define PUSH_REGS_HOST_TO_ABI0() \
+ PUSHFQ \
+ CLD \
+ ADJSP $(REGS_HOST_TO_ABI0_STACK - 8) \
+ MOVQ DI, (0*0)(SP) \
+ MOVQ SI, (1*8)(SP) \
+ MOVQ BP, (2*8)(SP) \
+ MOVQ BX, (3*8)(SP) \
+ MOVQ R12, (4*8)(SP) \
+ MOVQ R13, (5*8)(SP) \
+ MOVQ R14, (6*8)(SP) \
+ MOVQ R15, (7*8)(SP) \
+ MOVUPS X6, (8*8)(SP) \
+ MOVUPS X7, (10*8)(SP) \
+ MOVUPS X8, (12*8)(SP) \
+ MOVUPS X9, (14*8)(SP) \
+ MOVUPS X10, (16*8)(SP) \
+ MOVUPS X11, (18*8)(SP) \
+ MOVUPS X12, (20*8)(SP) \
+ MOVUPS X13, (22*8)(SP) \
+ MOVUPS X14, (24*8)(SP) \
+ MOVUPS X15, (26*8)(SP)
+
+#define POP_REGS_HOST_TO_ABI0() \
+ MOVQ (0*0)(SP), DI \
+ MOVQ (1*8)(SP), SI \
+ MOVQ (2*8)(SP), BP \
+ MOVQ (3*8)(SP), BX \
+ MOVQ (4*8)(SP), R12 \
+ MOVQ (5*8)(SP), R13 \
+ MOVQ (6*8)(SP), R14 \
+ MOVQ (7*8)(SP), R15 \
+ MOVUPS (8*8)(SP), X6 \
+ MOVUPS (10*8)(SP), X7 \
+ MOVUPS (12*8)(SP), X8 \
+ MOVUPS (14*8)(SP), X9 \
+ MOVUPS (16*8)(SP), X10 \
+ MOVUPS (18*8)(SP), X11 \
+ MOVUPS (20*8)(SP), X12 \
+ MOVUPS (22*8)(SP), X13 \
+ MOVUPS (24*8)(SP), X14 \
+ MOVUPS (26*8)(SP), X15 \
+ ADJSP $-(REGS_HOST_TO_ABI0_STACK - 8) \
+ POPFQ
+
+#else
+// SysV ABI
+
+#define REGS_HOST_TO_ABI0_STACK (6*8)
+
+// SysV MXCSR matches the Go ABI, so we don't have to set that,
+// and Go doesn't modify it, so we don't have to save it.
+// Both SysV and Go require DF to be cleared, so that's already clear.
+// The SysV and Go frame pointer conventions are compatible.
+#define PUSH_REGS_HOST_TO_ABI0() \
+ ADJSP $(REGS_HOST_TO_ABI0_STACK) \
+ MOVQ BP, (5*8)(SP) \
+ LEAQ (5*8)(SP), BP \
+ MOVQ BX, (0*8)(SP) \
+ MOVQ R12, (1*8)(SP) \
+ MOVQ R13, (2*8)(SP) \
+ MOVQ R14, (3*8)(SP) \
+ MOVQ R15, (4*8)(SP)
+
+#define POP_REGS_HOST_TO_ABI0() \
+ MOVQ (0*8)(SP), BX \
+ MOVQ (1*8)(SP), R12 \
+ MOVQ (2*8)(SP), R13 \
+ MOVQ (3*8)(SP), R14 \
+ MOVQ (4*8)(SP), R15 \
+ MOVQ (5*8)(SP), BP \
+ ADJSP $-(REGS_HOST_TO_ABI0_STACK)
+
+#endif
diff --git a/src/runtime/cgo/abi_arm64.h b/src/runtime/cgo/abi_arm64.h
new file mode 100644
index 0000000..e2b5e6d
--- /dev/null
+++ b/src/runtime/cgo/abi_arm64.h
@@ -0,0 +1,43 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Macros for transitioning from the host ABI to Go ABI0.
+//
+// These macros save and restore the callee-saved registers
+// from the stack, but they don't adjust stack pointer, so
+// the user should prepare stack space in advance.
+// SAVE_R19_TO_R28(offset) saves R19 ~ R28 to the stack space
+// of ((offset)+0*8)(RSP) ~ ((offset)+9*8)(RSP).
+//
+// SAVE_F8_TO_F15(offset) saves F8 ~ F15 to the stack space
+// of ((offset)+0*8)(RSP) ~ ((offset)+7*8)(RSP).
+//
+// R29 is not saved because Go will save and restore it.
+
+#define SAVE_R19_TO_R28(offset) \
+ STP (R19, R20), ((offset)+0*8)(RSP) \
+ STP (R21, R22), ((offset)+2*8)(RSP) \
+ STP (R23, R24), ((offset)+4*8)(RSP) \
+ STP (R25, R26), ((offset)+6*8)(RSP) \
+ STP (R27, g), ((offset)+8*8)(RSP)
+
+#define RESTORE_R19_TO_R28(offset) \
+ LDP ((offset)+0*8)(RSP), (R19, R20) \
+ LDP ((offset)+2*8)(RSP), (R21, R22) \
+ LDP ((offset)+4*8)(RSP), (R23, R24) \
+ LDP ((offset)+6*8)(RSP), (R25, R26) \
+ LDP ((offset)+8*8)(RSP), (R27, g) /* R28 */
+
+#define SAVE_F8_TO_F15(offset) \
+ FSTPD (F8, F9), ((offset)+0*8)(RSP) \
+ FSTPD (F10, F11), ((offset)+2*8)(RSP) \
+ FSTPD (F12, F13), ((offset)+4*8)(RSP) \
+ FSTPD (F14, F15), ((offset)+6*8)(RSP)
+
+#define RESTORE_F8_TO_F15(offset) \
+ FLDPD ((offset)+0*8)(RSP), (F8, F9) \
+ FLDPD ((offset)+2*8)(RSP), (F10, F11) \
+ FLDPD ((offset)+4*8)(RSP), (F12, F13) \
+ FLDPD ((offset)+6*8)(RSP), (F14, F15)
+
diff --git a/src/runtime/cgo/abi_loong64.h b/src/runtime/cgo/abi_loong64.h
new file mode 100644
index 0000000..b10d837
--- /dev/null
+++ b/src/runtime/cgo/abi_loong64.h
@@ -0,0 +1,60 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Macros for transitioning from the host ABI to Go ABI0.
+//
+// These macros save and restore the callee-saved registers
+// from the stack, but they don't adjust stack pointer, so
+// the user should prepare stack space in advance.
+// SAVE_R22_TO_R31(offset) saves R22 ~ R31 to the stack space
+// of ((offset)+0*8)(R3) ~ ((offset)+9*8)(R3).
+//
+// SAVE_F24_TO_F31(offset) saves F24 ~ F31 to the stack space
+// of ((offset)+0*8)(R3) ~ ((offset)+7*8)(R3).
+//
+// Note: g is R22
+
+#define SAVE_R22_TO_R31(offset) \
+ MOVV g, ((offset)+(0*8))(R3) \
+ MOVV R23, ((offset)+(1*8))(R3) \
+ MOVV R24, ((offset)+(2*8))(R3) \
+ MOVV R25, ((offset)+(3*8))(R3) \
+ MOVV R26, ((offset)+(4*8))(R3) \
+ MOVV R27, ((offset)+(5*8))(R3) \
+ MOVV R28, ((offset)+(6*8))(R3) \
+ MOVV R29, ((offset)+(7*8))(R3) \
+ MOVV R30, ((offset)+(8*8))(R3) \
+ MOVV R31, ((offset)+(9*8))(R3)
+
+#define SAVE_F24_TO_F31(offset) \
+ MOVD F24, ((offset)+(0*8))(R3) \
+ MOVD F25, ((offset)+(1*8))(R3) \
+ MOVD F26, ((offset)+(2*8))(R3) \
+ MOVD F27, ((offset)+(3*8))(R3) \
+ MOVD F28, ((offset)+(4*8))(R3) \
+ MOVD F29, ((offset)+(5*8))(R3) \
+ MOVD F30, ((offset)+(6*8))(R3) \
+ MOVD F31, ((offset)+(7*8))(R3)
+
+#define RESTORE_R22_TO_R31(offset) \
+ MOVV ((offset)+(0*8))(R3), g \
+ MOVV ((offset)+(1*8))(R3), R23 \
+ MOVV ((offset)+(2*8))(R3), R24 \
+ MOVV ((offset)+(3*8))(R3), R25 \
+ MOVV ((offset)+(4*8))(R3), R26 \
+ MOVV ((offset)+(5*8))(R3), R27 \
+ MOVV ((offset)+(6*8))(R3), R28 \
+ MOVV ((offset)+(7*8))(R3), R29 \
+ MOVV ((offset)+(8*8))(R3), R30 \
+ MOVV ((offset)+(9*8))(R3), R31
+
+#define RESTORE_F24_TO_F31(offset) \
+ MOVD ((offset)+(0*8))(R3), F24 \
+ MOVD ((offset)+(1*8))(R3), F25 \
+ MOVD ((offset)+(2*8))(R3), F26 \
+ MOVD ((offset)+(3*8))(R3), F27 \
+ MOVD ((offset)+(4*8))(R3), F28 \
+ MOVD ((offset)+(5*8))(R3), F29 \
+ MOVD ((offset)+(6*8))(R3), F30 \
+ MOVD ((offset)+(7*8))(R3), F31
diff --git a/src/runtime/cgo/abi_ppc64x.h b/src/runtime/cgo/abi_ppc64x.h
new file mode 100644
index 0000000..245a526
--- /dev/null
+++ b/src/runtime/cgo/abi_ppc64x.h
@@ -0,0 +1,195 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Macros for transitioning from the host ABI to Go ABI
+//
+// On PPC64/ELFv2 targets, the following registers are callee
+// saved when called from C. They must be preserved before
+// calling into Go which does not preserve any of them.
+//
+// R14-R31
+// CR2-4
+// VR20-31
+// F14-F31
+//
+// xcoff(aix) and ELFv1 are similar, but may only require a
+// subset of these.
+//
+// These macros assume a 16 byte aligned stack pointer. This
+// is required by ELFv1, ELFv2, and AIX PPC64.
+
+#define SAVE_GPR_SIZE (18*8)
+#define SAVE_GPR(offset) \
+ MOVD R14, (offset+8*0)(R1) \
+ MOVD R15, (offset+8*1)(R1) \
+ MOVD R16, (offset+8*2)(R1) \
+ MOVD R17, (offset+8*3)(R1) \
+ MOVD R18, (offset+8*4)(R1) \
+ MOVD R19, (offset+8*5)(R1) \
+ MOVD R20, (offset+8*6)(R1) \
+ MOVD R21, (offset+8*7)(R1) \
+ MOVD R22, (offset+8*8)(R1) \
+ MOVD R23, (offset+8*9)(R1) \
+ MOVD R24, (offset+8*10)(R1) \
+ MOVD R25, (offset+8*11)(R1) \
+ MOVD R26, (offset+8*12)(R1) \
+ MOVD R27, (offset+8*13)(R1) \
+ MOVD R28, (offset+8*14)(R1) \
+ MOVD R29, (offset+8*15)(R1) \
+ MOVD g, (offset+8*16)(R1) \
+ MOVD R31, (offset+8*17)(R1)
+
+#define RESTORE_GPR(offset) \
+ MOVD (offset+8*0)(R1), R14 \
+ MOVD (offset+8*1)(R1), R15 \
+ MOVD (offset+8*2)(R1), R16 \
+ MOVD (offset+8*3)(R1), R17 \
+ MOVD (offset+8*4)(R1), R18 \
+ MOVD (offset+8*5)(R1), R19 \
+ MOVD (offset+8*6)(R1), R20 \
+ MOVD (offset+8*7)(R1), R21 \
+ MOVD (offset+8*8)(R1), R22 \
+ MOVD (offset+8*9)(R1), R23 \
+ MOVD (offset+8*10)(R1), R24 \
+ MOVD (offset+8*11)(R1), R25 \
+ MOVD (offset+8*12)(R1), R26 \
+ MOVD (offset+8*13)(R1), R27 \
+ MOVD (offset+8*14)(R1), R28 \
+ MOVD (offset+8*15)(R1), R29 \
+ MOVD (offset+8*16)(R1), g \
+ MOVD (offset+8*17)(R1), R31
+
+#define SAVE_FPR_SIZE (18*8)
+#define SAVE_FPR(offset) \
+ FMOVD F14, (offset+8*0)(R1) \
+ FMOVD F15, (offset+8*1)(R1) \
+ FMOVD F16, (offset+8*2)(R1) \
+ FMOVD F17, (offset+8*3)(R1) \
+ FMOVD F18, (offset+8*4)(R1) \
+ FMOVD F19, (offset+8*5)(R1) \
+ FMOVD F20, (offset+8*6)(R1) \
+ FMOVD F21, (offset+8*7)(R1) \
+ FMOVD F22, (offset+8*8)(R1) \
+ FMOVD F23, (offset+8*9)(R1) \
+ FMOVD F24, (offset+8*10)(R1) \
+ FMOVD F25, (offset+8*11)(R1) \
+ FMOVD F26, (offset+8*12)(R1) \
+ FMOVD F27, (offset+8*13)(R1) \
+ FMOVD F28, (offset+8*14)(R1) \
+ FMOVD F29, (offset+8*15)(R1) \
+ FMOVD F30, (offset+8*16)(R1) \
+ FMOVD F31, (offset+8*17)(R1)
+
+#define RESTORE_FPR(offset) \
+ FMOVD (offset+8*0)(R1), F14 \
+ FMOVD (offset+8*1)(R1), F15 \
+ FMOVD (offset+8*2)(R1), F16 \
+ FMOVD (offset+8*3)(R1), F17 \
+ FMOVD (offset+8*4)(R1), F18 \
+ FMOVD (offset+8*5)(R1), F19 \
+ FMOVD (offset+8*6)(R1), F20 \
+ FMOVD (offset+8*7)(R1), F21 \
+ FMOVD (offset+8*8)(R1), F22 \
+ FMOVD (offset+8*9)(R1), F23 \
+ FMOVD (offset+8*10)(R1), F24 \
+ FMOVD (offset+8*11)(R1), F25 \
+ FMOVD (offset+8*12)(R1), F26 \
+ FMOVD (offset+8*13)(R1), F27 \
+ FMOVD (offset+8*14)(R1), F28 \
+ FMOVD (offset+8*15)(R1), F29 \
+ FMOVD (offset+8*16)(R1), F30 \
+ FMOVD (offset+8*17)(R1), F31
+
+// Save and restore VR20-31 (aka VSR56-63). These
+// macros must point to a 16B aligned offset.
+#define SAVE_VR_SIZE (12*16)
+#define SAVE_VR(offset, rtmp) \
+ MOVD $(offset+16*0), rtmp \
+ STVX V20, (rtmp)(R1) \
+ MOVD $(offset+16*1), rtmp \
+ STVX V21, (rtmp)(R1) \
+ MOVD $(offset+16*2), rtmp \
+ STVX V22, (rtmp)(R1) \
+ MOVD $(offset+16*3), rtmp \
+ STVX V23, (rtmp)(R1) \
+ MOVD $(offset+16*4), rtmp \
+ STVX V24, (rtmp)(R1) \
+ MOVD $(offset+16*5), rtmp \
+ STVX V25, (rtmp)(R1) \
+ MOVD $(offset+16*6), rtmp \
+ STVX V26, (rtmp)(R1) \
+ MOVD $(offset+16*7), rtmp \
+ STVX V27, (rtmp)(R1) \
+ MOVD $(offset+16*8), rtmp \
+ STVX V28, (rtmp)(R1) \
+ MOVD $(offset+16*9), rtmp \
+ STVX V29, (rtmp)(R1) \
+ MOVD $(offset+16*10), rtmp \
+ STVX V30, (rtmp)(R1) \
+ MOVD $(offset+16*11), rtmp \
+ STVX V31, (rtmp)(R1)
+
+#define RESTORE_VR(offset, rtmp) \
+ MOVD $(offset+16*0), rtmp \
+ LVX (rtmp)(R1), V20 \
+ MOVD $(offset+16*1), rtmp \
+ LVX (rtmp)(R1), V21 \
+ MOVD $(offset+16*2), rtmp \
+ LVX (rtmp)(R1), V22 \
+ MOVD $(offset+16*3), rtmp \
+ LVX (rtmp)(R1), V23 \
+ MOVD $(offset+16*4), rtmp \
+ LVX (rtmp)(R1), V24 \
+ MOVD $(offset+16*5), rtmp \
+ LVX (rtmp)(R1), V25 \
+ MOVD $(offset+16*6), rtmp \
+ LVX (rtmp)(R1), V26 \
+ MOVD $(offset+16*7), rtmp \
+ LVX (rtmp)(R1), V27 \
+ MOVD $(offset+16*8), rtmp \
+ LVX (rtmp)(R1), V28 \
+ MOVD $(offset+16*9), rtmp \
+ LVX (rtmp)(R1), V29 \
+ MOVD $(offset+16*10), rtmp \
+ LVX (rtmp)(R1), V30 \
+ MOVD $(offset+16*11), rtmp \
+ LVX (rtmp)(R1), V31
+
+// LR and CR are saved in the caller's frame. The callee must
+// make space for all other callee-save registers.
+#define SAVE_ALL_REG_SIZE (SAVE_GPR_SIZE+SAVE_FPR_SIZE+SAVE_VR_SIZE)
+
+// Stack a frame and save all callee-save registers following the
+// host OS's ABI. Fortunately, this is identical for AIX, ELFv1, and
+// ELFv2. All host ABIs require the stack pointer to maintain 16 byte
+// alignment, and save the callee-save registers in the same places.
+//
+// To restate, R1 is assumed to be aligned when this macro is used.
+// This assumes the caller's frame is compliant with the host ABI.
+// CR and LR are saved into the caller's frame per the host ABI.
+// R0 is initialized to $0 as expected by Go.
+#define STACK_AND_SAVE_HOST_TO_GO_ABI(extra) \
+ MOVD LR, R0 \
+ MOVD R0, 16(R1) \
+ MOVW CR, R0 \
+ MOVD R0, 8(R1) \
+ MOVDU R1, -(extra)-FIXED_FRAME-SAVE_ALL_REG_SIZE(R1) \
+ SAVE_GPR(extra+FIXED_FRAME) \
+ SAVE_FPR(extra+FIXED_FRAME+SAVE_GPR_SIZE) \
+ SAVE_VR(extra+FIXED_FRAME+SAVE_GPR_SIZE+SAVE_FPR_SIZE, R0) \
+ MOVD $0, R0
+
+// This unstacks the frame, restoring all callee-save registers
+// as saved by STACK_AND_SAVE_HOST_TO_GO_ABI.
+//
+// R0 is not guaranteed to contain $0 after this macro.
+#define UNSTACK_AND_RESTORE_GO_TO_HOST_ABI(extra) \
+ RESTORE_GPR(extra+FIXED_FRAME) \
+ RESTORE_FPR(extra+FIXED_FRAME+SAVE_GPR_SIZE) \
+ RESTORE_VR(extra+FIXED_FRAME+SAVE_GPR_SIZE+SAVE_FPR_SIZE, R0) \
+ ADD $(extra+FIXED_FRAME+SAVE_ALL_REG_SIZE), R1 \
+ MOVD 16(R1), R0 \
+ MOVD R0, LR \
+ MOVD 8(R1), R0 \
+ MOVW R0, CR
diff --git a/src/runtime/cgo/asm_386.s b/src/runtime/cgo/asm_386.s
new file mode 100644
index 0000000..f9a662a
--- /dev/null
+++ b/src/runtime/cgo/asm_386.s
@@ -0,0 +1,42 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
+// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
+// Use a local trampoline, to avoid taking the address of a dynamically exported
+// function.
+TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
+ MOVL _crosscall2_ptr(SB), AX
+ MOVL $crosscall2_trampoline<>(SB), BX
+ MOVL BX, (AX)
+ RET
+
+TEXT crosscall2_trampoline<>(SB),NOSPLIT,$0-0
+ JMP crosscall2(SB)
+
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls cgocallback with three arguments.
+// fn is the PC of a func(a unsafe.Pointer) function.
+TEXT crosscall2(SB),NOSPLIT,$28-16
+ MOVL BP, 24(SP)
+ MOVL BX, 20(SP)
+ MOVL SI, 16(SP)
+ MOVL DI, 12(SP)
+
+ MOVL ctxt+12(FP), AX
+ MOVL AX, 8(SP)
+ MOVL a+4(FP), AX
+ MOVL AX, 4(SP)
+ MOVL fn+0(FP), AX
+ MOVL AX, 0(SP)
+ CALL runtime·cgocallback(SB)
+
+ MOVL 12(SP), DI
+ MOVL 16(SP), SI
+ MOVL 20(SP), BX
+ MOVL 24(SP), BP
+ RET
diff --git a/src/runtime/cgo/asm_amd64.s b/src/runtime/cgo/asm_amd64.s
new file mode 100644
index 0000000..6bf1363
--- /dev/null
+++ b/src/runtime/cgo/asm_amd64.s
@@ -0,0 +1,47 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+#include "abi_amd64.h"
+
+// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
+// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
+// Use a local trampoline, to avoid taking the address of a dynamically exported
+// function.
+TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
+ MOVQ _crosscall2_ptr(SB), AX
+ MOVQ $crosscall2_trampoline<>(SB), BX
+ MOVQ BX, (AX)
+ RET
+
+TEXT crosscall2_trampoline<>(SB),NOSPLIT,$0-0
+ JMP crosscall2(SB)
+
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls cgocallback with three arguments.
+// fn is the PC of a func(a unsafe.Pointer) function.
+// This signature is known to SWIG, so we can't change it.
+TEXT crosscall2(SB),NOSPLIT,$0-0
+ PUSH_REGS_HOST_TO_ABI0()
+
+ // Make room for arguments to cgocallback.
+ ADJSP $0x18
+#ifndef GOOS_windows
+ MOVQ DI, 0x0(SP) /* fn */
+ MOVQ SI, 0x8(SP) /* arg */
+ // Skip n in DX.
+ MOVQ CX, 0x10(SP) /* ctxt */
+#else
+ MOVQ CX, 0x0(SP) /* fn */
+ MOVQ DX, 0x8(SP) /* arg */
+ // Skip n in R8.
+ MOVQ R9, 0x10(SP) /* ctxt */
+#endif
+
+ CALL runtime·cgocallback(SB)
+
+ ADJSP $-0x18
+ POP_REGS_HOST_TO_ABI0()
+ RET
diff --git a/src/runtime/cgo/asm_arm.s b/src/runtime/cgo/asm_arm.s
new file mode 100644
index 0000000..425899e
--- /dev/null
+++ b/src/runtime/cgo/asm_arm.s
@@ -0,0 +1,69 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
+// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
+// Use a local trampoline, to avoid taking the address of a dynamically exported
+// function.
+TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
+ MOVW _crosscall2_ptr(SB), R1
+ MOVW $crosscall2_trampoline<>(SB), R2
+ MOVW R2, (R1)
+ RET
+
+TEXT crosscall2_trampoline<>(SB),NOSPLIT,$0-0
+ JMP crosscall2(SB)
+
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls cgocallback with three arguments.
+// fn is the PC of a func(a unsafe.Pointer) function.
+TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
+ SUB $(8*9), R13 // Reserve space for the floating point registers.
+ // The C arguments arrive in R0, R1, R2, and R3. We want to
+ // pass R0, R1, and R3 to Go, so we push those on the stack.
+ // Also, save C callee-save registers R4-R12.
+ MOVM.WP [R0, R1, R3, R4, R5, R6, R7, R8, R9, g, R11, R12], (R13)
+ // Finally, save the link register R14. This also puts the
+ // arguments we pushed for cgocallback where they need to be,
+ // starting at 4(R13).
+ MOVW.W R14, -4(R13)
+
+ // Skip floating point registers if goarmsoftfp!=0.
+ MOVB runtime·goarmsoftfp(SB), R11
+ CMP $0, R11
+ BNE skipfpsave
+ MOVD F8, (13*4+8*1)(R13)
+ MOVD F9, (13*4+8*2)(R13)
+ MOVD F10, (13*4+8*3)(R13)
+ MOVD F11, (13*4+8*4)(R13)
+ MOVD F12, (13*4+8*5)(R13)
+ MOVD F13, (13*4+8*6)(R13)
+ MOVD F14, (13*4+8*7)(R13)
+ MOVD F15, (13*4+8*8)(R13)
+
+skipfpsave:
+ BL runtime·load_g(SB)
+ // We set up the arguments to cgocallback when saving registers above.
+ BL runtime·cgocallback(SB)
+
+ MOVB runtime·goarmsoftfp(SB), R11
+ CMP $0, R11
+ BNE skipfprest
+ MOVD (13*4+8*1)(R13), F8
+ MOVD (13*4+8*2)(R13), F9
+ MOVD (13*4+8*3)(R13), F10
+ MOVD (13*4+8*4)(R13), F11
+ MOVD (13*4+8*5)(R13), F12
+ MOVD (13*4+8*6)(R13), F13
+ MOVD (13*4+8*7)(R13), F14
+ MOVD (13*4+8*8)(R13), F15
+
+skipfprest:
+ MOVW.P 4(R13), R14
+ MOVM.IAW (R13), [R0, R1, R3, R4, R5, R6, R7, R8, R9, g, R11, R12]
+ ADD $(8*9), R13
+ MOVW R14, R15
diff --git a/src/runtime/cgo/asm_arm64.s b/src/runtime/cgo/asm_arm64.s
new file mode 100644
index 0000000..5492dc1
--- /dev/null
+++ b/src/runtime/cgo/asm_arm64.s
@@ -0,0 +1,50 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+#include "abi_arm64.h"
+
+// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
+// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
+// Use a local trampoline, to avoid taking the address of a dynamically exported
+// function.
+TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
+ MOVD _crosscall2_ptr(SB), R1
+ MOVD $crosscall2_trampoline<>(SB), R2
+ MOVD R2, (R1)
+ RET
+
+TEXT crosscall2_trampoline<>(SB),NOSPLIT,$0-0
+ JMP crosscall2(SB)
+
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls cgocallback with three arguments.
+// fn is the PC of a func(a unsafe.Pointer) function.
+TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
+ /*
+ * We still need to save all callee save register as before, and then
+ * push 3 args for fn (R0, R1, R3), skipping R2.
+ * Also note that at procedure entry in gc world, 8(RSP) will be the
+ * first arg.
+ */
+ SUB $(8*24), RSP
+ STP (R0, R1), (8*1)(RSP)
+ MOVD R3, (8*3)(RSP)
+
+ SAVE_R19_TO_R28(8*4)
+ SAVE_F8_TO_F15(8*14)
+ STP (R29, R30), (8*22)(RSP)
+
+
+ // Initialize Go ABI environment
+ BL runtime·load_g(SB)
+ BL runtime·cgocallback(SB)
+
+ RESTORE_R19_TO_R28(8*4)
+ RESTORE_F8_TO_F15(8*14)
+ LDP (8*22)(RSP), (R29, R30)
+
+ ADD $(8*24), RSP
+ RET
diff --git a/src/runtime/cgo/asm_loong64.s b/src/runtime/cgo/asm_loong64.s
new file mode 100644
index 0000000..19c8d74
--- /dev/null
+++ b/src/runtime/cgo/asm_loong64.s
@@ -0,0 +1,53 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+#include "abi_loong64.h"
+
+// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
+// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
+// Use a local trampoline, to avoid taking the address of a dynamically exported
+// function.
+TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
+ MOVV _crosscall2_ptr(SB), R5
+ MOVV $crosscall2_trampoline<>(SB), R6
+ MOVV R6, (R5)
+ RET
+
+TEXT crosscall2_trampoline<>(SB),NOSPLIT,$0-0
+ JMP crosscall2(SB)
+
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls cgocallback with three arguments.
+// fn is the PC of a func(a unsafe.Pointer) function.
+TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
+ /*
+ * We still need to save all callee save register as before, and then
+ * push 3 args for fn (R4, R5, R7), skipping R6.
+ * Also note that at procedure entry in gc world, 8(R29) will be the
+ * first arg.
+ */
+
+ ADDV $(-23*8), R3
+ MOVV R4, (1*8)(R3) // fn unsafe.Pointer
+ MOVV R5, (2*8)(R3) // a unsafe.Pointer
+ MOVV R7, (3*8)(R3) // ctxt uintptr
+
+ SAVE_R22_TO_R31((4*8))
+ SAVE_F24_TO_F31((14*8))
+ MOVV R1, (22*8)(R3)
+
+ // Initialize Go ABI environment
+ JAL runtime·load_g(SB)
+
+ JAL runtime·cgocallback(SB)
+
+ RESTORE_R22_TO_R31((4*8))
+ RESTORE_F24_TO_F31((14*8))
+ MOVV (22*8)(R3), R1
+
+ ADDV $(23*8), R3
+
+ RET
diff --git a/src/runtime/cgo/asm_mips64x.s b/src/runtime/cgo/asm_mips64x.s
new file mode 100644
index 0000000..af817d5
--- /dev/null
+++ b/src/runtime/cgo/asm_mips64x.s
@@ -0,0 +1,95 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build mips64 || mips64le
+
+#include "textflag.h"
+
+// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
+// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
+// Use a local trampoline, to avoid taking the address of a dynamically exported
+// function.
+TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
+ MOVV _crosscall2_ptr(SB), R5
+ MOVV $crosscall2_trampoline<>(SB), R6
+ MOVV R6, (R5)
+ RET
+
+TEXT crosscall2_trampoline<>(SB),NOSPLIT,$0-0
+ JMP crosscall2(SB)
+
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls cgocallback with three arguments.
+// fn is the PC of a func(a unsafe.Pointer) function.
+TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
+ /*
+ * We still need to save all callee save register as before, and then
+ * push 3 args for fn (R4, R5, R7), skipping R6.
+ * Also note that at procedure entry in gc world, 8(R29) will be the
+ * first arg.
+ */
+#ifndef GOMIPS64_softfloat
+ ADDV $(-8*23), R29
+#else
+ ADDV $(-8*15), R29
+#endif
+ MOVV R4, (8*1)(R29) // fn unsafe.Pointer
+ MOVV R5, (8*2)(R29) // a unsafe.Pointer
+ MOVV R7, (8*3)(R29) // ctxt uintptr
+ MOVV R16, (8*4)(R29)
+ MOVV R17, (8*5)(R29)
+ MOVV R18, (8*6)(R29)
+ MOVV R19, (8*7)(R29)
+ MOVV R20, (8*8)(R29)
+ MOVV R21, (8*9)(R29)
+ MOVV R22, (8*10)(R29)
+ MOVV R23, (8*11)(R29)
+ MOVV RSB, (8*12)(R29)
+ MOVV g, (8*13)(R29)
+ MOVV R31, (8*14)(R29)
+#ifndef GOMIPS64_softfloat
+ MOVD F24, (8*15)(R29)
+ MOVD F25, (8*16)(R29)
+ MOVD F26, (8*17)(R29)
+ MOVD F27, (8*18)(R29)
+ MOVD F28, (8*19)(R29)
+ MOVD F29, (8*20)(R29)
+ MOVD F30, (8*21)(R29)
+ MOVD F31, (8*22)(R29)
+#endif
+ // Initialize Go ABI environment
+ // prepare SB register = PC & 0xffffffff00000000
+ BGEZAL R0, 1(PC)
+ SRLV $32, R31, RSB
+ SLLV $32, RSB
+ JAL runtime·load_g(SB)
+
+ JAL runtime·cgocallback(SB)
+
+ MOVV (8*4)(R29), R16
+ MOVV (8*5)(R29), R17
+ MOVV (8*6)(R29), R18
+ MOVV (8*7)(R29), R19
+ MOVV (8*8)(R29), R20
+ MOVV (8*9)(R29), R21
+ MOVV (8*10)(R29), R22
+ MOVV (8*11)(R29), R23
+ MOVV (8*12)(R29), RSB
+ MOVV (8*13)(R29), g
+ MOVV (8*14)(R29), R31
+#ifndef GOMIPS64_softfloat
+ MOVD (8*15)(R29), F24
+ MOVD (8*16)(R29), F25
+ MOVD (8*17)(R29), F26
+ MOVD (8*18)(R29), F27
+ MOVD (8*19)(R29), F28
+ MOVD (8*20)(R29), F29
+ MOVD (8*21)(R29), F30
+ MOVD (8*22)(R29), F31
+ ADDV $(8*23), R29
+#else
+ ADDV $(8*15), R29
+#endif
+ RET
diff --git a/src/runtime/cgo/asm_mipsx.s b/src/runtime/cgo/asm_mipsx.s
new file mode 100644
index 0000000..198c59a
--- /dev/null
+++ b/src/runtime/cgo/asm_mipsx.s
@@ -0,0 +1,88 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build mips || mipsle
+
+#include "textflag.h"
+
+// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
+// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
+// Use a local trampoline, to avoid taking the address of a dynamically exported
+// function.
+TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
+ MOVW _crosscall2_ptr(SB), R5
+ MOVW $crosscall2_trampoline<>(SB), R6
+ MOVW R6, (R5)
+ RET
+
+TEXT crosscall2_trampoline<>(SB),NOSPLIT,$0-0
+ JMP crosscall2(SB)
+
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls cgocallback with three arguments.
+// fn is the PC of a func(a unsafe.Pointer) function.
+TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
+ /*
+ * We still need to save all callee save register as before, and then
+ * push 3 args for fn (R4, R5, R7), skipping R6.
+ * Also note that at procedure entry in gc world, 4(R29) will be the
+ * first arg.
+ */
+
+ // Space for 9 caller-saved GPR + LR + 6 caller-saved FPR.
+ // O32 ABI allows us to smash 16 bytes argument area of caller frame.
+#ifndef GOMIPS_softfloat
+ SUBU $(4*14+8*6-16), R29
+#else
+ SUBU $(4*14-16), R29 // For soft-float, no FPR.
+#endif
+ MOVW R4, (4*1)(R29) // fn unsafe.Pointer
+ MOVW R5, (4*2)(R29) // a unsafe.Pointer
+ MOVW R7, (4*3)(R29) // ctxt uintptr
+ MOVW R16, (4*4)(R29)
+ MOVW R17, (4*5)(R29)
+ MOVW R18, (4*6)(R29)
+ MOVW R19, (4*7)(R29)
+ MOVW R20, (4*8)(R29)
+ MOVW R21, (4*9)(R29)
+ MOVW R22, (4*10)(R29)
+ MOVW R23, (4*11)(R29)
+ MOVW g, (4*12)(R29)
+ MOVW R31, (4*13)(R29)
+#ifndef GOMIPS_softfloat
+ MOVD F20, (4*14)(R29)
+ MOVD F22, (4*14+8*1)(R29)
+ MOVD F24, (4*14+8*2)(R29)
+ MOVD F26, (4*14+8*3)(R29)
+ MOVD F28, (4*14+8*4)(R29)
+ MOVD F30, (4*14+8*5)(R29)
+#endif
+ JAL runtime·load_g(SB)
+
+ JAL runtime·cgocallback(SB)
+
+ MOVW (4*4)(R29), R16
+ MOVW (4*5)(R29), R17
+ MOVW (4*6)(R29), R18
+ MOVW (4*7)(R29), R19
+ MOVW (4*8)(R29), R20
+ MOVW (4*9)(R29), R21
+ MOVW (4*10)(R29), R22
+ MOVW (4*11)(R29), R23
+ MOVW (4*12)(R29), g
+ MOVW (4*13)(R29), R31
+#ifndef GOMIPS_softfloat
+ MOVD (4*14)(R29), F20
+ MOVD (4*14+8*1)(R29), F22
+ MOVD (4*14+8*2)(R29), F24
+ MOVD (4*14+8*3)(R29), F26
+ MOVD (4*14+8*4)(R29), F28
+ MOVD (4*14+8*5)(R29), F30
+
+ ADDU $(4*14+8*6-16), R29
+#else
+ ADDU $(4*14-16), R29
+#endif
+ RET
diff --git a/src/runtime/cgo/asm_ppc64x.s b/src/runtime/cgo/asm_ppc64x.s
new file mode 100644
index 0000000..a389745
--- /dev/null
+++ b/src/runtime/cgo/asm_ppc64x.s
@@ -0,0 +1,70 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build ppc64 || ppc64le
+
+#include "textflag.h"
+#include "asm_ppc64x.h"
+#include "abi_ppc64x.h"
+
+#ifdef GO_PPC64X_HAS_FUNCDESC
+// crosscall2 is marked with go:cgo_export_static. On AIX, this creates and exports
+// the symbol name and descriptor as the AIX linker expects, but does not work if
+// referenced from within Go. Create and use an aliased descriptor of crosscall2
+// to workaround this.
+DEFINE_PPC64X_FUNCDESC(_crosscall2<>, crosscall2)
+#define CROSSCALL2_FPTR $_crosscall2<>(SB)
+#else
+// Use a local trampoline, to avoid taking the address of a dynamically exported
+// function.
+#define CROSSCALL2_FPTR $crosscall2_trampoline<>(SB)
+#endif
+
+// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
+// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
+TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
+ MOVD _crosscall2_ptr(SB), R5
+ MOVD CROSSCALL2_FPTR, R6
+ MOVD R6, (R5)
+ RET
+
+TEXT crosscall2_trampoline<>(SB),NOSPLIT,$0-0
+ JMP crosscall2(SB)
+
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls cgocallback with three arguments.
+// fn is the PC of a func(a unsafe.Pointer) function.
+// The value of R2 is saved on the new stack frame, and not
+// the caller's frame due to issue #43228.
+TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
+ // Start with standard C stack frame layout and linkage, allocate
+ // 32 bytes of argument space, save callee-save regs, and set R0 to $0.
+ STACK_AND_SAVE_HOST_TO_GO_ABI(32)
+ // The above will not preserve R2 (TOC). Save it in case Go is
+ // compiled without a TOC pointer (e.g -buildmode=default).
+ MOVD R2, 24(R1)
+
+ // Load the current g.
+ BL runtime·load_g(SB)
+
+#ifdef GO_PPC64X_HAS_FUNCDESC
+ // Load the real entry address from the first slot of the function descriptor.
+ // The first argument fn might be null, that means dropm in pthread key destructor.
+ CMP R3, $0
+ BEQ nil_fn
+ MOVD 8(R3), R2
+ MOVD (R3), R3
+nil_fn:
+#endif
+ MOVD R3, FIXED_FRAME+0(R1) // fn unsafe.Pointer
+ MOVD R4, FIXED_FRAME+8(R1) // a unsafe.Pointer
+ // Skip R5 = n uint32
+ MOVD R6, FIXED_FRAME+16(R1) // ctxt uintptr
+ BL runtime·cgocallback(SB)
+
+ // Restore the old frame, and R2.
+ MOVD 24(R1), R2
+ UNSTACK_AND_RESTORE_GO_TO_HOST_ABI(32)
+ RET
diff --git a/src/runtime/cgo/asm_riscv64.s b/src/runtime/cgo/asm_riscv64.s
new file mode 100644
index 0000000..d75a543
--- /dev/null
+++ b/src/runtime/cgo/asm_riscv64.s
@@ -0,0 +1,91 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
+// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
+// Use a local trampoline, to avoid taking the address of a dynamically exported
+// function.
+TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
+ MOV _crosscall2_ptr(SB), X7
+ MOV $crosscall2_trampoline<>(SB), X8
+ MOV X8, (X7)
+ RET
+
+TEXT crosscall2_trampoline<>(SB),NOSPLIT,$0-0
+ JMP crosscall2(SB)
+
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls cgocallback with three arguments.
+// fn is the PC of a func(a unsafe.Pointer) function.
+TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
+ /*
+ * Push arguments for fn (X10, X11, X13), along with all callee-save
+ * registers. Note that at procedure entry the first argument is at
+ * 8(X2).
+ */
+ ADD $(-8*29), X2
+ MOV X10, (8*1)(X2) // fn unsafe.Pointer
+ MOV X11, (8*2)(X2) // a unsafe.Pointer
+ MOV X13, (8*3)(X2) // ctxt uintptr
+ MOV X8, (8*4)(X2)
+ MOV X9, (8*5)(X2)
+ MOV X18, (8*6)(X2)
+ MOV X19, (8*7)(X2)
+ MOV X20, (8*8)(X2)
+ MOV X21, (8*9)(X2)
+ MOV X22, (8*10)(X2)
+ MOV X23, (8*11)(X2)
+ MOV X24, (8*12)(X2)
+ MOV X25, (8*13)(X2)
+ MOV X26, (8*14)(X2)
+ MOV g, (8*15)(X2)
+ MOV X1, (8*16)(X2)
+ MOVD F8, (8*17)(X2)
+ MOVD F9, (8*18)(X2)
+ MOVD F18, (8*19)(X2)
+ MOVD F19, (8*20)(X2)
+ MOVD F20, (8*21)(X2)
+ MOVD F21, (8*22)(X2)
+ MOVD F22, (8*23)(X2)
+ MOVD F23, (8*24)(X2)
+ MOVD F24, (8*25)(X2)
+ MOVD F25, (8*26)(X2)
+ MOVD F26, (8*27)(X2)
+ MOVD F27, (8*28)(X2)
+
+ // Initialize Go ABI environment
+ CALL runtime·load_g(SB)
+ CALL runtime·cgocallback(SB)
+
+ MOV (8*4)(X2), X8
+ MOV (8*5)(X2), X9
+ MOV (8*6)(X2), X18
+ MOV (8*7)(X2), X19
+ MOV (8*8)(X2), X20
+ MOV (8*9)(X2), X21
+ MOV (8*10)(X2), X22
+ MOV (8*11)(X2), X23
+ MOV (8*12)(X2), X24
+ MOV (8*13)(X2), X25
+ MOV (8*14)(X2), X26
+ MOV (8*15)(X2), g
+ MOV (8*16)(X2), X1
+ MOVD (8*17)(X2), F8
+ MOVD (8*18)(X2), F9
+ MOVD (8*19)(X2), F18
+ MOVD (8*20)(X2), F19
+ MOVD (8*21)(X2), F20
+ MOVD (8*22)(X2), F21
+ MOVD (8*23)(X2), F22
+ MOVD (8*24)(X2), F23
+ MOVD (8*25)(X2), F24
+ MOVD (8*26)(X2), F25
+ MOVD (8*27)(X2), F26
+ MOVD (8*28)(X2), F27
+ ADD $(8*29), X2
+
+ RET
diff --git a/src/runtime/cgo/asm_s390x.s b/src/runtime/cgo/asm_s390x.s
new file mode 100644
index 0000000..8f74fd5
--- /dev/null
+++ b/src/runtime/cgo/asm_s390x.s
@@ -0,0 +1,68 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
+// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
+// Use a local trampoline, to avoid taking the address of a dynamically exported
+// function.
+TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
+ MOVD _crosscall2_ptr(SB), R1
+ MOVD $crosscall2_trampoline<>(SB), R2
+ MOVD R2, (R1)
+ RET
+
+TEXT crosscall2_trampoline<>(SB),NOSPLIT,$0-0
+ JMP crosscall2(SB)
+
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls cgocallback with three arguments.
+// fn is the PC of a func(a unsafe.Pointer) function.
+TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
+ // Start with standard C stack frame layout and linkage.
+
+ // Save R6-R15 in the register save area of the calling function.
+ STMG R6, R15, 48(R15)
+
+ // Allocate 96 bytes on the stack.
+ MOVD $-96(R15), R15
+
+ // Save F8-F15 in our stack frame.
+ FMOVD F8, 32(R15)
+ FMOVD F9, 40(R15)
+ FMOVD F10, 48(R15)
+ FMOVD F11, 56(R15)
+ FMOVD F12, 64(R15)
+ FMOVD F13, 72(R15)
+ FMOVD F14, 80(R15)
+ FMOVD F15, 88(R15)
+
+ // Initialize Go ABI environment.
+ BL runtime·load_g(SB)
+
+ MOVD R2, 8(R15) // fn unsafe.Pointer
+ MOVD R3, 16(R15) // a unsafe.Pointer
+ // Skip R4 = n uint32
+ MOVD R5, 24(R15) // ctxt uintptr
+ BL runtime·cgocallback(SB)
+
+ FMOVD 32(R15), F8
+ FMOVD 40(R15), F9
+ FMOVD 48(R15), F10
+ FMOVD 56(R15), F11
+ FMOVD 64(R15), F12
+ FMOVD 72(R15), F13
+ FMOVD 80(R15), F14
+ FMOVD 88(R15), F15
+
+ // De-allocate stack frame.
+ MOVD $96(R15), R15
+
+ // Restore R6-R15.
+ LMG 48(R15), R6, R15
+
+ RET
+
diff --git a/src/runtime/cgo/asm_wasm.s b/src/runtime/cgo/asm_wasm.s
new file mode 100644
index 0000000..e7f01bd
--- /dev/null
+++ b/src/runtime/cgo/asm_wasm.s
@@ -0,0 +1,11 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
+ UNDEF
+
+TEXT crosscall2(SB), NOSPLIT, $0
+ UNDEF
diff --git a/src/runtime/cgo/callbacks.go b/src/runtime/cgo/callbacks.go
new file mode 100644
index 0000000..3c246a8
--- /dev/null
+++ b/src/runtime/cgo/callbacks.go
@@ -0,0 +1,152 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgo
+
+import "unsafe"
+
+// These utility functions are available to be called from code
+// compiled with gcc via crosscall2.
+
+// The declaration of crosscall2 is:
+// void crosscall2(void (*fn)(void *), void *, int);
+//
+// We need to export the symbol crosscall2 in order to support
+// callbacks from shared libraries. This applies regardless of
+// linking mode.
+//
+// Compatibility note: SWIG uses crosscall2 in exactly one situation:
+// to call _cgo_panic using the pattern shown below. We need to keep
+// that pattern working. In particular, crosscall2 actually takes four
+// arguments, but it works to call it with three arguments when
+// calling _cgo_panic.
+//
+//go:cgo_export_static crosscall2
+//go:cgo_export_dynamic crosscall2
+
+// Panic. The argument is converted into a Go string.
+
+// Call like this in code compiled with gcc:
+// struct { const char *p; } a;
+// a.p = /* string to pass to panic */;
+// crosscall2(_cgo_panic, &a, sizeof a);
+// /* The function call will not return. */
+
+// TODO: We should export a regular C function to panic, change SWIG
+// to use that instead of the above pattern, and then we can drop
+// backwards-compatibility from crosscall2 and stop exporting it.
+
+//go:linkname _runtime_cgo_panic_internal runtime._cgo_panic_internal
+func _runtime_cgo_panic_internal(p *byte)
+
+//go:linkname _cgo_panic _cgo_panic
+//go:cgo_export_static _cgo_panic
+//go:cgo_export_dynamic _cgo_panic
+func _cgo_panic(a *struct{ cstr *byte }) {
+ _runtime_cgo_panic_internal(a.cstr)
+}
+
+//go:cgo_import_static x_cgo_init
+//go:linkname x_cgo_init x_cgo_init
+//go:linkname _cgo_init _cgo_init
+var x_cgo_init byte
+var _cgo_init = &x_cgo_init
+
+//go:cgo_import_static x_cgo_thread_start
+//go:linkname x_cgo_thread_start x_cgo_thread_start
+//go:linkname _cgo_thread_start _cgo_thread_start
+var x_cgo_thread_start byte
+var _cgo_thread_start = &x_cgo_thread_start
+
+// Creates a new system thread without updating any Go state.
+//
+// This method is invoked during shared library loading to create a new OS
+// thread to perform the runtime initialization. This method is similar to
+// _cgo_sys_thread_start except that it doesn't update any Go state.
+
+//go:cgo_import_static x_cgo_sys_thread_create
+//go:linkname x_cgo_sys_thread_create x_cgo_sys_thread_create
+//go:linkname _cgo_sys_thread_create _cgo_sys_thread_create
+var x_cgo_sys_thread_create byte
+var _cgo_sys_thread_create = &x_cgo_sys_thread_create
+
+// Indicates whether a dummy thread key has been created or not.
+//
+// When calling go exported function from C, we register a destructor
+// callback, for a dummy thread key, by using pthread_key_create.
+
+//go:cgo_import_static x_cgo_pthread_key_created
+//go:linkname x_cgo_pthread_key_created x_cgo_pthread_key_created
+//go:linkname _cgo_pthread_key_created _cgo_pthread_key_created
+var x_cgo_pthread_key_created byte
+var _cgo_pthread_key_created = &x_cgo_pthread_key_created
+
+// Export crosscall2 to a c function pointer variable.
+// Used to dropm in pthread key destructor, while C thread is exiting.
+
+//go:cgo_import_static x_crosscall2_ptr
+//go:linkname x_crosscall2_ptr x_crosscall2_ptr
+//go:linkname _crosscall2_ptr _crosscall2_ptr
+var x_crosscall2_ptr byte
+var _crosscall2_ptr = &x_crosscall2_ptr
+
+// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
+// It's for the runtime package to call at init time.
+func set_crosscall2()
+
+//go:linkname _set_crosscall2 runtime.set_crosscall2
+var _set_crosscall2 = set_crosscall2
+
+// Store the g into the thread-specific value.
+// So that pthread_key_destructor will dropm when the thread is exiting.
+
+//go:cgo_import_static x_cgo_bindm
+//go:linkname x_cgo_bindm x_cgo_bindm
+//go:linkname _cgo_bindm _cgo_bindm
+var x_cgo_bindm byte
+var _cgo_bindm = &x_cgo_bindm
+
+// Notifies that the runtime has been initialized.
+//
+// We currently block at every CGO entry point (via _cgo_wait_runtime_init_done)
+// to ensure that the runtime has been initialized before the CGO call is
+// executed. This is necessary for shared libraries where we kickoff runtime
+// initialization in a separate thread and return without waiting for this
+// thread to complete the init.
+
+//go:cgo_import_static x_cgo_notify_runtime_init_done
+//go:linkname x_cgo_notify_runtime_init_done x_cgo_notify_runtime_init_done
+//go:linkname _cgo_notify_runtime_init_done _cgo_notify_runtime_init_done
+var x_cgo_notify_runtime_init_done byte
+var _cgo_notify_runtime_init_done = &x_cgo_notify_runtime_init_done
+
+// Sets the traceback context function. See runtime.SetCgoTraceback.
+
+//go:cgo_import_static x_cgo_set_context_function
+//go:linkname x_cgo_set_context_function x_cgo_set_context_function
+//go:linkname _cgo_set_context_function _cgo_set_context_function
+var x_cgo_set_context_function byte
+var _cgo_set_context_function = &x_cgo_set_context_function
+
+// Calls a libc function to execute background work injected via libc
+// interceptors, such as processing pending signals under the thread
+// sanitizer.
+//
+// Left as a nil pointer if no libc interceptors are expected.
+
+//go:cgo_import_static _cgo_yield
+//go:linkname _cgo_yield _cgo_yield
+var _cgo_yield unsafe.Pointer
+
+//go:cgo_export_static _cgo_topofstack
+//go:cgo_export_dynamic _cgo_topofstack
+
+// x_cgo_getstackbound gets the thread's C stack size and
+// set the G's stack bound based on the stack size.
+
+//go:cgo_import_static x_cgo_getstackbound
+//go:linkname x_cgo_getstackbound x_cgo_getstackbound
+//go:linkname _cgo_getstackbound _cgo_getstackbound
+var x_cgo_getstackbound byte
+var _cgo_getstackbound = &x_cgo_getstackbound
diff --git a/src/runtime/cgo/callbacks_aix.go b/src/runtime/cgo/callbacks_aix.go
new file mode 100644
index 0000000..8f756fb
--- /dev/null
+++ b/src/runtime/cgo/callbacks_aix.go
@@ -0,0 +1,12 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgo
+
+// These functions must be exported in order to perform
+// longcall on cgo programs (cf gcc_aix_ppc64.c).
+//
+//go:cgo_export_static __cgo_topofstack
+//go:cgo_export_static runtime.rt0_go
+//go:cgo_export_static _rt0_ppc64_aix_lib
diff --git a/src/runtime/cgo/callbacks_traceback.go b/src/runtime/cgo/callbacks_traceback.go
new file mode 100644
index 0000000..dae31a8
--- /dev/null
+++ b/src/runtime/cgo/callbacks_traceback.go
@@ -0,0 +1,17 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build darwin || linux
+
+package cgo
+
+import _ "unsafe" // for go:linkname
+
+// Calls the traceback function passed to SetCgoTraceback.
+
+//go:cgo_import_static x_cgo_callers
+//go:linkname x_cgo_callers x_cgo_callers
+//go:linkname _cgo_callers _cgo_callers
+var x_cgo_callers byte
+var _cgo_callers = &x_cgo_callers
diff --git a/src/runtime/cgo/cgo.go b/src/runtime/cgo/cgo.go
new file mode 100644
index 0000000..1e3a502
--- /dev/null
+++ b/src/runtime/cgo/cgo.go
@@ -0,0 +1,40 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package cgo contains runtime support for code generated
+by the cgo tool. See the documentation for the cgo command
+for details on using cgo.
+*/
+package cgo
+
+/*
+
+#cgo darwin,!arm64 LDFLAGS: -lpthread
+#cgo darwin,arm64 LDFLAGS: -framework CoreFoundation
+#cgo dragonfly LDFLAGS: -lpthread
+#cgo freebsd LDFLAGS: -lpthread
+#cgo android LDFLAGS: -llog
+#cgo !android,linux LDFLAGS: -lpthread
+#cgo netbsd LDFLAGS: -lpthread
+#cgo openbsd LDFLAGS: -lpthread
+#cgo aix LDFLAGS: -Wl,-berok
+#cgo solaris LDFLAGS: -lxnet
+#cgo solaris LDFLAGS: -lsocket
+
+// Use -fno-stack-protector to avoid problems locating the
+// proper support functions. See issues #52919, #54313, #58385.
+#cgo CFLAGS: -Wall -Werror -fno-stack-protector
+
+#cgo solaris CPPFLAGS: -D_POSIX_PTHREAD_SEMANTICS
+
+*/
+import "C"
+
+import "runtime/internal/sys"
+
+// Incomplete is used specifically for the semantics of incomplete C types.
+type Incomplete struct {
+ _ sys.NotInHeap
+}
diff --git a/src/runtime/cgo/dragonfly.go b/src/runtime/cgo/dragonfly.go
new file mode 100644
index 0000000..36d70e3
--- /dev/null
+++ b/src/runtime/cgo/dragonfly.go
@@ -0,0 +1,19 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build dragonfly
+
+package cgo
+
+import _ "unsafe" // for go:linkname
+
+// Supply environ and __progname, because we don't
+// link against the standard DragonFly crt0.o and the
+// libc dynamic library needs them.
+
+//go:linkname _environ environ
+//go:linkname _progname __progname
+
+var _environ uintptr
+var _progname uintptr
diff --git a/src/runtime/cgo/freebsd.go b/src/runtime/cgo/freebsd.go
new file mode 100644
index 0000000..2d9f624
--- /dev/null
+++ b/src/runtime/cgo/freebsd.go
@@ -0,0 +1,22 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build freebsd
+
+package cgo
+
+import _ "unsafe" // for go:linkname
+
+// Supply environ and __progname, because we don't
+// link against the standard FreeBSD crt0.o and the
+// libc dynamic library needs them.
+
+//go:linkname _environ environ
+//go:linkname _progname __progname
+
+//go:cgo_export_dynamic environ
+//go:cgo_export_dynamic __progname
+
+var _environ uintptr
+var _progname uintptr
diff --git a/src/runtime/cgo/gcc_386.S b/src/runtime/cgo/gcc_386.S
new file mode 100644
index 0000000..d4c5934
--- /dev/null
+++ b/src/runtime/cgo/gcc_386.S
@@ -0,0 +1,48 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+.file "gcc_386.S"
+
+/*
+ * Windows still insists on underscore prefixes for C function names.
+ */
+#if defined(_WIN32)
+#define EXT(s) _##s
+#else
+#define EXT(s) s
+#endif
+
+/*
+ * void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g)
+ *
+ * Calling into the gc tool chain, where all registers are caller save.
+ * Called from standard x86 ABI, where %ebp, %ebx, %esi,
+ * and %edi are callee-save, so they must be saved explicitly.
+ */
+.globl EXT(crosscall1)
+EXT(crosscall1):
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+
+ movl 16(%ebp), %eax /* g */
+ pushl %eax
+ movl 12(%ebp), %eax /* setg_gcc */
+ call *%eax
+ popl %eax
+
+ movl 8(%ebp), %eax /* fn */
+ call *%eax
+
+ popl %edi
+ popl %esi
+ popl %ebx
+ popl %ebp
+ ret
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",@progbits
+#endif
diff --git a/src/runtime/cgo/gcc_aix_ppc64.S b/src/runtime/cgo/gcc_aix_ppc64.S
new file mode 100644
index 0000000..6f465f0
--- /dev/null
+++ b/src/runtime/cgo/gcc_aix_ppc64.S
@@ -0,0 +1,132 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+.file "gcc_aix_ppc64.S"
+
+/*
+ * void crosscall_ppc64(void (*fn)(void), void *g)
+ *
+ * Calling into the gc tool chain, where all registers are caller save.
+ * Called from standard ppc64 C ABI, where r2, r14-r31, f14-f31 are
+ * callee-save, so they must be saved explicitly.
+ * AIX has a special assembly syntax and keywords that can be mixed with
+ * Linux assembly.
+ */
+ .toc
+ .csect .text[PR]
+ .globl crosscall_ppc64
+ .globl .crosscall_ppc64
+ .csect crosscall_ppc64[DS]
+crosscall_ppc64:
+ .llong .crosscall_ppc64, TOC[tc0], 0
+ .csect .text[PR]
+.crosscall_ppc64:
+ // Start with standard C stack frame layout and linkage
+ mflr 0
+ std 0, 16(1) // Save LR in caller's frame
+ std 2, 40(1) // Save TOC in caller's frame
+ bl saveregs
+ stdu 1, -296(1)
+
+ // Set up Go ABI constant registers
+ // Must match _cgo_reginit in runtime package.
+ xor 0, 0, 0
+
+ // Restore g pointer (r30 in Go ABI, which may have been clobbered by C)
+ mr 30, 4
+
+ // Call fn
+ mr 12, 3
+ mtctr 12
+ bctrl
+
+ addi 1, 1, 296
+ bl restoreregs
+ ld 2, 40(1)
+ ld 0, 16(1)
+ mtlr 0
+ blr
+
+saveregs:
+ // Save callee-save registers
+ // O=-288; for R in {14..31}; do echo "\tstd\t$R, $O(1)"; ((O+=8)); done; for F in f{14..31}; do echo "\tstfd\t$F, $O(1)"; ((O+=8)); done
+ std 14, -288(1)
+ std 15, -280(1)
+ std 16, -272(1)
+ std 17, -264(1)
+ std 18, -256(1)
+ std 19, -248(1)
+ std 20, -240(1)
+ std 21, -232(1)
+ std 22, -224(1)
+ std 23, -216(1)
+ std 24, -208(1)
+ std 25, -200(1)
+ std 26, -192(1)
+ std 27, -184(1)
+ std 28, -176(1)
+ std 29, -168(1)
+ std 30, -160(1)
+ std 31, -152(1)
+ stfd 14, -144(1)
+ stfd 15, -136(1)
+ stfd 16, -128(1)
+ stfd 17, -120(1)
+ stfd 18, -112(1)
+ stfd 19, -104(1)
+ stfd 20, -96(1)
+ stfd 21, -88(1)
+ stfd 22, -80(1)
+ stfd 23, -72(1)
+ stfd 24, -64(1)
+ stfd 25, -56(1)
+ stfd 26, -48(1)
+ stfd 27, -40(1)
+ stfd 28, -32(1)
+ stfd 29, -24(1)
+ stfd 30, -16(1)
+ stfd 31, -8(1)
+
+ blr
+
+restoreregs:
+ // O=-288; for R in {14..31}; do echo "\tld\t$R, $O(1)"; ((O+=8)); done; for F in {14..31}; do echo "\tlfd\t$F, $O(1)"; ((O+=8)); done
+ ld 14, -288(1)
+ ld 15, -280(1)
+ ld 16, -272(1)
+ ld 17, -264(1)
+ ld 18, -256(1)
+ ld 19, -248(1)
+ ld 20, -240(1)
+ ld 21, -232(1)
+ ld 22, -224(1)
+ ld 23, -216(1)
+ ld 24, -208(1)
+ ld 25, -200(1)
+ ld 26, -192(1)
+ ld 27, -184(1)
+ ld 28, -176(1)
+ ld 29, -168(1)
+ ld 30, -160(1)
+ ld 31, -152(1)
+ lfd 14, -144(1)
+ lfd 15, -136(1)
+ lfd 16, -128(1)
+ lfd 17, -120(1)
+ lfd 18, -112(1)
+ lfd 19, -104(1)
+ lfd 20, -96(1)
+ lfd 21, -88(1)
+ lfd 22, -80(1)
+ lfd 23, -72(1)
+ lfd 24, -64(1)
+ lfd 25, -56(1)
+ lfd 26, -48(1)
+ lfd 27, -40(1)
+ lfd 28, -32(1)
+ lfd 29, -24(1)
+ lfd 30, -16(1)
+ lfd 31, -8(1)
+
+ blr
diff --git a/src/runtime/cgo/gcc_aix_ppc64.c b/src/runtime/cgo/gcc_aix_ppc64.c
new file mode 100644
index 0000000..9dd9524
--- /dev/null
+++ b/src/runtime/cgo/gcc_aix_ppc64.c
@@ -0,0 +1,35 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * On AIX, call to _cgo_topofstack and Go main are forced to be a longcall.
+ * Without it, ld might add trampolines in the middle of .text section
+ * to reach these functions which are normally declared in runtime package.
+ */
+extern int __attribute__((longcall)) __cgo_topofstack(void);
+extern int __attribute__((longcall)) runtime_rt0_go(int argc, char **argv);
+extern void __attribute__((longcall)) _rt0_ppc64_aix_lib(void);
+
+int _cgo_topofstack(void) {
+ return __cgo_topofstack();
+}
+
+int main(int argc, char **argv) {
+ return runtime_rt0_go(argc, argv);
+}
+
+static void libinit(void) __attribute__ ((constructor));
+
+/*
+ * libinit aims to replace .init_array section which isn't available on aix.
+ * Using __attribute__ ((constructor)) let gcc handles this instead of
+ * adding special code in cmd/link.
+ * However, it will be called for every Go programs which has cgo.
+ * Inside _rt0_ppc64_aix_lib(), runtime.isarchive is checked in order
+ * to know if this program is a c-archive or a simple cgo program.
+ * If it's not set, _rt0_ppc64_ax_lib() returns directly.
+ */
+static void libinit() {
+ _rt0_ppc64_aix_lib();
+}
diff --git a/src/runtime/cgo/gcc_amd64.S b/src/runtime/cgo/gcc_amd64.S
new file mode 100644
index 0000000..3ba793a
--- /dev/null
+++ b/src/runtime/cgo/gcc_amd64.S
@@ -0,0 +1,55 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+.file "gcc_amd64.S"
+
+/*
+ * Apple still insists on underscore prefixes for C function names.
+ */
+#if defined(__APPLE__)
+#define EXT(s) _##s
+#else
+#define EXT(s) s
+#endif
+
+/*
+ * void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g)
+ *
+ * Calling into the gc tool chain, where all registers are caller save.
+ * Called from standard x86-64 ABI, where %rbx, %rbp, %r12-%r15
+ * are callee-save so they must be saved explicitly.
+ * The standard x86-64 ABI passes the three arguments m, g, fn
+ * in %rdi, %rsi, %rdx.
+ */
+.globl EXT(crosscall1)
+EXT(crosscall1):
+ pushq %rbx
+ pushq %rbp
+ pushq %r12
+ pushq %r13
+ pushq %r14
+ pushq %r15
+
+#if defined(_WIN64)
+ movq %r8, %rdi /* arg of setg_gcc */
+ call *%rdx /* setg_gcc */
+ call *%rcx /* fn */
+#else
+ movq %rdi, %rbx
+ movq %rdx, %rdi /* arg of setg_gcc */
+ call *%rsi /* setg_gcc */
+ call *%rbx /* fn */
+#endif
+
+ popq %r15
+ popq %r14
+ popq %r13
+ popq %r12
+ popq %rbp
+ popq %rbx
+ ret
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",@progbits
+#endif
diff --git a/src/runtime/cgo/gcc_android.c b/src/runtime/cgo/gcc_android.c
new file mode 100644
index 0000000..7ea2135
--- /dev/null
+++ b/src/runtime/cgo/gcc_android.c
@@ -0,0 +1,90 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <stdarg.h>
+#include <android/log.h>
+#include <pthread.h>
+#include <dlfcn.h>
+#include "libcgo.h"
+
+void
+fatalf(const char* format, ...)
+{
+ va_list ap;
+
+ // Write to both stderr and logcat.
+ //
+ // When running from an .apk, /dev/stderr and /dev/stdout
+ // redirect to /dev/null. And when running a test binary
+ // via adb shell, it's easy to miss logcat.
+
+ fprintf(stderr, "runtime/cgo: ");
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+
+ va_start(ap, format);
+ __android_log_vprint(ANDROID_LOG_FATAL, "runtime/cgo", format, ap);
+ va_end(ap);
+
+ abort();
+}
+
+// Truncated to a different magic value on 32-bit; that's ok.
+#define magic1 (0x23581321345589ULL)
+
+// From https://android.googlesource.com/platform/bionic/+/refs/heads/android10-tests-release/libc/private/bionic_asm_tls.h#69.
+#define TLS_SLOT_APP 2
+
+// inittls allocates a thread-local storage slot for g.
+//
+// It finds the first available slot using pthread_key_create and uses
+// it as the offset value for runtime.tls_g.
+static void
+inittls(void **tlsg, void **tlsbase)
+{
+ pthread_key_t k;
+ int i, err;
+ void *handle, *get_ver, *off;
+
+ // Check for Android Q where we can use the free TLS_SLOT_APP slot.
+ handle = dlopen("libc.so", RTLD_LAZY);
+ if (handle == NULL) {
+ fatalf("inittls: failed to dlopen main program");
+ return;
+ }
+ // android_get_device_api_level is introduced in Android Q, so its mere presence
+ // is enough.
+ get_ver = dlsym(handle, "android_get_device_api_level");
+ dlclose(handle);
+ if (get_ver != NULL) {
+ off = (void *)(TLS_SLOT_APP*sizeof(void *));
+ // tlsg is initialized to Q's free TLS slot. Verify it while we're here.
+ if (*tlsg != off) {
+ fatalf("tlsg offset wrong, got %ld want %ld\n", *tlsg, off);
+ }
+ return;
+ }
+
+ err = pthread_key_create(&k, nil);
+ if(err != 0) {
+ fatalf("pthread_key_create failed: %d", err);
+ }
+ pthread_setspecific(k, (void*)magic1);
+ // If thread local slots are laid out as we expect, our magic word will
+ // be located at some low offset from tlsbase. However, just in case something went
+ // wrong, the search is limited to sensible offsets. PTHREAD_KEYS_MAX was the
+ // original limit, but issue 19472 made a higher limit necessary.
+ for (i=0; i<384; i++) {
+ if (*(tlsbase+i) == (void*)magic1) {
+ *tlsg = (void*)(i*sizeof(void *));
+ pthread_setspecific(k, 0);
+ return;
+ }
+ }
+ fatalf("inittls: could not find pthread key");
+}
+
+void (*x_cgo_inittls)(void **tlsg, void **tlsbase) = inittls;
diff --git a/src/runtime/cgo/gcc_arm.S b/src/runtime/cgo/gcc_arm.S
new file mode 100644
index 0000000..3df8143
--- /dev/null
+++ b/src/runtime/cgo/gcc_arm.S
@@ -0,0 +1,31 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+.file "gcc_arm.S"
+
+/*
+ * void crosscall1(void (*fn)(void), void (*setg_gcc)(void *g), void *g)
+ *
+ * Calling into the gc tool chain, where all registers are caller save.
+ * Called from standard ARM EABI, where r4-r11 are callee-save, so they
+ * must be saved explicitly.
+ */
+.globl crosscall1
+crosscall1:
+ push {r4, r5, r6, r7, r8, r9, r10, r11, ip, lr}
+ mov r4, r0
+ mov r5, r1
+ mov r0, r2
+
+ // Because the assembler might target an earlier revision of the ISA
+ // by default, we encode BLX as a .word.
+ .word 0xe12fff35 // blx r5 // setg(g)
+ .word 0xe12fff34 // blx r4 // fn()
+
+ pop {r4, r5, r6, r7, r8, r9, r10, r11, ip, pc}
+
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/src/runtime/cgo/gcc_arm64.S b/src/runtime/cgo/gcc_arm64.S
new file mode 100644
index 0000000..865f67c
--- /dev/null
+++ b/src/runtime/cgo/gcc_arm64.S
@@ -0,0 +1,84 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+.file "gcc_arm64.S"
+
+/*
+ * Apple still insists on underscore prefixes for C function names.
+ */
+#if defined(__APPLE__)
+#define EXT(s) _##s
+#else
+#define EXT(s) s
+#endif
+
+// Apple's ld64 wants 4-byte alignment for ARM code sections.
+// .align in both Apple as and GNU as treat n as aligning to 2**n bytes.
+.align 2
+
+/*
+ * void crosscall1(void (*fn)(void), void (*setg_gcc)(void *g), void *g)
+ *
+ * Calling into the gc tool chain, where all registers are caller save.
+ * Called from standard ARM EABI, where x19-x29 are callee-save, so they
+ * must be saved explicitly, along with x30 (LR).
+ */
+.globl EXT(crosscall1)
+EXT(crosscall1):
+ .cfi_startproc
+ stp x29, x30, [sp, #-96]!
+ .cfi_def_cfa_offset 96
+ .cfi_offset 29, -96
+ .cfi_offset 30, -88
+ mov x29, sp
+ .cfi_def_cfa_register 29
+ stp x19, x20, [sp, #80]
+ .cfi_offset 19, -16
+ .cfi_offset 20, -8
+ stp x21, x22, [sp, #64]
+ .cfi_offset 21, -32
+ .cfi_offset 22, -24
+ stp x23, x24, [sp, #48]
+ .cfi_offset 23, -48
+ .cfi_offset 24, -40
+ stp x25, x26, [sp, #32]
+ .cfi_offset 25, -64
+ .cfi_offset 26, -56
+ stp x27, x28, [sp, #16]
+ .cfi_offset 27, -80
+ .cfi_offset 28, -72
+
+ mov x19, x0
+ mov x20, x1
+ mov x0, x2
+
+ blr x20
+ blr x19
+
+ ldp x27, x28, [sp, #16]
+ .cfi_restore 27
+ .cfi_restore 28
+ ldp x25, x26, [sp, #32]
+ .cfi_restore 25
+ .cfi_restore 26
+ ldp x23, x24, [sp, #48]
+ .cfi_restore 23
+ .cfi_restore 24
+ ldp x21, x22, [sp, #64]
+ .cfi_restore 21
+ .cfi_restore 22
+ ldp x19, x20, [sp, #80]
+ .cfi_restore 19
+ .cfi_restore 20
+ ldp x29, x30, [sp], #96
+ .cfi_restore 29
+ .cfi_restore 30
+ .cfi_def_cfa 31, 0
+ ret
+ .cfi_endproc
+
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/src/runtime/cgo/gcc_context.c b/src/runtime/cgo/gcc_context.c
new file mode 100644
index 0000000..ad58692
--- /dev/null
+++ b/src/runtime/cgo/gcc_context.c
@@ -0,0 +1,20 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build unix || windows
+
+#include "libcgo.h"
+
+// Releases the cgo traceback context.
+void _cgo_release_context(uintptr_t ctxt) {
+ void (*pfn)(struct context_arg*);
+
+ pfn = _cgo_get_context_function();
+ if (ctxt != 0 && pfn != nil) {
+ struct context_arg arg;
+
+ arg.Context = ctxt;
+ (*pfn)(&arg);
+ }
+}
diff --git a/src/runtime/cgo/gcc_darwin_amd64.c b/src/runtime/cgo/gcc_darwin_amd64.c
new file mode 100644
index 0000000..5b5e369
--- /dev/null
+++ b/src/runtime/cgo/gcc_darwin_amd64.c
@@ -0,0 +1,60 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <string.h> /* for strerror */
+#include <pthread.h>
+#include <signal.h>
+#include "libcgo.h"
+#include "libcgo_unix.h"
+
+static void* threadentry(void*);
+static void (*setg_gcc)(void*);
+
+void
+x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
+{
+ setg_gcc = setg;
+ _cgo_set_stacklo(g, NULL);
+}
+
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ sigset_t ign, oset;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ sigfillset(&ign);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+ size = pthread_get_stacksize_np(pthread_self());
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, size);
+ // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
+ ts->g->stackhi = size;
+ err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
+
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
+
+ if (err != 0) {
+ fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+ abort();
+ }
+}
+
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ crosscall1(ts.fn, setg_gcc, (void*)ts.g);
+ return nil;
+}
diff --git a/src/runtime/cgo/gcc_darwin_arm64.c b/src/runtime/cgo/gcc_darwin_arm64.c
new file mode 100644
index 0000000..f1344de
--- /dev/null
+++ b/src/runtime/cgo/gcc_darwin_arm64.c
@@ -0,0 +1,139 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <limits.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h> /* for strerror */
+#include <sys/param.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "libcgo.h"
+#include "libcgo_unix.h"
+
+#include <TargetConditionals.h>
+
+#if TARGET_OS_IPHONE
+#include <CoreFoundation/CFBundle.h>
+#include <CoreFoundation/CFString.h>
+#endif
+
+static void *threadentry(void*);
+static void (*setg_gcc)(void*);
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ sigset_t ign, oset;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ //fprintf(stderr, "runtime/cgo: _cgo_sys_thread_start: fn=%p, g=%p\n", ts->fn, ts->g); // debug
+ sigfillset(&ign);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+ size = pthread_get_stacksize_np(pthread_self());
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, size);
+ // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
+ ts->g->stackhi = size;
+ err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
+
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
+
+ if (err != 0) {
+ fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+ abort();
+ }
+}
+
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+#if TARGET_OS_IPHONE
+ darwin_arm_init_thread_exception_port();
+#endif
+
+ crosscall1(ts.fn, setg_gcc, (void*)ts.g);
+ return nil;
+}
+
+#if TARGET_OS_IPHONE
+
+// init_working_dir sets the current working directory to the app root.
+// By default ios/arm64 processes start in "/".
+static void
+init_working_dir()
+{
+ CFBundleRef bundle = CFBundleGetMainBundle();
+ if (bundle == NULL) {
+ fprintf(stderr, "runtime/cgo: no main bundle\n");
+ return;
+ }
+ CFURLRef url_ref = CFBundleCopyResourceURL(bundle, CFSTR("Info"), CFSTR("plist"), NULL);
+ if (url_ref == NULL) {
+ // No Info.plist found. It can happen on Corellium virtual devices.
+ return;
+ }
+ CFStringRef url_str_ref = CFURLGetString(url_ref);
+ char buf[MAXPATHLEN];
+ Boolean res = CFStringGetCString(url_str_ref, buf, sizeof(buf), kCFStringEncodingUTF8);
+ CFRelease(url_ref);
+ if (!res) {
+ fprintf(stderr, "runtime/cgo: cannot get URL string\n");
+ return;
+ }
+
+ // url is of the form "file:///path/to/Info.plist".
+ // strip it down to the working directory "/path/to".
+ int url_len = strlen(buf);
+ if (url_len < sizeof("file://")+sizeof("/Info.plist")) {
+ fprintf(stderr, "runtime/cgo: bad URL: %s\n", buf);
+ return;
+ }
+ buf[url_len-sizeof("/Info.plist")+1] = 0;
+ char *dir = &buf[0] + sizeof("file://")-1;
+
+ if (chdir(dir) != 0) {
+ fprintf(stderr, "runtime/cgo: chdir(%s) failed\n", dir);
+ }
+
+ // The test harness in go_ios_exec passes the relative working directory
+ // in the GoExecWrapperWorkingDirectory property of the app bundle.
+ CFStringRef wd_ref = CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("GoExecWrapperWorkingDirectory"));
+ if (wd_ref != NULL) {
+ if (!CFStringGetCString(wd_ref, buf, sizeof(buf), kCFStringEncodingUTF8)) {
+ fprintf(stderr, "runtime/cgo: cannot get GoExecWrapperWorkingDirectory string\n");
+ return;
+ }
+ if (chdir(buf) != 0) {
+ fprintf(stderr, "runtime/cgo: chdir(%s) failed\n", buf);
+ }
+ }
+}
+
+#endif // TARGET_OS_IPHONE
+
+void
+x_cgo_init(G *g, void (*setg)(void*))
+{
+ //fprintf(stderr, "x_cgo_init = %p\n", &x_cgo_init); // aid debugging in presence of ASLR
+ setg_gcc = setg;
+ _cgo_set_stacklo(g, NULL);
+
+#if TARGET_OS_IPHONE
+ darwin_arm_init_mach_exception_handler();
+ darwin_arm_init_thread_exception_port();
+ init_working_dir();
+#endif
+}
diff --git a/src/runtime/cgo/gcc_dragonfly_amd64.c b/src/runtime/cgo/gcc_dragonfly_amd64.c
new file mode 100644
index 0000000..009d4b4
--- /dev/null
+++ b/src/runtime/cgo/gcc_dragonfly_amd64.c
@@ -0,0 +1,60 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include "libcgo.h"
+#include "libcgo_unix.h"
+
+static void* threadentry(void*);
+static void (*setg_gcc)(void*);
+
+void
+x_cgo_init(G *g, void (*setg)(void*))
+{
+ setg_gcc = setg;
+ _cgo_set_stacklo(g, NULL);
+}
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ sigset_t ign, oset;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ SIGFILLSET(ign);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+
+ // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
+ ts->g->stackhi = size;
+ err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
+
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
+
+ if (err != 0) {
+ fatalf("pthread_create failed: %s", strerror(err));
+ }
+}
+
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ crosscall1(ts.fn, setg_gcc, (void*)ts.g);
+ return nil;
+}
diff --git a/src/runtime/cgo/gcc_fatalf.c b/src/runtime/cgo/gcc_fatalf.c
new file mode 100644
index 0000000..822c015
--- /dev/null
+++ b/src/runtime/cgo/gcc_fatalf.c
@@ -0,0 +1,23 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build aix || (!android && linux) || dragonfly || freebsd || netbsd || openbsd || solaris
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "libcgo.h"
+
+void
+fatalf(const char* format, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "runtime/cgo: ");
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ abort();
+}
diff --git a/src/runtime/cgo/gcc_freebsd.c b/src/runtime/cgo/gcc_freebsd.c
new file mode 100644
index 0000000..a941211
--- /dev/null
+++ b/src/runtime/cgo/gcc_freebsd.c
@@ -0,0 +1,71 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build freebsd && (386 || arm || arm64 || riscv64)
+
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <machine/sysarch.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include "libcgo.h"
+#include "libcgo_unix.h"
+
+#ifdef ARM_TP_ADDRESS
+// ARM_TP_ADDRESS is (ARM_VECTORS_HIGH + 0x1000) or 0xffff1000
+// and is known to runtime.read_tls_fallback. Verify it with
+// cpp.
+#if ARM_TP_ADDRESS != 0xffff1000
+#error Wrong ARM_TP_ADDRESS!
+#endif
+#endif
+
+static void* threadentry(void*);
+static void (*setg_gcc)(void*);
+
+void
+x_cgo_init(G *g, void (*setg)(void*))
+{
+ setg_gcc = setg;
+ _cgo_set_stacklo(g, NULL);
+}
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ sigset_t ign, oset;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ SIGFILLSET(ign);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
+ ts->g->stackhi = size;
+ err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
+
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
+
+ if (err != 0) {
+ fatalf("pthread_create failed: %s", strerror(err));
+ }
+}
+
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ crosscall1(ts.fn, setg_gcc, ts.g);
+ return nil;
+}
diff --git a/src/runtime/cgo/gcc_freebsd_amd64.c b/src/runtime/cgo/gcc_freebsd_amd64.c
new file mode 100644
index 0000000..31905f2
--- /dev/null
+++ b/src/runtime/cgo/gcc_freebsd_amd64.c
@@ -0,0 +1,71 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <sys/types.h>
+#include <errno.h>
+#include <sys/signalvar.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include "libcgo.h"
+#include "libcgo_unix.h"
+
+static void* threadentry(void*);
+static void (*setg_gcc)(void*);
+
+void
+x_cgo_init(G *g, void (*setg)(void*))
+{
+ uintptr *pbounds;
+
+ // Deal with memory sanitizer/clang interaction.
+ // See gcc_linux_amd64.c for details.
+ setg_gcc = setg;
+ pbounds = (uintptr*)malloc(2 * sizeof(uintptr));
+ if (pbounds == NULL) {
+ fatalf("malloc failed: %s", strerror(errno));
+ }
+ _cgo_set_stacklo(g, pbounds);
+ free(pbounds);
+}
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ sigset_t ign, oset;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ SIGFILLSET(ign);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
+ ts->g->stackhi = size;
+ err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
+
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
+
+ if (err != 0) {
+ fatalf("pthread_create failed: %s", strerror(err));
+ }
+}
+
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ _cgo_tsan_acquire();
+ free(v);
+ _cgo_tsan_release();
+
+ crosscall1(ts.fn, setg_gcc, (void*)ts.g);
+ return nil;
+}
diff --git a/src/runtime/cgo/gcc_freebsd_sigaction.c b/src/runtime/cgo/gcc_freebsd_sigaction.c
new file mode 100644
index 0000000..b324983
--- /dev/null
+++ b/src/runtime/cgo/gcc_freebsd_sigaction.c
@@ -0,0 +1,80 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build freebsd && amd64
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <signal.h>
+
+#include "libcgo.h"
+
+// go_sigaction_t is a C version of the sigactiont struct from
+// os_freebsd.go. This definition — and its conversion to and from struct
+// sigaction — are specific to freebsd/amd64.
+typedef struct {
+ uint32_t __bits[_SIG_WORDS];
+} go_sigset_t;
+typedef struct {
+ uintptr_t handler;
+ int32_t flags;
+ go_sigset_t mask;
+} go_sigaction_t;
+
+int32_t
+x_cgo_sigaction(intptr_t signum, const go_sigaction_t *goact, go_sigaction_t *oldgoact) {
+ int32_t ret;
+ struct sigaction act;
+ struct sigaction oldact;
+ size_t i;
+
+ _cgo_tsan_acquire();
+
+ memset(&act, 0, sizeof act);
+ memset(&oldact, 0, sizeof oldact);
+
+ if (goact) {
+ if (goact->flags & SA_SIGINFO) {
+ act.sa_sigaction = (void(*)(int, siginfo_t*, void*))(goact->handler);
+ } else {
+ act.sa_handler = (void(*)(int))(goact->handler);
+ }
+ sigemptyset(&act.sa_mask);
+ for (i = 0; i < 8 * sizeof(goact->mask); i++) {
+ if (goact->mask.__bits[i/32] & ((uint32_t)(1)<<(i&31))) {
+ sigaddset(&act.sa_mask, i+1);
+ }
+ }
+ act.sa_flags = goact->flags;
+ }
+
+ ret = sigaction(signum, goact ? &act : NULL, oldgoact ? &oldact : NULL);
+ if (ret == -1) {
+ // runtime.sigaction expects _cgo_sigaction to return errno on error.
+ _cgo_tsan_release();
+ return errno;
+ }
+
+ if (oldgoact) {
+ if (oldact.sa_flags & SA_SIGINFO) {
+ oldgoact->handler = (uintptr_t)(oldact.sa_sigaction);
+ } else {
+ oldgoact->handler = (uintptr_t)(oldact.sa_handler);
+ }
+ for (i = 0 ; i < _SIG_WORDS; i++) {
+ oldgoact->mask.__bits[i] = 0;
+ }
+ for (i = 0; i < 8 * sizeof(oldgoact->mask); i++) {
+ if (sigismember(&oldact.sa_mask, i+1) == 1) {
+ oldgoact->mask.__bits[i/32] |= (uint32_t)(1)<<(i&31);
+ }
+ }
+ oldgoact->flags = oldact.sa_flags;
+ }
+
+ _cgo_tsan_release();
+ return ret;
+}
diff --git a/src/runtime/cgo/gcc_libinit.c b/src/runtime/cgo/gcc_libinit.c
new file mode 100644
index 0000000..68f4a02
--- /dev/null
+++ b/src/runtime/cgo/gcc_libinit.c
@@ -0,0 +1,171 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build unix
+
+#include <pthread.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> // strerror
+#include <time.h>
+#include "libcgo.h"
+#include "libcgo_unix.h"
+
+static pthread_cond_t runtime_init_cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t runtime_init_mu = PTHREAD_MUTEX_INITIALIZER;
+static int runtime_init_done;
+
+// pthread_g is a pthread specific key, for storing the g that binded to the C thread.
+// The registered pthread_key_destructor will dropm, when the pthread-specified value g is not NULL,
+// while a C thread is exiting.
+static pthread_key_t pthread_g;
+static void pthread_key_destructor(void* g);
+uintptr_t x_cgo_pthread_key_created;
+void (*x_crosscall2_ptr)(void (*fn)(void *), void *, int, size_t);
+
+// The context function, used when tracing back C calls into Go.
+static void (*cgo_context_function)(struct context_arg*);
+
+void
+x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
+ pthread_t p;
+ int err = _cgo_try_pthread_create(&p, NULL, func, arg);
+ if (err != 0) {
+ fprintf(stderr, "pthread_create failed: %s", strerror(err));
+ abort();
+ }
+}
+
+uintptr_t
+_cgo_wait_runtime_init_done(void) {
+ void (*pfn)(struct context_arg*);
+ pfn = __atomic_load_n(&cgo_context_function, __ATOMIC_CONSUME);
+
+ int done = 2;
+ if (__atomic_load_n(&runtime_init_done, __ATOMIC_CONSUME) != done) {
+ pthread_mutex_lock(&runtime_init_mu);
+ while (__atomic_load_n(&runtime_init_done, __ATOMIC_CONSUME) == 0) {
+ pthread_cond_wait(&runtime_init_cond, &runtime_init_mu);
+ }
+
+ // The key and x_cgo_pthread_key_created are for the whole program,
+ // whereas the specific and destructor is per thread.
+ if (x_cgo_pthread_key_created == 0 && pthread_key_create(&pthread_g, pthread_key_destructor) == 0) {
+ x_cgo_pthread_key_created = 1;
+ }
+
+
+ // TODO(iant): For the case of a new C thread calling into Go, such
+ // as when using -buildmode=c-archive, we know that Go runtime
+ // initialization is complete but we do not know that all Go init
+ // functions have been run. We should not fetch cgo_context_function
+ // until they have been, because that is where a call to
+ // SetCgoTraceback is likely to occur. We are going to wait for Go
+ // initialization to be complete anyhow, later, by waiting for
+ // main_init_done to be closed in cgocallbackg1. We should wait here
+ // instead. See also issue #15943.
+ pfn = __atomic_load_n(&cgo_context_function, __ATOMIC_CONSUME);
+
+ __atomic_store_n(&runtime_init_done, done, __ATOMIC_RELEASE);
+ pthread_mutex_unlock(&runtime_init_mu);
+ }
+
+ if (pfn != nil) {
+ struct context_arg arg;
+
+ arg.Context = 0;
+ (*pfn)(&arg);
+ return arg.Context;
+ }
+ return 0;
+}
+
+// _cgo_set_stacklo sets g->stacklo based on the stack size.
+// This is common code called from x_cgo_init, which is itself
+// called by rt0_go in the runtime package.
+void _cgo_set_stacklo(G *g, uintptr *pbounds)
+{
+ uintptr bounds[2];
+
+ // pbounds can be passed in by the caller; see gcc_linux_amd64.c.
+ if (pbounds == NULL) {
+ pbounds = &bounds[0];
+ }
+
+ x_cgo_getstackbound(pbounds);
+
+ g->stacklo = *pbounds;
+
+ // Sanity check the results now, rather than getting a
+ // morestack on g0 crash.
+ if (g->stacklo >= g->stackhi) {
+ fprintf(stderr, "runtime/cgo: bad stack bounds: lo=%p hi=%p\n", (void*)(g->stacklo), (void*)(g->stackhi));
+ abort();
+ }
+}
+
+// Store the g into a thread-specific value associated with the pthread key pthread_g.
+// And pthread_key_destructor will dropm when the thread is exiting.
+void x_cgo_bindm(void* g) {
+ // We assume this will always succeed, otherwise, there might be extra M leaking,
+ // when a C thread exits after a cgo call.
+ // We only invoke this function once per thread in runtime.needAndBindM,
+ // and the next calls just reuse the bound m.
+ pthread_setspecific(pthread_g, g);
+}
+
+void
+x_cgo_notify_runtime_init_done(void* dummy __attribute__ ((unused))) {
+ pthread_mutex_lock(&runtime_init_mu);
+ __atomic_store_n(&runtime_init_done, 1, __ATOMIC_RELEASE);
+ pthread_cond_broadcast(&runtime_init_cond);
+ pthread_mutex_unlock(&runtime_init_mu);
+}
+
+// Sets the context function to call to record the traceback context
+// when calling a Go function from C code. Called from runtime.SetCgoTraceback.
+void x_cgo_set_context_function(void (*context)(struct context_arg*)) {
+ __atomic_store_n(&cgo_context_function, context, __ATOMIC_RELEASE);
+}
+
+// Gets the context function.
+void (*(_cgo_get_context_function(void)))(struct context_arg*) {
+ return __atomic_load_n(&cgo_context_function, __ATOMIC_CONSUME);
+}
+
+// _cgo_try_pthread_create retries pthread_create if it fails with
+// EAGAIN.
+int
+_cgo_try_pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*pfn)(void*), void* arg) {
+ int tries;
+ int err;
+ struct timespec ts;
+
+ for (tries = 0; tries < 20; tries++) {
+ err = pthread_create(thread, attr, pfn, arg);
+ if (err == 0) {
+ pthread_detach(*thread);
+ return 0;
+ }
+ if (err != EAGAIN) {
+ return err;
+ }
+ ts.tv_sec = 0;
+ ts.tv_nsec = (tries + 1) * 1000 * 1000; // Milliseconds.
+ nanosleep(&ts, nil);
+ }
+ return EAGAIN;
+}
+
+static void
+pthread_key_destructor(void* g) {
+ if (x_crosscall2_ptr != NULL) {
+ // fn == NULL means dropm.
+ // We restore g by using the stored g, before dropm in runtime.cgocallback,
+ // since the g stored in the TLS by Go might be cleared in some platforms,
+ // before this destructor invoked.
+ x_crosscall2_ptr(NULL, g, 0, 0);
+ }
+}
diff --git a/src/runtime/cgo/gcc_libinit_windows.c b/src/runtime/cgo/gcc_libinit_windows.c
new file mode 100644
index 0000000..9a8c65e
--- /dev/null
+++ b/src/runtime/cgo/gcc_libinit_windows.c
@@ -0,0 +1,158 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <process.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "libcgo.h"
+#include "libcgo_windows.h"
+
+// Ensure there's one symbol marked __declspec(dllexport).
+// If there are no exported symbols, the unfortunate behavior of
+// the binutils linker is to also strip the relocations table,
+// resulting in non-PIE binary. The other option is the
+// --export-all-symbols flag, but we don't need to export all symbols
+// and this may overflow the export table (#40795).
+// See https://sourceware.org/bugzilla/show_bug.cgi?id=19011
+__declspec(dllexport) int _cgo_dummy_export;
+
+static volatile LONG runtime_init_once_gate = 0;
+static volatile LONG runtime_init_once_done = 0;
+
+static CRITICAL_SECTION runtime_init_cs;
+
+static HANDLE runtime_init_wait;
+static int runtime_init_done;
+
+uintptr_t x_cgo_pthread_key_created;
+void (*x_crosscall2_ptr)(void (*fn)(void *), void *, int, size_t);
+
+// Pre-initialize the runtime synchronization objects
+void
+_cgo_preinit_init() {
+ runtime_init_wait = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (runtime_init_wait == NULL) {
+ fprintf(stderr, "runtime: failed to create runtime initialization wait event.\n");
+ abort();
+ }
+
+ InitializeCriticalSection(&runtime_init_cs);
+}
+
+// Make sure that the preinit sequence has run.
+void
+_cgo_maybe_run_preinit() {
+ if (!InterlockedExchangeAdd(&runtime_init_once_done, 0)) {
+ if (InterlockedIncrement(&runtime_init_once_gate) == 1) {
+ _cgo_preinit_init();
+ InterlockedIncrement(&runtime_init_once_done);
+ } else {
+ // Decrement to avoid overflow.
+ InterlockedDecrement(&runtime_init_once_gate);
+ while(!InterlockedExchangeAdd(&runtime_init_once_done, 0)) {
+ Sleep(0);
+ }
+ }
+ }
+}
+
+void
+x_cgo_sys_thread_create(void (*func)(void*), void* arg) {
+ _cgo_beginthread(func, arg);
+}
+
+int
+_cgo_is_runtime_initialized() {
+ EnterCriticalSection(&runtime_init_cs);
+ int status = runtime_init_done;
+ LeaveCriticalSection(&runtime_init_cs);
+ return status;
+}
+
+uintptr_t
+_cgo_wait_runtime_init_done(void) {
+ void (*pfn)(struct context_arg*);
+
+ _cgo_maybe_run_preinit();
+ while (!_cgo_is_runtime_initialized()) {
+ WaitForSingleObject(runtime_init_wait, INFINITE);
+ }
+ pfn = _cgo_get_context_function();
+ if (pfn != nil) {
+ struct context_arg arg;
+
+ arg.Context = 0;
+ (*pfn)(&arg);
+ return arg.Context;
+ }
+ return 0;
+}
+
+// Should not be used since x_cgo_pthread_key_created will always be zero.
+void x_cgo_bindm(void* dummy) {
+ fprintf(stderr, "unexpected cgo_bindm on Windows\n");
+ abort();
+}
+
+void
+x_cgo_notify_runtime_init_done(void* dummy) {
+ _cgo_maybe_run_preinit();
+
+ EnterCriticalSection(&runtime_init_cs);
+ runtime_init_done = 1;
+ LeaveCriticalSection(&runtime_init_cs);
+
+ if (!SetEvent(runtime_init_wait)) {
+ fprintf(stderr, "runtime: failed to signal runtime initialization complete.\n");
+ abort();
+ }
+}
+
+// The context function, used when tracing back C calls into Go.
+static void (*cgo_context_function)(struct context_arg*);
+
+// Sets the context function to call to record the traceback context
+// when calling a Go function from C code. Called from runtime.SetCgoTraceback.
+void x_cgo_set_context_function(void (*context)(struct context_arg*)) {
+ EnterCriticalSection(&runtime_init_cs);
+ cgo_context_function = context;
+ LeaveCriticalSection(&runtime_init_cs);
+}
+
+// Gets the context function.
+void (*(_cgo_get_context_function(void)))(struct context_arg*) {
+ void (*ret)(struct context_arg*);
+
+ EnterCriticalSection(&runtime_init_cs);
+ ret = cgo_context_function;
+ LeaveCriticalSection(&runtime_init_cs);
+ return ret;
+}
+
+void _cgo_beginthread(void (*func)(void*), void* arg) {
+ int tries;
+ uintptr_t thandle;
+
+ for (tries = 0; tries < 20; tries++) {
+ thandle = _beginthread(func, 0, arg);
+ if (thandle == -1 && errno == EACCES) {
+ // "Insufficient resources", try again in a bit.
+ //
+ // Note that the first Sleep(0) is a yield.
+ Sleep(tries); // milliseconds
+ continue;
+ } else if (thandle == -1) {
+ break;
+ }
+ return; // Success!
+ }
+
+ fprintf(stderr, "runtime: failed to create new OS thread (%d)\n", errno);
+ abort();
+}
diff --git a/src/runtime/cgo/gcc_linux.c b/src/runtime/cgo/gcc_linux.c
new file mode 100644
index 0000000..9624df5
--- /dev/null
+++ b/src/runtime/cgo/gcc_linux.c
@@ -0,0 +1,66 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build linux && (386 || arm || loong64 || mips || mipsle || mips64 || mips64le || riscv64)
+
+#include <pthread.h>
+#include <string.h>
+#include <signal.h>
+#include "libcgo.h"
+#include "libcgo_unix.h"
+
+static void *threadentry(void*);
+
+void (*x_cgo_inittls)(void **tlsg, void **tlsbase) __attribute__((common));
+static void (*setg_gcc)(void*);
+
+void
+x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
+{
+ setg_gcc = setg;
+
+ _cgo_set_stacklo(g, NULL);
+
+ if (x_cgo_inittls) {
+ x_cgo_inittls(tlsg, tlsbase);
+ }
+}
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ sigset_t ign, oset;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ sigfillset(&ign);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
+ ts->g->stackhi = size;
+ err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
+
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
+
+ if (err != 0) {
+ fatalf("pthread_create failed: %s", strerror(err));
+ }
+}
+
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ crosscall1(ts.fn, setg_gcc, ts.g);
+ return nil;
+}
diff --git a/src/runtime/cgo/gcc_linux_amd64.c b/src/runtime/cgo/gcc_linux_amd64.c
new file mode 100644
index 0000000..dcb596e
--- /dev/null
+++ b/src/runtime/cgo/gcc_linux_amd64.c
@@ -0,0 +1,91 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <pthread.h>
+#include <errno.h>
+#include <string.h> // strerror
+#include <signal.h>
+#include <stdlib.h>
+#include "libcgo.h"
+#include "libcgo_unix.h"
+
+static void* threadentry(void*);
+static void (*setg_gcc)(void*);
+
+// This will be set in gcc_android.c for android-specific customization.
+void (*x_cgo_inittls)(void **tlsg, void **tlsbase) __attribute__((common));
+
+void
+x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
+{
+ uintptr *pbounds;
+
+ /* The memory sanitizer distributed with versions of clang
+ before 3.8 has a bug: if you call mmap before malloc, mmap
+ may return an address that is later overwritten by the msan
+ library. Avoid this problem by forcing a call to malloc
+ here, before we ever call malloc.
+
+ This is only required for the memory sanitizer, so it's
+ unfortunate that we always run it. It should be possible
+ to remove this when we no longer care about versions of
+ clang before 3.8. The test for this is
+ misc/cgo/testsanitizers.
+
+ GCC works hard to eliminate a seemingly unnecessary call to
+ malloc, so we actually use the memory we allocate. */
+
+ setg_gcc = setg;
+ pbounds = (uintptr*)malloc(2 * sizeof(uintptr));
+ if (pbounds == NULL) {
+ fatalf("malloc failed: %s", strerror(errno));
+ }
+ _cgo_set_stacklo(g, pbounds);
+ free(pbounds);
+
+ if (x_cgo_inittls) {
+ x_cgo_inittls(tlsg, tlsbase);
+ }
+}
+
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ sigset_t ign, oset;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ sigfillset(&ign);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
+ ts->g->stackhi = size;
+ err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
+
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
+
+ if (err != 0) {
+ fatalf("pthread_create failed: %s", strerror(err));
+ }
+}
+
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ _cgo_tsan_acquire();
+ free(v);
+ _cgo_tsan_release();
+
+ crosscall1(ts.fn, setg_gcc, (void*)ts.g);
+ return nil;
+}
diff --git a/src/runtime/cgo/gcc_linux_arm64.c b/src/runtime/cgo/gcc_linux_arm64.c
new file mode 100644
index 0000000..0dcff2c
--- /dev/null
+++ b/src/runtime/cgo/gcc_linux_arm64.c
@@ -0,0 +1,87 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <pthread.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <stdlib.h>
+#include "libcgo.h"
+#include "libcgo_unix.h"
+
+static void *threadentry(void*);
+
+void (*x_cgo_inittls)(void **tlsg, void **tlsbase) __attribute__((common));
+static void (*setg_gcc)(void*);
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ sigset_t ign, oset;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ sigfillset(&ign);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
+ ts->g->stackhi = size;
+ err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
+
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
+
+ if (err != 0) {
+ fatalf("pthread_create failed: %s", strerror(err));
+ }
+}
+
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ crosscall1(ts.fn, setg_gcc, (void*)ts.g);
+ return nil;
+}
+
+void
+x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
+{
+ uintptr *pbounds;
+
+ /* The memory sanitizer distributed with versions of clang
+ before 3.8 has a bug: if you call mmap before malloc, mmap
+ may return an address that is later overwritten by the msan
+ library. Avoid this problem by forcing a call to malloc
+ here, before we ever call malloc.
+
+ This is only required for the memory sanitizer, so it's
+ unfortunate that we always run it. It should be possible
+ to remove this when we no longer care about versions of
+ clang before 3.8. The test for this is
+ misc/cgo/testsanitizers.
+
+ GCC works hard to eliminate a seemingly unnecessary call to
+ malloc, so we actually use the memory we allocate. */
+
+ setg_gcc = setg;
+ pbounds = (uintptr*)malloc(2 * sizeof(uintptr));
+ if (pbounds == NULL) {
+ fatalf("malloc failed: %s", strerror(errno));
+ }
+ _cgo_set_stacklo(g, pbounds);
+ free(pbounds);
+
+ if (x_cgo_inittls) {
+ x_cgo_inittls(tlsg, tlsbase);
+ }
+}
diff --git a/src/runtime/cgo/gcc_linux_ppc64x.S b/src/runtime/cgo/gcc_linux_ppc64x.S
new file mode 100644
index 0000000..745d232
--- /dev/null
+++ b/src/runtime/cgo/gcc_linux_ppc64x.S
@@ -0,0 +1,86 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build linux && (ppc64 || ppc64le)
+
+.file "gcc_linux_ppc64x.S"
+
+// Define a frame which has no argument space, but is compatible with
+// a call into a Go ABI. We allocate 32B to match FIXED_FRAME with
+// similar semantics, except we store the backchain pointer, not the
+// LR at offset 0. R2 is stored in the Go TOC save slot (offset 24).
+.set GPR_OFFSET, 32
+.set FPR_OFFSET, GPR_OFFSET + 18*8
+.set VR_OFFSET, FPR_OFFSET + 18*8
+.set FRAME_SIZE, VR_OFFSET + 12*16
+
+.macro FOR_EACH_GPR opcode r=14
+.ifge 31 - \r
+ \opcode \r, GPR_OFFSET + 8*(\r-14)(1)
+ FOR_EACH_GPR \opcode "(\r+1)"
+.endif
+.endm
+
+.macro FOR_EACH_FPR opcode fr=14
+.ifge 31 - \fr
+ \opcode \fr, FPR_OFFSET + 8*(\fr-14)(1)
+ FOR_EACH_FPR \opcode "(\fr+1)"
+.endif
+.endm
+
+.macro FOR_EACH_VR opcode vr=20
+.ifge 31 - \vr
+ li 0, VR_OFFSET + 16*(\vr-20)
+ \opcode \vr, 1, 0
+ FOR_EACH_VR \opcode "(\vr+1)"
+.endif
+.endm
+
+/*
+ * void crosscall_ppc64(void (*fn)(void), void *g)
+ *
+ * Calling into the gc tool chain, where all registers are caller save.
+ * Called from standard ppc64 C ABI, where r2, r14-r31, f14-f31 are
+ * callee-save, so they must be saved explicitly.
+ */
+.globl crosscall_ppc64
+crosscall_ppc64:
+ // Start with standard C stack frame layout and linkage
+ mflr %r0
+ std %r0, 16(%r1) // Save LR in caller's frame
+ mfcr %r0
+ std %r0, 8(%r1) // Save CR in caller's frame
+ stdu %r1, -FRAME_SIZE(%r1)
+ std %r2, 24(%r1)
+
+ FOR_EACH_GPR std
+ FOR_EACH_FPR stfd
+ FOR_EACH_VR stvx
+
+ // Set up Go ABI constant registers
+ li %r0, 0
+
+ // Restore g pointer (r30 in Go ABI, which may have been clobbered by C)
+ mr %r30, %r4
+
+ // Call fn
+ mr %r12, %r3
+ mtctr %r3
+ bctrl
+
+ FOR_EACH_GPR ld
+ FOR_EACH_FPR lfd
+ FOR_EACH_VR lvx
+
+ ld %r2, 24(%r1)
+ addi %r1, %r1, FRAME_SIZE
+ ld %r0, 16(%r1)
+ mtlr %r0
+ ld %r0, 8(%r1)
+ mtcr %r0
+ blr
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/src/runtime/cgo/gcc_linux_s390x.c b/src/runtime/cgo/gcc_linux_s390x.c
new file mode 100644
index 0000000..4b9f76c
--- /dev/null
+++ b/src/runtime/cgo/gcc_linux_s390x.c
@@ -0,0 +1,63 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <pthread.h>
+#include <string.h>
+#include <signal.h>
+#include "libcgo.h"
+#include "libcgo_unix.h"
+
+static void *threadentry(void*);
+
+void (*x_cgo_inittls)(void **tlsg, void **tlsbase);
+static void (*setg_gcc)(void*);
+
+void
+x_cgo_init(G *g, void (*setg)(void*), void **tlsbase)
+{
+ setg_gcc = setg;
+ _cgo_set_stacklo(g, NULL);
+}
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ sigset_t ign, oset;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ sigfillset(&ign);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
+ ts->g->stackhi = size;
+ err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
+
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
+
+ if (err != 0) {
+ fatalf("pthread_create failed: %s", strerror(err));
+ }
+}
+
+extern void crosscall_s390x(void (*fn)(void), void *g);
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ // Save g for this thread in C TLS
+ setg_gcc((void*)ts.g);
+
+ crosscall_s390x(ts.fn, (void*)ts.g);
+ return nil;
+}
diff --git a/src/runtime/cgo/gcc_loong64.S b/src/runtime/cgo/gcc_loong64.S
new file mode 100644
index 0000000..6b7668f
--- /dev/null
+++ b/src/runtime/cgo/gcc_loong64.S
@@ -0,0 +1,67 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+.file "gcc_loong64.S"
+
+/*
+ * void crosscall1(void (*fn)(void), void (*setg_gcc)(void *g), void *g)
+ *
+ * Calling into the gc tool chain, where all registers are caller save.
+ * Called from standard lp64d ABI, where $r1, $r3, $r23-$r30, and $f24-$f31
+ * are callee-save, so they must be saved explicitly, along with $r1 (LR).
+ */
+.globl crosscall1
+crosscall1:
+ addi.d $r3, $r3, -160
+ st.d $r1, $r3, 0
+ st.d $r23, $r3, 8
+ st.d $r24, $r3, 16
+ st.d $r25, $r3, 24
+ st.d $r26, $r3, 32
+ st.d $r27, $r3, 40
+ st.d $r28, $r3, 48
+ st.d $r29, $r3, 56
+ st.d $r30, $r3, 64
+ st.d $r2, $r3, 72
+ st.d $r22, $r3, 80
+ fst.d $f24, $r3, 88
+ fst.d $f25, $r3, 96
+ fst.d $f26, $r3, 104
+ fst.d $f27, $r3, 112
+ fst.d $f28, $r3, 120
+ fst.d $f29, $r3, 128
+ fst.d $f30, $r3, 136
+ fst.d $f31, $r3, 144
+
+ move $r18, $r4 // save R4
+ move $r19, $r6
+ jirl $r1, $r5, 0 // call setg_gcc (clobbers R4)
+ jirl $r1, $r18, 0 // call fn
+
+ ld.d $r23, $r3, 8
+ ld.d $r24, $r3, 16
+ ld.d $r25, $r3, 24
+ ld.d $r26, $r3, 32
+ ld.d $r27, $r3, 40
+ ld.d $r28, $r3, 48
+ ld.d $r29, $r3, 56
+ ld.d $r30, $r3, 64
+ ld.d $r2, $r3, 72
+ ld.d $r22, $r3, 80
+ fld.d $f24, $r3, 88
+ fld.d $f25, $r3, 96
+ fld.d $f26, $r3, 104
+ fld.d $f27, $r3, 112
+ fld.d $f28, $r3, 120
+ fld.d $f29, $r3, 128
+ fld.d $f30, $r3, 136
+ fld.d $f31, $r3, 144
+ ld.d $r1, $r3, 0
+ addi.d $r3, $r3, 160
+ jirl $r0, $r1, 0
+
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/src/runtime/cgo/gcc_mips64x.S b/src/runtime/cgo/gcc_mips64x.S
new file mode 100644
index 0000000..1629e47
--- /dev/null
+++ b/src/runtime/cgo/gcc_mips64x.S
@@ -0,0 +1,89 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build mips64 || mips64le
+
+.file "gcc_mips64x.S"
+
+/*
+ * void crosscall1(void (*fn)(void), void (*setg_gcc)(void *g), void *g)
+ *
+ * Calling into the gc tool chain, where all registers are caller save.
+ * Called from standard MIPS N64 ABI, where $16-$23, $28, $30, and $f24-$f31
+ * are callee-save, so they must be saved explicitly, along with $31 (LR).
+ */
+.globl crosscall1
+.set noat
+crosscall1:
+#ifndef __mips_soft_float
+ daddiu $29, $29, -160
+#else
+ daddiu $29, $29, -96 // For soft-float, no need to make room for FP registers
+#endif
+ sd $31, 0($29)
+ sd $16, 8($29)
+ sd $17, 16($29)
+ sd $18, 24($29)
+ sd $19, 32($29)
+ sd $20, 40($29)
+ sd $21, 48($29)
+ sd $22, 56($29)
+ sd $23, 64($29)
+ sd $28, 72($29)
+ sd $30, 80($29)
+#ifndef __mips_soft_float
+ sdc1 $f24, 88($29)
+ sdc1 $f25, 96($29)
+ sdc1 $f26, 104($29)
+ sdc1 $f27, 112($29)
+ sdc1 $f28, 120($29)
+ sdc1 $f29, 128($29)
+ sdc1 $f30, 136($29)
+ sdc1 $f31, 144($29)
+#endif
+
+ // prepare SB register = pc & 0xffffffff00000000
+ bal 1f
+1:
+ dsrl $28, $31, 32
+ dsll $28, $28, 32
+
+ move $20, $4 // save R4
+ move $1, $6
+ jalr $5 // call setg_gcc (clobbers R4)
+ jalr $20 // call fn
+
+ ld $16, 8($29)
+ ld $17, 16($29)
+ ld $18, 24($29)
+ ld $19, 32($29)
+ ld $20, 40($29)
+ ld $21, 48($29)
+ ld $22, 56($29)
+ ld $23, 64($29)
+ ld $28, 72($29)
+ ld $30, 80($29)
+#ifndef __mips_soft_float
+ ldc1 $f24, 88($29)
+ ldc1 $f25, 96($29)
+ ldc1 $f26, 104($29)
+ ldc1 $f27, 112($29)
+ ldc1 $f28, 120($29)
+ ldc1 $f29, 128($29)
+ ldc1 $f30, 136($29)
+ ldc1 $f31, 144($29)
+#endif
+ ld $31, 0($29)
+#ifndef __mips_soft_float
+ daddiu $29, $29, 160
+#else
+ daddiu $29, $29, 96
+#endif
+ jr $31
+
+.set at
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/src/runtime/cgo/gcc_mipsx.S b/src/runtime/cgo/gcc_mipsx.S
new file mode 100644
index 0000000..fb19c11
--- /dev/null
+++ b/src/runtime/cgo/gcc_mipsx.S
@@ -0,0 +1,77 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build mips || mipsle
+
+.file "gcc_mipsx.S"
+
+/*
+ * void crosscall1(void (*fn)(void), void (*setg_gcc)(void *g), void *g)
+ *
+ * Calling into the gc tool chain, where all registers are caller save.
+ * Called from standard MIPS O32 ABI, where $16-$23, $30, and $f20-$f31
+ * are callee-save, so they must be saved explicitly, along with $31 (LR).
+ */
+.globl crosscall1
+.set noat
+crosscall1:
+#ifndef __mips_soft_float
+ addiu $29, $29, -88
+#else
+ addiu $29, $29, -40 // For soft-float, no need to make room for FP registers
+#endif
+ sw $31, 0($29)
+ sw $16, 4($29)
+ sw $17, 8($29)
+ sw $18, 12($29)
+ sw $19, 16($29)
+ sw $20, 20($29)
+ sw $21, 24($29)
+ sw $22, 28($29)
+ sw $23, 32($29)
+ sw $30, 36($29)
+
+#ifndef __mips_soft_float
+ sdc1 $f20, 40($29)
+ sdc1 $f22, 48($29)
+ sdc1 $f24, 56($29)
+ sdc1 $f26, 64($29)
+ sdc1 $f28, 72($29)
+ sdc1 $f30, 80($29)
+#endif
+ move $20, $4 // save R4
+ move $4, $6
+ jalr $5 // call setg_gcc
+ jalr $20 // call fn
+
+ lw $16, 4($29)
+ lw $17, 8($29)
+ lw $18, 12($29)
+ lw $19, 16($29)
+ lw $20, 20($29)
+ lw $21, 24($29)
+ lw $22, 28($29)
+ lw $23, 32($29)
+ lw $30, 36($29)
+#ifndef __mips_soft_float
+ ldc1 $f20, 40($29)
+ ldc1 $f22, 48($29)
+ ldc1 $f24, 56($29)
+ ldc1 $f26, 64($29)
+ ldc1 $f28, 72($29)
+ ldc1 $f30, 80($29)
+#endif
+ lw $31, 0($29)
+#ifndef __mips_soft_float
+ addiu $29, $29, 88
+#else
+ addiu $29, $29, 40
+#endif
+ jr $31
+
+.set at
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/src/runtime/cgo/gcc_mmap.c b/src/runtime/cgo/gcc_mmap.c
new file mode 100644
index 0000000..eb710a0
--- /dev/null
+++ b/src/runtime/cgo/gcc_mmap.c
@@ -0,0 +1,39 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (linux && (amd64 || arm64 || loong64 || ppc64le)) || (freebsd && amd64)
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+
+#include "libcgo.h"
+
+uintptr_t
+x_cgo_mmap(void *addr, uintptr_t length, int32_t prot, int32_t flags, int32_t fd, uint32_t offset) {
+ void *p;
+
+ _cgo_tsan_acquire();
+ p = mmap(addr, length, prot, flags, fd, offset);
+ _cgo_tsan_release();
+ if (p == MAP_FAILED) {
+ /* This is what the Go code expects on failure. */
+ return (uintptr_t)errno;
+ }
+ return (uintptr_t)p;
+}
+
+void
+x_cgo_munmap(void *addr, uintptr_t length) {
+ int r;
+
+ _cgo_tsan_acquire();
+ r = munmap(addr, length);
+ _cgo_tsan_release();
+ if (r < 0) {
+ /* The Go runtime is not prepared for munmap to fail. */
+ abort();
+ }
+}
diff --git a/src/runtime/cgo/gcc_netbsd.c b/src/runtime/cgo/gcc_netbsd.c
new file mode 100644
index 0000000..16819ce
--- /dev/null
+++ b/src/runtime/cgo/gcc_netbsd.c
@@ -0,0 +1,73 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build netbsd && (386 || amd64 || arm || arm64)
+
+#include <sys/types.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include "libcgo.h"
+#include "libcgo_unix.h"
+
+static void* threadentry(void*);
+static void (*setg_gcc)(void*);
+
+void
+x_cgo_init(G *g, void (*setg)(void*))
+{
+ setg_gcc = setg;
+ _cgo_set_stacklo(g, NULL);
+}
+
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ sigset_t ign, oset;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ sigfillset(&ign);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
+ ts->g->stackhi = size;
+ err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
+
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
+
+ if (err != 0) {
+ fatalf("pthread_create failed: %s", strerror(err));
+ }
+}
+
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+ stack_t ss;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ // On NetBSD, a new thread inherits the signal stack of the
+ // creating thread. That confuses minit, so we remove that
+ // signal stack here before calling the regular mstart. It's
+ // a bit baroque to remove a signal stack here only to add one
+ // in minit, but it's a simple change that keeps NetBSD
+ // working like other OS's. At this point all signals are
+ // blocked, so there is no race.
+ memset(&ss, 0, sizeof ss);
+ ss.ss_flags = SS_DISABLE;
+ sigaltstack(&ss, nil);
+
+ crosscall1(ts.fn, setg_gcc, ts.g);
+ return nil;
+}
diff --git a/src/runtime/cgo/gcc_openbsd.c b/src/runtime/cgo/gcc_openbsd.c
new file mode 100644
index 0000000..3a4e545
--- /dev/null
+++ b/src/runtime/cgo/gcc_openbsd.c
@@ -0,0 +1,61 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build openbsd && (386 || arm || amd64 || arm64 || riscv64)
+
+#include <sys/types.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include "libcgo.h"
+#include "libcgo_unix.h"
+
+static void* threadentry(void*);
+static void (*setg_gcc)(void*);
+
+void
+x_cgo_init(G *g, void (*setg)(void*))
+{
+ setg_gcc = setg;
+ _cgo_set_stacklo(g, NULL);
+}
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ sigset_t ign, oset;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ sigfillset(&ign);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+
+ // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
+ ts->g->stackhi = size;
+ err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
+
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
+
+ if (err != 0) {
+ fatalf("pthread_create failed: %s", strerror(err));
+ }
+}
+
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ crosscall1(ts.fn, setg_gcc, ts.g);
+ return nil;
+}
diff --git a/src/runtime/cgo/gcc_ppc64x.c b/src/runtime/cgo/gcc_ppc64x.c
new file mode 100644
index 0000000..98a6549
--- /dev/null
+++ b/src/runtime/cgo/gcc_ppc64x.c
@@ -0,0 +1,67 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build ppc64 || ppc64le
+
+#include <pthread.h>
+#include <string.h>
+#include <signal.h>
+#include "libcgo.h"
+#include "libcgo_unix.h"
+
+static void *threadentry(void*);
+
+void (*x_cgo_inittls)(void **tlsg, void **tlsbase);
+static void (*setg_gcc)(void*);
+
+void
+x_cgo_init(G *g, void (*setg)(void*), void **tlsbase)
+{
+ setg_gcc = setg;
+ _cgo_set_stacklo(g, NULL);
+}
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ sigset_t ign, oset;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ sigfillset(&ign);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
+ ts->g->stackhi = size;
+ err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
+
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
+
+ if (err != 0) {
+ fatalf("pthread_create failed: %s", strerror(err));
+ }
+}
+
+extern void crosscall_ppc64(void (*fn)(void), void *g);
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ _cgo_tsan_acquire();
+ free(v);
+ _cgo_tsan_release();
+
+ // Save g for this thread in C TLS
+ setg_gcc((void*)ts.g);
+
+ crosscall_ppc64(ts.fn, (void*)ts.g);
+ return nil;
+}
diff --git a/src/runtime/cgo/gcc_riscv64.S b/src/runtime/cgo/gcc_riscv64.S
new file mode 100644
index 0000000..8f07649
--- /dev/null
+++ b/src/runtime/cgo/gcc_riscv64.S
@@ -0,0 +1,82 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+.file "gcc_riscv64.S"
+
+/*
+ * void crosscall1(void (*fn)(void), void (*setg_gcc)(void *g), void *g)
+ *
+ * Calling into the gc tool chain, where all registers are caller save.
+ * Called from standard RISCV ELF psABI, where x8-x9, x18-x27, f8-f9 and
+ * f18-f27 are callee-save, so they must be saved explicitly, along with
+ * x1 (LR).
+ */
+.globl crosscall1
+crosscall1:
+ sd x1, -200(sp)
+ addi sp, sp, -200
+ sd x8, 8(sp)
+ sd x9, 16(sp)
+ sd x18, 24(sp)
+ sd x19, 32(sp)
+ sd x20, 40(sp)
+ sd x21, 48(sp)
+ sd x22, 56(sp)
+ sd x23, 64(sp)
+ sd x24, 72(sp)
+ sd x25, 80(sp)
+ sd x26, 88(sp)
+ sd x27, 96(sp)
+ fsd f8, 104(sp)
+ fsd f9, 112(sp)
+ fsd f18, 120(sp)
+ fsd f19, 128(sp)
+ fsd f20, 136(sp)
+ fsd f21, 144(sp)
+ fsd f22, 152(sp)
+ fsd f23, 160(sp)
+ fsd f24, 168(sp)
+ fsd f25, 176(sp)
+ fsd f26, 184(sp)
+ fsd f27, 192(sp)
+
+ // a0 = *fn, a1 = *setg_gcc, a2 = *g
+ mv s1, a0
+ mv s0, a1
+ mv a0, a2
+ jalr ra, s0 // call setg_gcc (clobbers x30 aka g)
+ jalr ra, s1 // call fn
+
+ ld x1, 0(sp)
+ ld x8, 8(sp)
+ ld x9, 16(sp)
+ ld x18, 24(sp)
+ ld x19, 32(sp)
+ ld x20, 40(sp)
+ ld x21, 48(sp)
+ ld x22, 56(sp)
+ ld x23, 64(sp)
+ ld x24, 72(sp)
+ ld x25, 80(sp)
+ ld x26, 88(sp)
+ ld x27, 96(sp)
+ fld f8, 104(sp)
+ fld f9, 112(sp)
+ fld f18, 120(sp)
+ fld f19, 128(sp)
+ fld f20, 136(sp)
+ fld f21, 144(sp)
+ fld f22, 152(sp)
+ fld f23, 160(sp)
+ fld f24, 168(sp)
+ fld f25, 176(sp)
+ fld f26, 184(sp)
+ fld f27, 192(sp)
+ addi sp, sp, 200
+
+ jr ra
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/src/runtime/cgo/gcc_s390x.S b/src/runtime/cgo/gcc_s390x.S
new file mode 100644
index 0000000..8bd30fe
--- /dev/null
+++ b/src/runtime/cgo/gcc_s390x.S
@@ -0,0 +1,58 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+.file "gcc_s390x.S"
+
+/*
+ * void crosscall_s390x(void (*fn)(void), void *g)
+ *
+ * Calling into the go tool chain, where all registers are caller save.
+ * Called from standard s390x C ABI, where r6-r13, r15, and f8-f15 are
+ * callee-save, so they must be saved explicitly.
+ */
+.globl crosscall_s390x
+crosscall_s390x:
+ /* save r6-r15 in the register save area of the calling function */
+ stmg %r6, %r15, 48(%r15)
+
+ /* allocate 64 bytes of stack space to save f8-f15 */
+ lay %r15, -64(%r15)
+
+ /* save callee-saved floating point registers */
+ std %f8, 0(%r15)
+ std %f9, 8(%r15)
+ std %f10, 16(%r15)
+ std %f11, 24(%r15)
+ std %f12, 32(%r15)
+ std %f13, 40(%r15)
+ std %f14, 48(%r15)
+ std %f15, 56(%r15)
+
+ /* restore g pointer */
+ lgr %r13, %r3
+
+ /* call fn */
+ basr %r14, %r2
+
+ /* restore floating point registers */
+ ld %f8, 0(%r15)
+ ld %f9, 8(%r15)
+ ld %f10, 16(%r15)
+ ld %f11, 24(%r15)
+ ld %f12, 32(%r15)
+ ld %f13, 40(%r15)
+ ld %f14, 48(%r15)
+ ld %f15, 56(%r15)
+
+ /* de-allocate stack frame */
+ la %r15, 64(%r15)
+
+ /* restore general purpose registers */
+ lmg %r6, %r15, 48(%r15)
+
+ br %r14 /* restored by lmg */
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/src/runtime/cgo/gcc_setenv.c b/src/runtime/cgo/gcc_setenv.c
new file mode 100644
index 0000000..47caa4b
--- /dev/null
+++ b/src/runtime/cgo/gcc_setenv.c
@@ -0,0 +1,27 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build unix
+
+#include "libcgo.h"
+
+#include <stdlib.h>
+
+/* Stub for calling setenv */
+void
+x_cgo_setenv(char **arg)
+{
+ _cgo_tsan_acquire();
+ setenv(arg[0], arg[1], 1);
+ _cgo_tsan_release();
+}
+
+/* Stub for calling unsetenv */
+void
+x_cgo_unsetenv(char **arg)
+{
+ _cgo_tsan_acquire();
+ unsetenv(arg[0]);
+ _cgo_tsan_release();
+}
diff --git a/src/runtime/cgo/gcc_sigaction.c b/src/runtime/cgo/gcc_sigaction.c
new file mode 100644
index 0000000..374909b
--- /dev/null
+++ b/src/runtime/cgo/gcc_sigaction.c
@@ -0,0 +1,82 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build linux && (amd64 || arm64 || ppc64le)
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <signal.h>
+
+#include "libcgo.h"
+
+// go_sigaction_t is a C version of the sigactiont struct from
+// defs_linux_amd64.go. This definition — and its conversion to and from struct
+// sigaction — are specific to linux/amd64.
+typedef struct {
+ uintptr_t handler;
+ uint64_t flags;
+ uintptr_t restorer;
+ uint64_t mask;
+} go_sigaction_t;
+
+// SA_RESTORER is part of the kernel interface.
+// This is Linux i386/amd64 specific.
+#ifndef SA_RESTORER
+#define SA_RESTORER 0x4000000
+#endif
+
+int32_t
+x_cgo_sigaction(intptr_t signum, const go_sigaction_t *goact, go_sigaction_t *oldgoact) {
+ int32_t ret;
+ struct sigaction act;
+ struct sigaction oldact;
+ size_t i;
+
+ _cgo_tsan_acquire();
+
+ memset(&act, 0, sizeof act);
+ memset(&oldact, 0, sizeof oldact);
+
+ if (goact) {
+ if (goact->flags & SA_SIGINFO) {
+ act.sa_sigaction = (void(*)(int, siginfo_t*, void*))(goact->handler);
+ } else {
+ act.sa_handler = (void(*)(int))(goact->handler);
+ }
+ sigemptyset(&act.sa_mask);
+ for (i = 0; i < 8 * sizeof(goact->mask); i++) {
+ if (goact->mask & ((uint64_t)(1)<<i)) {
+ sigaddset(&act.sa_mask, (int)(i+1));
+ }
+ }
+ act.sa_flags = (int)(goact->flags & ~(uint64_t)SA_RESTORER);
+ }
+
+ ret = sigaction((int)signum, goact ? &act : NULL, oldgoact ? &oldact : NULL);
+ if (ret == -1) {
+ // runtime.rt_sigaction expects _cgo_sigaction to return errno on error.
+ _cgo_tsan_release();
+ return errno;
+ }
+
+ if (oldgoact) {
+ if (oldact.sa_flags & SA_SIGINFO) {
+ oldgoact->handler = (uintptr_t)(oldact.sa_sigaction);
+ } else {
+ oldgoact->handler = (uintptr_t)(oldact.sa_handler);
+ }
+ oldgoact->mask = 0;
+ for (i = 0; i < 8 * sizeof(oldgoact->mask); i++) {
+ if (sigismember(&oldact.sa_mask, (int)(i+1)) == 1) {
+ oldgoact->mask |= (uint64_t)(1)<<i;
+ }
+ }
+ oldgoact->flags = (uint64_t)oldact.sa_flags;
+ }
+
+ _cgo_tsan_release();
+ return ret;
+}
diff --git a/src/runtime/cgo/gcc_signal2_ios_arm64.c b/src/runtime/cgo/gcc_signal2_ios_arm64.c
new file mode 100644
index 0000000..f8cef54
--- /dev/null
+++ b/src/runtime/cgo/gcc_signal2_ios_arm64.c
@@ -0,0 +1,11 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build lldb
+
+// Used by gcc_signal_darwin_arm64.c when doing the test build during cgo.
+// We hope that for real binaries the definition provided by Go will take precedence
+// and the linker will drop this .o file altogether, which is why this definition
+// is all by itself in its own file.
+void __attribute__((weak)) xx_cgo_panicmem(void) {}
diff --git a/src/runtime/cgo/gcc_signal_ios_arm64.c b/src/runtime/cgo/gcc_signal_ios_arm64.c
new file mode 100644
index 0000000..87055e9
--- /dev/null
+++ b/src/runtime/cgo/gcc_signal_ios_arm64.c
@@ -0,0 +1,213 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Emulation of the Unix signal SIGSEGV.
+//
+// On iOS, Go tests and apps under development are run by lldb.
+// The debugger uses a task-level exception handler to intercept signals.
+// Despite having a 'handle' mechanism like gdb, lldb will not allow a
+// SIGSEGV to pass to the running program. For Go, this means we cannot
+// generate a panic, which cannot be recovered, and so tests fail.
+//
+// We work around this by registering a thread-level mach exception handler
+// and intercepting EXC_BAD_ACCESS. The kernel offers thread handlers a
+// chance to resolve exceptions before the task handler, so we can generate
+// the panic and avoid lldb's SIGSEGV handler.
+//
+// The dist tool enables this by build flag when testing.
+
+//go:build lldb
+
+#include <limits.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <mach/arm/thread_status.h>
+#include <mach/exception_types.h>
+#include <mach/mach.h>
+#include <mach/mach_init.h>
+#include <mach/mach_port.h>
+#include <mach/thread_act.h>
+#include <mach/thread_status.h>
+
+#include "libcgo.h"
+#include "libcgo_unix.h"
+
+void xx_cgo_panicmem(void);
+uintptr_t x_cgo_panicmem = (uintptr_t)xx_cgo_panicmem;
+
+static pthread_mutex_t mach_exception_handler_port_set_mu;
+static mach_port_t mach_exception_handler_port_set = MACH_PORT_NULL;
+
+kern_return_t
+catch_exception_raise(
+ mach_port_t exception_port,
+ mach_port_t thread,
+ mach_port_t task,
+ exception_type_t exception,
+ exception_data_t code_vector,
+ mach_msg_type_number_t code_count)
+{
+ kern_return_t ret;
+ arm_unified_thread_state_t thread_state;
+ mach_msg_type_number_t state_count = ARM_UNIFIED_THREAD_STATE_COUNT;
+
+ // Returning KERN_SUCCESS intercepts the exception.
+ //
+ // Returning KERN_FAILURE lets the exception fall through to the
+ // next handler, which is the standard signal emulation code
+ // registered on the task port.
+
+ if (exception != EXC_BAD_ACCESS) {
+ return KERN_FAILURE;
+ }
+
+ ret = thread_get_state(thread, ARM_UNIFIED_THREAD_STATE, (thread_state_t)&thread_state, &state_count);
+ if (ret) {
+ fprintf(stderr, "runtime/cgo: thread_get_state failed: %d\n", ret);
+ abort();
+ }
+
+ // Bounce call to sigpanic through asm that makes it look like
+ // we call sigpanic directly from the faulting code.
+#ifdef __arm64__
+ thread_state.ts_64.__x[1] = thread_state.ts_64.__lr;
+ thread_state.ts_64.__x[2] = thread_state.ts_64.__pc;
+ thread_state.ts_64.__pc = x_cgo_panicmem;
+#else
+ thread_state.ts_32.__r[1] = thread_state.ts_32.__lr;
+ thread_state.ts_32.__r[2] = thread_state.ts_32.__pc;
+ thread_state.ts_32.__pc = x_cgo_panicmem;
+#endif
+
+ if (0) {
+ // Useful debugging logic when panicmem is broken.
+ //
+ // Sends the first SIGSEGV and lets lldb catch the
+ // second one, avoiding a loop that locks up iOS
+ // devices requiring a hard reboot.
+ fprintf(stderr, "runtime/cgo: caught exc_bad_access\n");
+ fprintf(stderr, "__lr = %llx\n", thread_state.ts_64.__lr);
+ fprintf(stderr, "__pc = %llx\n", thread_state.ts_64.__pc);
+ static int pass1 = 0;
+ if (pass1) {
+ return KERN_FAILURE;
+ }
+ pass1 = 1;
+ }
+
+ ret = thread_set_state(thread, ARM_UNIFIED_THREAD_STATE, (thread_state_t)&thread_state, state_count);
+ if (ret) {
+ fprintf(stderr, "runtime/cgo: thread_set_state failed: %d\n", ret);
+ abort();
+ }
+
+ return KERN_SUCCESS;
+}
+
+void
+darwin_arm_init_thread_exception_port()
+{
+ // Called by each new OS thread to bind its EXC_BAD_ACCESS exception
+ // to mach_exception_handler_port_set.
+ int ret;
+ mach_port_t port = MACH_PORT_NULL;
+
+ ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
+ if (ret) {
+ fprintf(stderr, "runtime/cgo: mach_port_allocate failed: %d\n", ret);
+ abort();
+ }
+ ret = mach_port_insert_right(
+ mach_task_self(),
+ port,
+ port,
+ MACH_MSG_TYPE_MAKE_SEND);
+ if (ret) {
+ fprintf(stderr, "runtime/cgo: mach_port_insert_right failed: %d\n", ret);
+ abort();
+ }
+
+ ret = thread_set_exception_ports(
+ mach_thread_self(),
+ EXC_MASK_BAD_ACCESS,
+ port,
+ EXCEPTION_DEFAULT,
+ THREAD_STATE_NONE);
+ if (ret) {
+ fprintf(stderr, "runtime/cgo: thread_set_exception_ports failed: %d\n", ret);
+ abort();
+ }
+
+ ret = pthread_mutex_lock(&mach_exception_handler_port_set_mu);
+ if (ret) {
+ fprintf(stderr, "runtime/cgo: pthread_mutex_lock failed: %d\n", ret);
+ abort();
+ }
+ ret = mach_port_move_member(
+ mach_task_self(),
+ port,
+ mach_exception_handler_port_set);
+ if (ret) {
+ fprintf(stderr, "runtime/cgo: mach_port_move_member failed: %d\n", ret);
+ abort();
+ }
+ ret = pthread_mutex_unlock(&mach_exception_handler_port_set_mu);
+ if (ret) {
+ fprintf(stderr, "runtime/cgo: pthread_mutex_unlock failed: %d\n", ret);
+ abort();
+ }
+}
+
+static void*
+mach_exception_handler(void *port)
+{
+ // Calls catch_exception_raise.
+ extern boolean_t exc_server();
+ mach_msg_server(exc_server, 2048, (mach_port_t)port, 0);
+ abort(); // never returns
+}
+
+void
+darwin_arm_init_mach_exception_handler()
+{
+ pthread_mutex_init(&mach_exception_handler_port_set_mu, NULL);
+
+ // Called once per process to initialize a mach port server, listening
+ // for EXC_BAD_ACCESS thread exceptions.
+ int ret;
+ pthread_t thr = NULL;
+ pthread_attr_t attr;
+ sigset_t ign, oset;
+
+ ret = mach_port_allocate(
+ mach_task_self(),
+ MACH_PORT_RIGHT_PORT_SET,
+ &mach_exception_handler_port_set);
+ if (ret) {
+ fprintf(stderr, "runtime/cgo: mach_port_allocate failed for port_set: %d\n", ret);
+ abort();
+ }
+
+ // Block all signals to the exception handler thread
+ sigfillset(&ign);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+ // Start a thread to handle exceptions.
+ uintptr_t port_set = (uintptr_t)mach_exception_handler_port_set;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ ret = _cgo_try_pthread_create(&thr, &attr, mach_exception_handler, (void*)port_set);
+
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
+
+ if (ret) {
+ fprintf(stderr, "runtime/cgo: pthread_create failed: %d\n", ret);
+ abort();
+ }
+ pthread_attr_destroy(&attr);
+}
diff --git a/src/runtime/cgo/gcc_signal_ios_nolldb.c b/src/runtime/cgo/gcc_signal_ios_nolldb.c
new file mode 100644
index 0000000..9ddc37a
--- /dev/null
+++ b/src/runtime/cgo/gcc_signal_ios_nolldb.c
@@ -0,0 +1,10 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !lldb && ios && arm64
+
+#include <stdint.h>
+
+void darwin_arm_init_thread_exception_port() {}
+void darwin_arm_init_mach_exception_handler() {}
diff --git a/src/runtime/cgo/gcc_solaris_amd64.c b/src/runtime/cgo/gcc_solaris_amd64.c
new file mode 100644
index 0000000..9b106a6
--- /dev/null
+++ b/src/runtime/cgo/gcc_solaris_amd64.c
@@ -0,0 +1,83 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <pthread.h>
+#include <string.h>
+#include <signal.h>
+#include <ucontext.h>
+#include "libcgo.h"
+#include "libcgo_unix.h"
+
+static void* threadentry(void*);
+static void (*setg_gcc)(void*);
+
+void
+x_cgo_init(G *g, void (*setg)(void*))
+{
+ ucontext_t ctx;
+
+ setg_gcc = setg;
+ if (getcontext(&ctx) != 0)
+ perror("runtime/cgo: getcontext failed");
+ g->stacklo = (uintptr_t)ctx.uc_stack.ss_sp;
+
+ // Solaris processes report a tiny stack when run with "ulimit -s unlimited".
+ // Correct that as best we can: assume it's at least 1 MB.
+ // See golang.org/issue/12210.
+ if(ctx.uc_stack.ss_size < 1024*1024)
+ g->stacklo -= 1024*1024 - ctx.uc_stack.ss_size;
+
+ // Sanity check the results now, rather than getting a
+ // morestack on g0 crash.
+ if (g->stacklo >= g->stackhi) {
+ fatalf("bad stack bounds: lo=%p hi=%p", (void*)(g->stacklo), (void*)(g->stackhi));
+ }
+}
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ sigset_t ign, oset;
+ pthread_t p;
+ void *base;
+ size_t size;
+ int err;
+
+ sigfillset(&ign);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+ pthread_attr_init(&attr);
+
+ if (pthread_attr_getstack(&attr, &base, &size) != 0)
+ perror("runtime/cgo: pthread_attr_getstack failed");
+ if (size == 0) {
+ ts->g->stackhi = 2 << 20;
+ if (pthread_attr_setstack(&attr, NULL, ts->g->stackhi) != 0)
+ perror("runtime/cgo: pthread_attr_setstack failed");
+ } else {
+ ts->g->stackhi = size;
+ }
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
+
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
+
+ if (err != 0) {
+ fatalf("pthread_create failed: %s", strerror(err));
+ }
+}
+
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ crosscall1(ts.fn, setg_gcc, (void*)ts.g);
+ return nil;
+}
diff --git a/src/runtime/cgo/gcc_stack_darwin.c b/src/runtime/cgo/gcc_stack_darwin.c
new file mode 100644
index 0000000..0a9038e
--- /dev/null
+++ b/src/runtime/cgo/gcc_stack_darwin.c
@@ -0,0 +1,20 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <pthread.h>
+#include "libcgo.h"
+
+void
+x_cgo_getstackbound(uintptr bounds[2])
+{
+ void* addr;
+ size_t size;
+ pthread_t p;
+
+ p = pthread_self();
+ addr = pthread_get_stackaddr_np(p); // high address (!)
+ size = pthread_get_stacksize_np(p);
+ bounds[0] = (uintptr)addr - size;
+ bounds[1] = (uintptr)addr;
+}
diff --git a/src/runtime/cgo/gcc_stack_unix.c b/src/runtime/cgo/gcc_stack_unix.c
new file mode 100644
index 0000000..f3fead9
--- /dev/null
+++ b/src/runtime/cgo/gcc_stack_unix.c
@@ -0,0 +1,40 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build unix && !darwin
+
+#ifndef _GNU_SOURCE // pthread_getattr_np
+#define _GNU_SOURCE
+#endif
+
+#include <pthread.h>
+#include "libcgo.h"
+
+void
+x_cgo_getstackbound(uintptr bounds[2])
+{
+ pthread_attr_t attr;
+ void *addr;
+ size_t size;
+
+#if defined(__GLIBC__) || (defined(__sun) && !defined(__illumos__))
+ // pthread_getattr_np is a GNU extension supported in glibc.
+ // Solaris is not glibc but does support pthread_getattr_np
+ // (and the fallback doesn't work...). Illumos does not.
+ pthread_getattr_np(pthread_self(), &attr); // GNU extension
+ pthread_attr_getstack(&attr, &addr, &size); // low address
+#elif defined(__illumos__)
+ pthread_attr_init(&attr);
+ pthread_attr_get_np(pthread_self(), &attr);
+ pthread_attr_getstack(&attr, &addr, &size); // low address
+#else
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ addr = __builtin_frame_address(0) + 4096 - size;
+#endif
+ pthread_attr_destroy(&attr);
+
+ bounds[0] = (uintptr)addr;
+ bounds[1] = (uintptr)addr + size;
+}
diff --git a/src/runtime/cgo/gcc_stack_windows.c b/src/runtime/cgo/gcc_stack_windows.c
new file mode 100644
index 0000000..d798cc7
--- /dev/null
+++ b/src/runtime/cgo/gcc_stack_windows.c
@@ -0,0 +1,7 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "libcgo.h"
+
+void x_cgo_getstackbound(uintptr bounds[2]) {} // no-op for now
diff --git a/src/runtime/cgo/gcc_traceback.c b/src/runtime/cgo/gcc_traceback.c
new file mode 100644
index 0000000..c6643a1
--- /dev/null
+++ b/src/runtime/cgo/gcc_traceback.c
@@ -0,0 +1,46 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build darwin || linux
+
+#include <stdint.h>
+#include "libcgo.h"
+
+#ifndef __has_feature
+#define __has_feature(x) 0
+#endif
+
+#if __has_feature(memory_sanitizer)
+#include <sanitizer/msan_interface.h>
+#endif
+
+// Call the user's traceback function and then call sigtramp.
+// The runtime signal handler will jump to this code.
+// We do it this way so that the user's traceback function will be called
+// by a C function with proper unwind info.
+void
+x_cgo_callers(uintptr_t sig, void *info, void *context, void (*cgoTraceback)(struct cgoTracebackArg*), uintptr_t* cgoCallers, void (*sigtramp)(uintptr_t, void*, void*)) {
+ struct cgoTracebackArg arg;
+
+ arg.Context = 0;
+ arg.SigContext = (uintptr_t)(context);
+ arg.Buf = cgoCallers;
+ arg.Max = 32; // must match len(runtime.cgoCallers)
+
+#if __has_feature(memory_sanitizer)
+ // This function is called directly from the signal handler.
+ // The arguments are passed in registers, so whether msan
+ // considers cgoCallers to be initialized depends on whether
+ // it considers the appropriate register to be initialized.
+ // That can cause false reports in rare cases.
+ // Explicitly unpoison the memory to avoid that.
+ // See issue #47543 for more details.
+ __msan_unpoison(&arg, sizeof arg);
+#endif
+
+ _cgo_tsan_acquire();
+ (*cgoTraceback)(&arg);
+ _cgo_tsan_release();
+ sigtramp(sig, info, context);
+}
diff --git a/src/runtime/cgo/gcc_util.c b/src/runtime/cgo/gcc_util.c
new file mode 100644
index 0000000..3fcb48c
--- /dev/null
+++ b/src/runtime/cgo/gcc_util.c
@@ -0,0 +1,69 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "libcgo.h"
+
+/* Stub for creating a new thread */
+void
+x_cgo_thread_start(ThreadStart *arg)
+{
+ ThreadStart *ts;
+
+ /* Make our own copy that can persist after we return. */
+ _cgo_tsan_acquire();
+ ts = malloc(sizeof *ts);
+ _cgo_tsan_release();
+ if(ts == nil) {
+ fprintf(stderr, "runtime/cgo: out of memory in thread_start\n");
+ abort();
+ }
+ *ts = *arg;
+
+ _cgo_sys_thread_start(ts); /* OS-dependent half */
+}
+
+#ifndef CGO_TSAN
+void(* const _cgo_yield)() = NULL;
+#else
+
+#include <string.h>
+
+char x_cgo_yield_strncpy_src = 0;
+char x_cgo_yield_strncpy_dst = 0;
+size_t x_cgo_yield_strncpy_n = 0;
+
+/*
+Stub for allowing libc interceptors to execute.
+
+_cgo_yield is set to NULL if we do not expect libc interceptors to exist.
+*/
+static void
+x_cgo_yield()
+{
+ /*
+ The libc function(s) we call here must form a no-op and include at least one
+ call that triggers TSAN to process pending asynchronous signals.
+
+ sleep(0) would be fine, but it's not portable C (so it would need more header
+ guards).
+ free(NULL) has a fast-path special case in TSAN, so it doesn't
+ trigger signal delivery.
+ free(malloc(0)) would work (triggering the interceptors in malloc), but
+ it also runs a bunch of user-supplied malloc hooks.
+
+ So we choose strncpy(_, _, 0): it requires an extra header,
+ but it's standard and should be very efficient.
+
+ GCC 7 has an unfortunate habit of optimizing out strncpy calls (see
+ https://golang.org/issue/21196), so the arguments here need to be global
+ variables with external linkage in order to ensure that the call traps all the
+ way down into libc.
+ */
+ strncpy(&x_cgo_yield_strncpy_dst, &x_cgo_yield_strncpy_src,
+ x_cgo_yield_strncpy_n);
+}
+
+void(* const _cgo_yield)() = &x_cgo_yield;
+
+#endif /* GO_TSAN */
diff --git a/src/runtime/cgo/gcc_windows_386.c b/src/runtime/cgo/gcc_windows_386.c
new file mode 100644
index 0000000..983e14b
--- /dev/null
+++ b/src/runtime/cgo/gcc_windows_386.c
@@ -0,0 +1,53 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <process.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include "libcgo.h"
+#include "libcgo_windows.h"
+
+static void threadentry(void*);
+static void (*setg_gcc)(void*);
+static DWORD *tls_g;
+
+void
+x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
+{
+ setg_gcc = setg;
+ tls_g = (DWORD *)tlsg;
+}
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ _cgo_beginthread(threadentry, ts);
+}
+
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+static void
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ // minit queries stack bounds from the OS.
+
+ /*
+ * Set specific keys in thread local storage.
+ */
+ asm volatile (
+ "movl %0, %%fs:0(%1)\n" // MOVL tls0, 0(tls_g)(FS)
+ "movl %%fs:0(%1), %%eax\n" // MOVL 0(tls_g)(FS), tmp
+ "movl %2, 0(%%eax)\n" // MOVL g, 0(AX)
+ :: "r"(ts.tls), "r"(*tls_g), "r"(ts.g) : "%eax"
+ );
+
+ crosscall1(ts.fn, setg_gcc, ts.g);
+}
diff --git a/src/runtime/cgo/gcc_windows_amd64.c b/src/runtime/cgo/gcc_windows_amd64.c
new file mode 100644
index 0000000..e26887a
--- /dev/null
+++ b/src/runtime/cgo/gcc_windows_amd64.c
@@ -0,0 +1,52 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <process.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include "libcgo.h"
+#include "libcgo_windows.h"
+
+static void threadentry(void*);
+static void (*setg_gcc)(void*);
+static DWORD *tls_g;
+
+void
+x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
+{
+ setg_gcc = setg;
+ tls_g = (DWORD *)tlsg;
+}
+
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ _cgo_beginthread(threadentry, ts);
+}
+
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+static void
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ // minit queries stack bounds from the OS.
+
+ /*
+ * Set specific keys in thread local storage.
+ */
+ asm volatile (
+ "movq %0, %%gs:0(%1)\n" // MOVL tls0, 0(tls_g)(GS)
+ :: "r"(ts.tls), "r"(*tls_g)
+ );
+
+ crosscall1(ts.fn, setg_gcc, (void*)ts.g);
+}
diff --git a/src/runtime/cgo/gcc_windows_arm64.c b/src/runtime/cgo/gcc_windows_arm64.c
new file mode 100644
index 0000000..8f113cc
--- /dev/null
+++ b/src/runtime/cgo/gcc_windows_arm64.c
@@ -0,0 +1,40 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <process.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include "libcgo.h"
+#include "libcgo_windows.h"
+
+static void threadentry(void*);
+static void (*setg_gcc)(void*);
+
+void
+x_cgo_init(G *g, void (*setg)(void*))
+{
+ setg_gcc = setg;
+}
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ _cgo_beginthread(threadentry, ts);
+}
+
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+
+static void
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ crosscall1(ts.fn, setg_gcc, (void *)ts.g);
+}
diff --git a/src/runtime/cgo/handle.go b/src/runtime/cgo/handle.go
new file mode 100644
index 0000000..59b65da
--- /dev/null
+++ b/src/runtime/cgo/handle.go
@@ -0,0 +1,144 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgo
+
+import (
+ "sync"
+ "sync/atomic"
+)
+
+// Handle provides a way to pass values that contain Go pointers
+// (pointers to memory allocated by Go) between Go and C without
+// breaking the cgo pointer passing rules. A Handle is an integer
+// value that can represent any Go value. A Handle can be passed
+// through C and back to Go, and Go code can use the Handle to
+// retrieve the original Go value.
+//
+// The underlying type of Handle is guaranteed to fit in an integer type
+// that is large enough to hold the bit pattern of any pointer. The zero
+// value of a Handle is not valid, and thus is safe to use as a sentinel
+// in C APIs.
+//
+// For instance, on the Go side:
+//
+// package main
+//
+// /*
+// #include <stdint.h> // for uintptr_t
+//
+// extern void MyGoPrint(uintptr_t handle);
+// void myprint(uintptr_t handle);
+// */
+// import "C"
+// import "runtime/cgo"
+//
+// //export MyGoPrint
+// func MyGoPrint(handle C.uintptr_t) {
+// h := cgo.Handle(handle)
+// val := h.Value().(string)
+// println(val)
+// h.Delete()
+// }
+//
+// func main() {
+// val := "hello Go"
+// C.myprint(C.uintptr_t(cgo.NewHandle(val)))
+// // Output: hello Go
+// }
+//
+// and on the C side:
+//
+// #include <stdint.h> // for uintptr_t
+//
+// // A Go function
+// extern void MyGoPrint(uintptr_t handle);
+//
+// // A C function
+// void myprint(uintptr_t handle) {
+// MyGoPrint(handle);
+// }
+//
+// Some C functions accept a void* argument that points to an arbitrary
+// data value supplied by the caller. It is not safe to coerce a [cgo.Handle]
+// (an integer) to a Go [unsafe.Pointer], but instead we can pass the address
+// of the cgo.Handle to the void* parameter, as in this variant of the
+// previous example:
+//
+// package main
+//
+// /*
+// extern void MyGoPrint(void *context);
+// static inline void myprint(void *context) {
+// MyGoPrint(context);
+// }
+// */
+// import "C"
+// import (
+// "runtime/cgo"
+// "unsafe"
+// )
+//
+// //export MyGoPrint
+// func MyGoPrint(context unsafe.Pointer) {
+// h := *(*cgo.Handle)(context)
+// val := h.Value().(string)
+// println(val)
+// h.Delete()
+// }
+//
+// func main() {
+// val := "hello Go"
+// h := cgo.NewHandle(val)
+// C.myprint(unsafe.Pointer(&h))
+// // Output: hello Go
+// }
+type Handle uintptr
+
+// NewHandle returns a handle for a given value.
+//
+// The handle is valid until the program calls Delete on it. The handle
+// uses resources, and this package assumes that C code may hold on to
+// the handle, so a program must explicitly call Delete when the handle
+// is no longer needed.
+//
+// The intended use is to pass the returned handle to C code, which
+// passes it back to Go, which calls Value.
+func NewHandle(v any) Handle {
+ h := handleIdx.Add(1)
+ if h == 0 {
+ panic("runtime/cgo: ran out of handle space")
+ }
+
+ handles.Store(h, v)
+ return Handle(h)
+}
+
+// Value returns the associated Go value for a valid handle.
+//
+// The method panics if the handle is invalid.
+func (h Handle) Value() any {
+ v, ok := handles.Load(uintptr(h))
+ if !ok {
+ panic("runtime/cgo: misuse of an invalid Handle")
+ }
+ return v
+}
+
+// Delete invalidates a handle. This method should only be called once
+// the program no longer needs to pass the handle to C and the C code
+// no longer has a copy of the handle value.
+//
+// The method panics if the handle is invalid.
+func (h Handle) Delete() {
+ _, ok := handles.LoadAndDelete(uintptr(h))
+ if !ok {
+ panic("runtime/cgo: misuse of an invalid Handle")
+ }
+}
+
+var (
+ handles = sync.Map{} // map[Handle]interface{}
+ handleIdx atomic.Uintptr
+)
diff --git a/src/runtime/cgo/handle_test.go b/src/runtime/cgo/handle_test.go
new file mode 100644
index 0000000..b341c8e
--- /dev/null
+++ b/src/runtime/cgo/handle_test.go
@@ -0,0 +1,103 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgo
+
+import (
+ "reflect"
+ "testing"
+)
+
+func TestHandle(t *testing.T) {
+ v := 42
+
+ tests := []struct {
+ v1 any
+ v2 any
+ }{
+ {v1: v, v2: v},
+ {v1: &v, v2: &v},
+ {v1: nil, v2: nil},
+ }
+
+ for _, tt := range tests {
+ h1 := NewHandle(tt.v1)
+ h2 := NewHandle(tt.v2)
+
+ if uintptr(h1) == 0 || uintptr(h2) == 0 {
+ t.Fatalf("NewHandle returns zero")
+ }
+
+ if uintptr(h1) == uintptr(h2) {
+ t.Fatalf("Duplicated Go values should have different handles, but got equal")
+ }
+
+ h1v := h1.Value()
+ h2v := h2.Value()
+ if !reflect.DeepEqual(h1v, h2v) || !reflect.DeepEqual(h1v, tt.v1) {
+ t.Fatalf("Value of a Handle got wrong, got %+v %+v, want %+v", h1v, h2v, tt.v1)
+ }
+
+ h1.Delete()
+ h2.Delete()
+ }
+
+ siz := 0
+ handles.Range(func(k, v any) bool {
+ siz++
+ return true
+ })
+ if siz != 0 {
+ t.Fatalf("handles are not cleared, got %d, want %d", siz, 0)
+ }
+}
+
+func TestInvalidHandle(t *testing.T) {
+ t.Run("zero", func(t *testing.T) {
+ h := Handle(0)
+
+ defer func() {
+ if r := recover(); r != nil {
+ return
+ }
+ t.Fatalf("Delete of zero handle did not trigger a panic")
+ }()
+
+ h.Delete()
+ })
+
+ t.Run("invalid", func(t *testing.T) {
+ h := NewHandle(42)
+
+ defer func() {
+ if r := recover(); r != nil {
+ h.Delete()
+ return
+ }
+ t.Fatalf("Invalid handle did not trigger a panic")
+ }()
+
+ Handle(h + 1).Delete()
+ })
+}
+
+func BenchmarkHandle(b *testing.B) {
+ b.Run("non-concurrent", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ h := NewHandle(i)
+ _ = h.Value()
+ h.Delete()
+ }
+ })
+ b.Run("concurrent", func(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ var v int
+ for pb.Next() {
+ h := NewHandle(v)
+ _ = h.Value()
+ h.Delete()
+ }
+ })
+ })
+}
diff --git a/src/runtime/cgo/iscgo.go b/src/runtime/cgo/iscgo.go
new file mode 100644
index 0000000..e12d0f4
--- /dev/null
+++ b/src/runtime/cgo/iscgo.go
@@ -0,0 +1,17 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The runtime package contains an uninitialized definition
+// for runtime·iscgo. Override it to tell the runtime we're here.
+// There are various function pointers that should be set too,
+// but those depend on dynamic linker magic to get initialized
+// correctly, and sometimes they break. This variable is a
+// backup: it depends only on old C style static linking rules.
+
+package cgo
+
+import _ "unsafe" // for go:linkname
+
+//go:linkname _iscgo runtime.iscgo
+var _iscgo bool = true
diff --git a/src/runtime/cgo/libcgo.h b/src/runtime/cgo/libcgo.h
new file mode 100644
index 0000000..295c12c
--- /dev/null
+++ b/src/runtime/cgo/libcgo.h
@@ -0,0 +1,151 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#undef nil
+#define nil ((void*)0)
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+
+typedef uint32_t uint32;
+typedef uint64_t uint64;
+typedef uintptr_t uintptr;
+
+/*
+ * The beginning of the per-goroutine structure,
+ * as defined in ../pkg/runtime/runtime.h.
+ * Just enough to edit these two fields.
+ */
+typedef struct G G;
+struct G
+{
+ uintptr stacklo;
+ uintptr stackhi;
+};
+
+/*
+ * Arguments to the _cgo_thread_start call.
+ * Also known to ../pkg/runtime/runtime.h.
+ */
+typedef struct ThreadStart ThreadStart;
+struct ThreadStart
+{
+ G *g;
+ uintptr *tls;
+ void (*fn)(void);
+};
+
+/*
+ * Called by 5c/6c/8c world.
+ * Makes a local copy of the ThreadStart and
+ * calls _cgo_sys_thread_start(ts).
+ */
+extern void (*_cgo_thread_start)(ThreadStart *ts);
+
+/*
+ * Creates a new operating system thread without updating any Go state
+ * (OS dependent).
+ */
+extern void (*_cgo_sys_thread_create)(void* (*func)(void*), void* arg);
+
+/*
+ * Indicates whether a dummy pthread per-thread variable is allocated.
+ */
+extern uintptr_t *_cgo_pthread_key_created;
+
+/*
+ * Creates the new operating system thread (OS, arch dependent).
+ */
+void _cgo_sys_thread_start(ThreadStart *ts);
+
+/*
+ * Waits for the Go runtime to be initialized (OS dependent).
+ * If runtime.SetCgoTraceback is used to set a context function,
+ * calls the context function and returns the context value.
+ */
+uintptr_t _cgo_wait_runtime_init_done(void);
+
+/*
+ * Get the low and high boundaries of the stack.
+ */
+void x_cgo_getstackbound(uintptr bounds[2]);
+
+/*
+ * Prints error then calls abort. For linux and android.
+ */
+void fatalf(const char* format, ...);
+
+/*
+ * Registers the current mach thread port for EXC_BAD_ACCESS processing.
+ */
+void darwin_arm_init_thread_exception_port(void);
+
+/*
+ * Starts a mach message server processing EXC_BAD_ACCESS.
+ */
+void darwin_arm_init_mach_exception_handler(void);
+
+/*
+ * The cgo context function. See runtime.SetCgoTraceback.
+ */
+struct context_arg {
+ uintptr_t Context;
+};
+extern void (*(_cgo_get_context_function(void)))(struct context_arg*);
+
+/*
+ * The argument for the cgo traceback callback. See runtime.SetCgoTraceback.
+ */
+struct cgoTracebackArg {
+ uintptr_t Context;
+ uintptr_t SigContext;
+ uintptr_t* Buf;
+ uintptr_t Max;
+};
+
+/*
+ * TSAN support. This is only useful when building with
+ * CGO_CFLAGS="-fsanitize=thread" CGO_LDFLAGS="-fsanitize=thread" go install
+ */
+#undef CGO_TSAN
+#if defined(__has_feature)
+# if __has_feature(thread_sanitizer)
+# define CGO_TSAN
+# endif
+#elif defined(__SANITIZE_THREAD__)
+# define CGO_TSAN
+#endif
+
+#ifdef CGO_TSAN
+
+// These must match the definitions in yesTsanProlog in cmd/cgo/out.go.
+// In general we should call _cgo_tsan_acquire when we enter C code,
+// and call _cgo_tsan_release when we return to Go code.
+// This is only necessary when calling code that might be instrumented
+// by TSAN, which mostly means system library calls that TSAN intercepts.
+// See the comment in cmd/cgo/out.go for more details.
+
+long long _cgo_sync __attribute__ ((common));
+
+extern void __tsan_acquire(void*);
+extern void __tsan_release(void*);
+
+__attribute__ ((unused))
+static void _cgo_tsan_acquire() {
+ __tsan_acquire(&_cgo_sync);
+}
+
+__attribute__ ((unused))
+static void _cgo_tsan_release() {
+ __tsan_release(&_cgo_sync);
+}
+
+#else // !defined(CGO_TSAN)
+
+#define _cgo_tsan_acquire()
+#define _cgo_tsan_release()
+
+#endif // !defined(CGO_TSAN)
diff --git a/src/runtime/cgo/libcgo_unix.h b/src/runtime/cgo/libcgo_unix.h
new file mode 100644
index 0000000..b8f8d30
--- /dev/null
+++ b/src/runtime/cgo/libcgo_unix.h
@@ -0,0 +1,20 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * Initialize g->stacklo.
+ */
+extern void _cgo_set_stacklo(G *, uintptr *);
+
+/*
+ * Call pthread_create, retrying on EAGAIN.
+ */
+extern int _cgo_try_pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*);
+
+/*
+ * Same as _cgo_try_pthread_create, but passing on the pthread_create function.
+ * Only defined on OpenBSD.
+ */
+extern int _cgo_openbsd_try_pthread_create(int (*)(pthread_t*, const pthread_attr_t*, void *(*pfn)(void*), void*),
+ pthread_t*, const pthread_attr_t*, void* (*)(void*), void* arg);
diff --git a/src/runtime/cgo/libcgo_windows.h b/src/runtime/cgo/libcgo_windows.h
new file mode 100644
index 0000000..33d7637
--- /dev/null
+++ b/src/runtime/cgo/libcgo_windows.h
@@ -0,0 +1,6 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Call _beginthread, aborting on failure.
+void _cgo_beginthread(void (*func)(void*), void* arg);
diff --git a/src/runtime/cgo/linux.go b/src/runtime/cgo/linux.go
new file mode 100644
index 0000000..1d6fe03
--- /dev/null
+++ b/src/runtime/cgo/linux.go
@@ -0,0 +1,74 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Linux system call wrappers that provide POSIX semantics through the
+// corresponding cgo->libc (nptl) wrappers for various system calls.
+
+//go:build linux
+
+package cgo
+
+import "unsafe"
+
+// Each of the following entries is needed to ensure that the
+// syscall.syscall_linux code can conditionally call these
+// function pointers:
+//
+// 1. find the C-defined function start
+// 2. force the local byte alias to be mapped to that location
+// 3. map the Go pointer to the function to the syscall package
+
+//go:cgo_import_static _cgo_libc_setegid
+//go:linkname _cgo_libc_setegid _cgo_libc_setegid
+//go:linkname cgo_libc_setegid syscall.cgo_libc_setegid
+var _cgo_libc_setegid byte
+var cgo_libc_setegid = unsafe.Pointer(&_cgo_libc_setegid)
+
+//go:cgo_import_static _cgo_libc_seteuid
+//go:linkname _cgo_libc_seteuid _cgo_libc_seteuid
+//go:linkname cgo_libc_seteuid syscall.cgo_libc_seteuid
+var _cgo_libc_seteuid byte
+var cgo_libc_seteuid = unsafe.Pointer(&_cgo_libc_seteuid)
+
+//go:cgo_import_static _cgo_libc_setregid
+//go:linkname _cgo_libc_setregid _cgo_libc_setregid
+//go:linkname cgo_libc_setregid syscall.cgo_libc_setregid
+var _cgo_libc_setregid byte
+var cgo_libc_setregid = unsafe.Pointer(&_cgo_libc_setregid)
+
+//go:cgo_import_static _cgo_libc_setresgid
+//go:linkname _cgo_libc_setresgid _cgo_libc_setresgid
+//go:linkname cgo_libc_setresgid syscall.cgo_libc_setresgid
+var _cgo_libc_setresgid byte
+var cgo_libc_setresgid = unsafe.Pointer(&_cgo_libc_setresgid)
+
+//go:cgo_import_static _cgo_libc_setresuid
+//go:linkname _cgo_libc_setresuid _cgo_libc_setresuid
+//go:linkname cgo_libc_setresuid syscall.cgo_libc_setresuid
+var _cgo_libc_setresuid byte
+var cgo_libc_setresuid = unsafe.Pointer(&_cgo_libc_setresuid)
+
+//go:cgo_import_static _cgo_libc_setreuid
+//go:linkname _cgo_libc_setreuid _cgo_libc_setreuid
+//go:linkname cgo_libc_setreuid syscall.cgo_libc_setreuid
+var _cgo_libc_setreuid byte
+var cgo_libc_setreuid = unsafe.Pointer(&_cgo_libc_setreuid)
+
+//go:cgo_import_static _cgo_libc_setgroups
+//go:linkname _cgo_libc_setgroups _cgo_libc_setgroups
+//go:linkname cgo_libc_setgroups syscall.cgo_libc_setgroups
+var _cgo_libc_setgroups byte
+var cgo_libc_setgroups = unsafe.Pointer(&_cgo_libc_setgroups)
+
+//go:cgo_import_static _cgo_libc_setgid
+//go:linkname _cgo_libc_setgid _cgo_libc_setgid
+//go:linkname cgo_libc_setgid syscall.cgo_libc_setgid
+var _cgo_libc_setgid byte
+var cgo_libc_setgid = unsafe.Pointer(&_cgo_libc_setgid)
+
+//go:cgo_import_static _cgo_libc_setuid
+//go:linkname _cgo_libc_setuid _cgo_libc_setuid
+//go:linkname cgo_libc_setuid syscall.cgo_libc_setuid
+var _cgo_libc_setuid byte
+var cgo_libc_setuid = unsafe.Pointer(&_cgo_libc_setuid)
diff --git a/src/runtime/cgo/linux_syscall.c b/src/runtime/cgo/linux_syscall.c
new file mode 100644
index 0000000..0ea2da7
--- /dev/null
+++ b/src/runtime/cgo/linux_syscall.c
@@ -0,0 +1,85 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build linux
+
+#ifndef _GNU_SOURCE // setres[ug]id() API.
+#define _GNU_SOURCE
+#endif
+
+#include <grp.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include "libcgo.h"
+
+/*
+ * Assumed POSIX compliant libc system call wrappers. For linux, the
+ * glibc/nptl/setxid mechanism ensures that POSIX semantics are
+ * honored for all pthreads (by default), and this in turn with cgo
+ * ensures that all Go threads launched with cgo are kept in sync for
+ * these function calls.
+ */
+
+// argset_t matches runtime/cgocall.go:argset.
+typedef struct {
+ uintptr_t* args;
+ uintptr_t retval;
+} argset_t;
+
+// libc backed posix-compliant syscalls.
+
+#define SET_RETVAL(fn) \
+ uintptr_t ret = (uintptr_t) fn ; \
+ if (ret == (uintptr_t) -1) { \
+ x->retval = (uintptr_t) errno; \
+ } else \
+ x->retval = ret
+
+void
+_cgo_libc_setegid(argset_t* x) {
+ SET_RETVAL(setegid((gid_t) x->args[0]));
+}
+
+void
+_cgo_libc_seteuid(argset_t* x) {
+ SET_RETVAL(seteuid((uid_t) x->args[0]));
+}
+
+void
+_cgo_libc_setgid(argset_t* x) {
+ SET_RETVAL(setgid((gid_t) x->args[0]));
+}
+
+void
+_cgo_libc_setgroups(argset_t* x) {
+ SET_RETVAL(setgroups((size_t) x->args[0], (const gid_t *) x->args[1]));
+}
+
+void
+_cgo_libc_setregid(argset_t* x) {
+ SET_RETVAL(setregid((gid_t) x->args[0], (gid_t) x->args[1]));
+}
+
+void
+_cgo_libc_setresgid(argset_t* x) {
+ SET_RETVAL(setresgid((gid_t) x->args[0], (gid_t) x->args[1],
+ (gid_t) x->args[2]));
+}
+
+void
+_cgo_libc_setresuid(argset_t* x) {
+ SET_RETVAL(setresuid((uid_t) x->args[0], (uid_t) x->args[1],
+ (uid_t) x->args[2]));
+}
+
+void
+_cgo_libc_setreuid(argset_t* x) {
+ SET_RETVAL(setreuid((uid_t) x->args[0], (uid_t) x->args[1]));
+}
+
+void
+_cgo_libc_setuid(argset_t* x) {
+ SET_RETVAL(setuid((uid_t) x->args[0]));
+}
diff --git a/src/runtime/cgo/mmap.go b/src/runtime/cgo/mmap.go
new file mode 100644
index 0000000..144af2b
--- /dev/null
+++ b/src/runtime/cgo/mmap.go
@@ -0,0 +1,31 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (linux && (amd64 || arm64 || loong64)) || (freebsd && amd64)
+
+package cgo
+
+// Import "unsafe" because we use go:linkname.
+import _ "unsafe"
+
+// When using cgo, call the C library for mmap, so that we call into
+// any sanitizer interceptors. This supports using the memory
+// sanitizer with Go programs. The memory sanitizer only applies to
+// C/C++ code; this permits that code to see the Go code as normal
+// program addresses that have been initialized.
+
+// To support interceptors that look for both mmap and munmap,
+// also call the C library for munmap.
+
+//go:cgo_import_static x_cgo_mmap
+//go:linkname x_cgo_mmap x_cgo_mmap
+//go:linkname _cgo_mmap _cgo_mmap
+var x_cgo_mmap byte
+var _cgo_mmap = &x_cgo_mmap
+
+//go:cgo_import_static x_cgo_munmap
+//go:linkname x_cgo_munmap x_cgo_munmap
+//go:linkname _cgo_munmap _cgo_munmap
+var x_cgo_munmap byte
+var _cgo_munmap = &x_cgo_munmap
diff --git a/src/runtime/cgo/netbsd.go b/src/runtime/cgo/netbsd.go
new file mode 100644
index 0000000..8a8018b
--- /dev/null
+++ b/src/runtime/cgo/netbsd.go
@@ -0,0 +1,21 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build netbsd
+
+package cgo
+
+import _ "unsafe" // for go:linkname
+
+// Supply environ and __progname, because we don't
+// link against the standard NetBSD crt0.o and the
+// libc dynamic library needs them.
+
+//go:linkname _environ environ
+//go:linkname _progname __progname
+//go:linkname ___ps_strings __ps_strings
+
+var _environ uintptr
+var _progname uintptr
+var ___ps_strings uintptr
diff --git a/src/runtime/cgo/openbsd.go b/src/runtime/cgo/openbsd.go
new file mode 100644
index 0000000..26b62fb
--- /dev/null
+++ b/src/runtime/cgo/openbsd.go
@@ -0,0 +1,21 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build openbsd
+
+package cgo
+
+import _ "unsafe" // for go:linkname
+
+// Supply __guard_local because we don't link against the standard
+// OpenBSD crt0.o and the libc dynamic library needs it.
+
+//go:linkname _guard_local __guard_local
+
+var _guard_local uintptr
+
+// This is normally marked as hidden and placed in the
+// .openbsd.randomdata section.
+//
+//go:cgo_export_dynamic __guard_local __guard_local
diff --git a/src/runtime/cgo/setenv.go b/src/runtime/cgo/setenv.go
new file mode 100644
index 0000000..2247cb2
--- /dev/null
+++ b/src/runtime/cgo/setenv.go
@@ -0,0 +1,21 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build unix
+
+package cgo
+
+import _ "unsafe" // for go:linkname
+
+//go:cgo_import_static x_cgo_setenv
+//go:linkname x_cgo_setenv x_cgo_setenv
+//go:linkname _cgo_setenv runtime._cgo_setenv
+var x_cgo_setenv byte
+var _cgo_setenv = &x_cgo_setenv
+
+//go:cgo_import_static x_cgo_unsetenv
+//go:linkname x_cgo_unsetenv x_cgo_unsetenv
+//go:linkname _cgo_unsetenv runtime._cgo_unsetenv
+var x_cgo_unsetenv byte
+var _cgo_unsetenv = &x_cgo_unsetenv
diff --git a/src/runtime/cgo/sigaction.go b/src/runtime/cgo/sigaction.go
new file mode 100644
index 0000000..dc714f7
--- /dev/null
+++ b/src/runtime/cgo/sigaction.go
@@ -0,0 +1,22 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (linux && amd64) || (freebsd && amd64) || (linux && arm64) || (linux && ppc64le)
+
+package cgo
+
+// Import "unsafe" because we use go:linkname.
+import _ "unsafe"
+
+// When using cgo, call the C library for sigaction, so that we call into
+// any sanitizer interceptors. This supports using the sanitizers
+// with Go programs. The thread and memory sanitizers only apply to
+// C/C++ code; this permits that code to see the Go runtime's existing signal
+// handlers when registering new signal handlers for the process.
+
+//go:cgo_import_static x_cgo_sigaction
+//go:linkname x_cgo_sigaction x_cgo_sigaction
+//go:linkname _cgo_sigaction _cgo_sigaction
+var x_cgo_sigaction byte
+var _cgo_sigaction = &x_cgo_sigaction
diff --git a/src/runtime/cgo/signal_ios_arm64.go b/src/runtime/cgo/signal_ios_arm64.go
new file mode 100644
index 0000000..3425c44
--- /dev/null
+++ b/src/runtime/cgo/signal_ios_arm64.go
@@ -0,0 +1,10 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgo
+
+import _ "unsafe"
+
+//go:cgo_export_static xx_cgo_panicmem xx_cgo_panicmem
+func xx_cgo_panicmem()
diff --git a/src/runtime/cgo/signal_ios_arm64.s b/src/runtime/cgo/signal_ios_arm64.s
new file mode 100644
index 0000000..1ae00d1
--- /dev/null
+++ b/src/runtime/cgo/signal_ios_arm64.s
@@ -0,0 +1,56 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// xx_cgo_panicmem is the entrypoint for SIGSEGV as intercepted via a
+// mach thread port as EXC_BAD_ACCESS. As the segfault may have happened
+// in C code, we first need to load_g then call xx_cgo_panicmem.
+//
+// R1 - LR at moment of fault
+// R2 - PC at moment of fault
+TEXT xx_cgo_panicmem(SB),NOSPLIT|NOFRAME,$0
+ // If in external C code, we need to load the g register.
+ BL runtime·load_g(SB)
+ CMP $0, g
+ BNE ongothread
+
+ // On a foreign thread.
+ // TODO(crawshaw): call badsignal
+ MOVD.W $0, -16(RSP)
+ MOVW $139, R1
+ MOVW R1, 8(RSP)
+ B runtime·exit(SB)
+
+ongothread:
+ // Trigger a SIGSEGV panic.
+ //
+ // The goal is to arrange the stack so it looks like the runtime
+ // function sigpanic was called from the PC that faulted. It has
+ // to be sigpanic, as the stack unwinding code in traceback.go
+ // looks explicitly for it.
+ //
+ // To do this we call into runtime·setsigsegv, which sets the
+ // appropriate state inside the g object. We give it the faulting
+ // PC on the stack, then put it in the LR before calling sigpanic.
+
+ // Build a 32-byte stack frame for us for this call.
+ // Saved LR (none available) is at the bottom,
+ // then the PC argument for setsigsegv,
+ // then a copy of the LR for us to restore.
+ MOVD.W $0, -32(RSP)
+ MOVD R1, 8(RSP)
+ MOVD R2, 16(RSP)
+ BL runtime·setsigsegv(SB)
+ MOVD 8(RSP), R1
+ MOVD 16(RSP), R2
+
+ // Build a 16-byte stack frame for the simulated
+ // call to sigpanic, by taking 16 bytes away from the
+ // 32-byte stack frame above.
+ // The saved LR in this frame is the LR at time of fault,
+ // and the LR on entry to sigpanic is the PC at time of fault.
+ MOVD.W R1, 16(RSP)
+ MOVD R2, R30
+ B runtime·sigpanic(SB)