Initial commit: Go 1.23 release state
This commit is contained in:
99
src/runtime/cgo/abi_amd64.h
Normal file
99
src/runtime/cgo/abi_amd64.h
Normal file
@@ -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
|
||||
43
src/runtime/cgo/abi_arm64.h
Normal file
43
src/runtime/cgo/abi_arm64.h
Normal file
@@ -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)
|
||||
|
||||
60
src/runtime/cgo/abi_loong64.h
Normal file
60
src/runtime/cgo/abi_loong64.h
Normal file
@@ -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
|
||||
195
src/runtime/cgo/abi_ppc64x.h
Normal file
195
src/runtime/cgo/abi_ppc64x.h
Normal file
@@ -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
|
||||
42
src/runtime/cgo/asm_386.s
Normal file
42
src/runtime/cgo/asm_386.s
Normal file
@@ -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
|
||||
47
src/runtime/cgo/asm_amd64.s
Normal file
47
src/runtime/cgo/asm_amd64.s
Normal file
@@ -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
|
||||
69
src/runtime/cgo/asm_arm.s
Normal file
69
src/runtime/cgo/asm_arm.s
Normal file
@@ -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
|
||||
50
src/runtime/cgo/asm_arm64.s
Normal file
50
src/runtime/cgo/asm_arm64.s
Normal file
@@ -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
|
||||
53
src/runtime/cgo/asm_loong64.s
Normal file
53
src/runtime/cgo/asm_loong64.s
Normal file
@@ -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
|
||||
95
src/runtime/cgo/asm_mips64x.s
Normal file
95
src/runtime/cgo/asm_mips64x.s
Normal file
@@ -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
|
||||
88
src/runtime/cgo/asm_mipsx.s
Normal file
88
src/runtime/cgo/asm_mipsx.s
Normal file
@@ -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
|
||||
70
src/runtime/cgo/asm_ppc64x.s
Normal file
70
src/runtime/cgo/asm_ppc64x.s
Normal file
@@ -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
|
||||
91
src/runtime/cgo/asm_riscv64.s
Normal file
91
src/runtime/cgo/asm_riscv64.s
Normal file
@@ -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
|
||||
68
src/runtime/cgo/asm_s390x.s
Normal file
68
src/runtime/cgo/asm_s390x.s
Normal file
@@ -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
|
||||
|
||||
11
src/runtime/cgo/asm_wasm.s
Normal file
11
src/runtime/cgo/asm_wasm.s
Normal file
@@ -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
|
||||
152
src/runtime/cgo/callbacks.go
Normal file
152
src/runtime/cgo/callbacks.go
Normal file
@@ -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
|
||||
12
src/runtime/cgo/callbacks_aix.go
Normal file
12
src/runtime/cgo/callbacks_aix.go
Normal file
@@ -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
|
||||
17
src/runtime/cgo/callbacks_traceback.go
Normal file
17
src/runtime/cgo/callbacks_traceback.go
Normal file
@@ -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
|
||||
40
src/runtime/cgo/cgo.go
Normal file
40
src/runtime/cgo/cgo.go
Normal file
@@ -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
|
||||
}
|
||||
19
src/runtime/cgo/dragonfly.go
Normal file
19
src/runtime/cgo/dragonfly.go
Normal file
@@ -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
|
||||
22
src/runtime/cgo/freebsd.go
Normal file
22
src/runtime/cgo/freebsd.go
Normal file
@@ -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
|
||||
48
src/runtime/cgo/gcc_386.S
Normal file
48
src/runtime/cgo/gcc_386.S
Normal file
@@ -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
|
||||
132
src/runtime/cgo/gcc_aix_ppc64.S
Normal file
132
src/runtime/cgo/gcc_aix_ppc64.S
Normal file
@@ -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
|
||||
35
src/runtime/cgo/gcc_aix_ppc64.c
Normal file
35
src/runtime/cgo/gcc_aix_ppc64.c
Normal file
@@ -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();
|
||||
}
|
||||
55
src/runtime/cgo/gcc_amd64.S
Normal file
55
src/runtime/cgo/gcc_amd64.S
Normal file
@@ -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
|
||||
90
src/runtime/cgo/gcc_android.c
Normal file
90
src/runtime/cgo/gcc_android.c
Normal file
@@ -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;
|
||||
31
src/runtime/cgo/gcc_arm.S
Normal file
31
src/runtime/cgo/gcc_arm.S
Normal file
@@ -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
|
||||
84
src/runtime/cgo/gcc_arm64.S
Normal file
84
src/runtime/cgo/gcc_arm64.S
Normal file
@@ -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
|
||||
20
src/runtime/cgo/gcc_context.c
Normal file
20
src/runtime/cgo/gcc_context.c
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
60
src/runtime/cgo/gcc_darwin_amd64.c
Normal file
60
src/runtime/cgo/gcc_darwin_amd64.c
Normal file
@@ -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;
|
||||
}
|
||||
139
src/runtime/cgo/gcc_darwin_arm64.c
Normal file
139
src/runtime/cgo/gcc_darwin_arm64.c
Normal file
@@ -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
|
||||
}
|
||||
60
src/runtime/cgo/gcc_dragonfly_amd64.c
Normal file
60
src/runtime/cgo/gcc_dragonfly_amd64.c
Normal file
@@ -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;
|
||||
}
|
||||
23
src/runtime/cgo/gcc_fatalf.c
Normal file
23
src/runtime/cgo/gcc_fatalf.c
Normal file
@@ -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();
|
||||
}
|
||||
71
src/runtime/cgo/gcc_freebsd.c
Normal file
71
src/runtime/cgo/gcc_freebsd.c
Normal file
@@ -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;
|
||||
}
|
||||
71
src/runtime/cgo/gcc_freebsd_amd64.c
Normal file
71
src/runtime/cgo/gcc_freebsd_amd64.c
Normal file
@@ -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;
|
||||
}
|
||||
80
src/runtime/cgo/gcc_freebsd_sigaction.c
Normal file
80
src/runtime/cgo/gcc_freebsd_sigaction.c
Normal file
@@ -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;
|
||||
}
|
||||
178
src/runtime/cgo/gcc_libinit.c
Normal file
178
src/runtime/cgo/gcc_libinit.c
Normal file
@@ -0,0 +1,178 @@
|
||||
// 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
|
||||
|
||||
// When cross-compiling with clang to linux/armv5, atomics are emulated
|
||||
// and cause a compiler warning. This results in a build failure since
|
||||
// cgo uses -Werror. See #65290.
|
||||
#pragma GCC diagnostic ignored "-Wpragmas"
|
||||
#pragma GCC diagnostic ignored "-Wunknown-warning-option"
|
||||
#pragma GCC diagnostic ignored "-Watomic-alignment"
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
158
src/runtime/cgo/gcc_libinit_windows.c
Normal file
158
src/runtime/cgo/gcc_libinit_windows.c
Normal file
@@ -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();
|
||||
}
|
||||
66
src/runtime/cgo/gcc_linux.c
Normal file
66
src/runtime/cgo/gcc_linux.c
Normal file
@@ -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;
|
||||
}
|
||||
91
src/runtime/cgo/gcc_linux_amd64.c
Normal file
91
src/runtime/cgo/gcc_linux_amd64.c
Normal file
@@ -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;
|
||||
}
|
||||
87
src/runtime/cgo/gcc_linux_arm64.c
Normal file
87
src/runtime/cgo/gcc_linux_arm64.c
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
86
src/runtime/cgo/gcc_linux_ppc64x.S
Normal file
86
src/runtime/cgo/gcc_linux_ppc64x.S
Normal file
@@ -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
|
||||
63
src/runtime/cgo/gcc_linux_s390x.c
Normal file
63
src/runtime/cgo/gcc_linux_s390x.c
Normal file
@@ -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;
|
||||
}
|
||||
67
src/runtime/cgo/gcc_loong64.S
Normal file
67
src/runtime/cgo/gcc_loong64.S
Normal file
@@ -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
|
||||
89
src/runtime/cgo/gcc_mips64x.S
Normal file
89
src/runtime/cgo/gcc_mips64x.S
Normal file
@@ -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
|
||||
77
src/runtime/cgo/gcc_mipsx.S
Normal file
77
src/runtime/cgo/gcc_mipsx.S
Normal file
@@ -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
|
||||
39
src/runtime/cgo/gcc_mmap.c
Normal file
39
src/runtime/cgo/gcc_mmap.c
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
73
src/runtime/cgo/gcc_netbsd.c
Normal file
73
src/runtime/cgo/gcc_netbsd.c
Normal file
@@ -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;
|
||||
}
|
||||
61
src/runtime/cgo/gcc_openbsd.c
Normal file
61
src/runtime/cgo/gcc_openbsd.c
Normal file
@@ -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;
|
||||
}
|
||||
67
src/runtime/cgo/gcc_ppc64x.c
Normal file
67
src/runtime/cgo/gcc_ppc64x.c
Normal file
@@ -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;
|
||||
}
|
||||
82
src/runtime/cgo/gcc_riscv64.S
Normal file
82
src/runtime/cgo/gcc_riscv64.S
Normal file
@@ -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
|
||||
58
src/runtime/cgo/gcc_s390x.S
Normal file
58
src/runtime/cgo/gcc_s390x.S
Normal file
@@ -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
|
||||
27
src/runtime/cgo/gcc_setenv.c
Normal file
27
src/runtime/cgo/gcc_setenv.c
Normal file
@@ -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();
|
||||
}
|
||||
82
src/runtime/cgo/gcc_sigaction.c
Normal file
82
src/runtime/cgo/gcc_sigaction.c
Normal file
@@ -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;
|
||||
}
|
||||
11
src/runtime/cgo/gcc_signal2_ios_arm64.c
Normal file
11
src/runtime/cgo/gcc_signal2_ios_arm64.c
Normal file
@@ -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) {}
|
||||
213
src/runtime/cgo/gcc_signal_ios_arm64.c
Normal file
213
src/runtime/cgo/gcc_signal_ios_arm64.c
Normal file
@@ -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)(uintptr_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);
|
||||
}
|
||||
10
src/runtime/cgo/gcc_signal_ios_nolldb.c
Normal file
10
src/runtime/cgo/gcc_signal_ios_nolldb.c
Normal file
@@ -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() {}
|
||||
83
src/runtime/cgo/gcc_solaris_amd64.c
Normal file
83
src/runtime/cgo/gcc_solaris_amd64.c
Normal file
@@ -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;
|
||||
}
|
||||
25
src/runtime/cgo/gcc_stack_darwin.c
Normal file
25
src/runtime/cgo/gcc_stack_darwin.c
Normal file
@@ -0,0 +1,25 @@
|
||||
// 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 points into the Go stack. TSAN can't see the synchronization
|
||||
// in Go around stack reuse.
|
||||
_cgo_tsan_acquire();
|
||||
bounds[0] = (uintptr)addr - size;
|
||||
bounds[1] = (uintptr)addr;
|
||||
_cgo_tsan_release();
|
||||
}
|
||||
47
src/runtime/cgo/gcc_stack_unix.c
Normal file
47
src/runtime/cgo/gcc_stack_unix.c
Normal file
@@ -0,0 +1,47 @@
|
||||
// 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;
|
||||
|
||||
// Needed before pthread_getattr_np, too, since before glibc 2.32
|
||||
// it did not call pthread_attr_init in all cases (see #65625).
|
||||
pthread_attr_init(&attr);
|
||||
#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_get_np(pthread_self(), &attr);
|
||||
pthread_attr_getstack(&attr, &addr, &size); // low address
|
||||
#else
|
||||
// We don't know how to get the current stacks, so assume they are the
|
||||
// same as the default stack bounds.
|
||||
pthread_attr_getstacksize(&attr, &size);
|
||||
addr = __builtin_frame_address(0) + 4096 - size;
|
||||
#endif
|
||||
pthread_attr_destroy(&attr);
|
||||
|
||||
// bounds points into the Go stack. TSAN can't see the synchronization
|
||||
// in Go around stack reuse.
|
||||
_cgo_tsan_acquire();
|
||||
bounds[0] = (uintptr)addr;
|
||||
bounds[1] = (uintptr)addr + size;
|
||||
_cgo_tsan_release();
|
||||
}
|
||||
7
src/runtime/cgo/gcc_stack_windows.c
Normal file
7
src/runtime/cgo/gcc_stack_windows.c
Normal file
@@ -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
|
||||
46
src/runtime/cgo/gcc_traceback.c
Normal file
46
src/runtime/cgo/gcc_traceback.c
Normal file
@@ -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);
|
||||
}
|
||||
69
src/runtime/cgo/gcc_util.c
Normal file
69
src/runtime/cgo/gcc_util.c
Normal file
@@ -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 */
|
||||
53
src/runtime/cgo/gcc_windows_386.c
Normal file
53
src/runtime/cgo/gcc_windows_386.c
Normal file
@@ -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);
|
||||
}
|
||||
52
src/runtime/cgo/gcc_windows_amd64.c
Normal file
52
src/runtime/cgo/gcc_windows_amd64.c
Normal file
@@ -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);
|
||||
}
|
||||
40
src/runtime/cgo/gcc_windows_arm64.c
Normal file
40
src/runtime/cgo/gcc_windows_arm64.c
Normal file
@@ -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);
|
||||
}
|
||||
144
src/runtime/cgo/handle.go
Normal file
144
src/runtime/cgo/handle.go
Normal file
@@ -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
|
||||
)
|
||||
103
src/runtime/cgo/handle_test.go
Normal file
103
src/runtime/cgo/handle_test.go
Normal file
@@ -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()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
17
src/runtime/cgo/iscgo.go
Normal file
17
src/runtime/cgo/iscgo.go
Normal file
@@ -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
|
||||
151
src/runtime/cgo/libcgo.h
Normal file
151
src/runtime/cgo/libcgo.h
Normal file
@@ -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, ...) __attribute__ ((noreturn));
|
||||
|
||||
/*
|
||||
* 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)
|
||||
20
src/runtime/cgo/libcgo_unix.h
Normal file
20
src/runtime/cgo/libcgo_unix.h
Normal file
@@ -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);
|
||||
6
src/runtime/cgo/libcgo_windows.h
Normal file
6
src/runtime/cgo/libcgo_windows.h
Normal file
@@ -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);
|
||||
74
src/runtime/cgo/linux.go
Normal file
74
src/runtime/cgo/linux.go
Normal file
@@ -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)
|
||||
85
src/runtime/cgo/linux_syscall.c
Normal file
85
src/runtime/cgo/linux_syscall.c
Normal file
@@ -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]));
|
||||
}
|
||||
31
src/runtime/cgo/mmap.go
Normal file
31
src/runtime/cgo/mmap.go
Normal file
@@ -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
|
||||
21
src/runtime/cgo/netbsd.go
Normal file
21
src/runtime/cgo/netbsd.go
Normal file
@@ -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
|
||||
21
src/runtime/cgo/openbsd.go
Normal file
21
src/runtime/cgo/openbsd.go
Normal file
@@ -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
|
||||
21
src/runtime/cgo/setenv.go
Normal file
21
src/runtime/cgo/setenv.go
Normal file
@@ -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
|
||||
22
src/runtime/cgo/sigaction.go
Normal file
22
src/runtime/cgo/sigaction.go
Normal file
@@ -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
|
||||
10
src/runtime/cgo/signal_ios_arm64.go
Normal file
10
src/runtime/cgo/signal_ios_arm64.go
Normal file
@@ -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()
|
||||
56
src/runtime/cgo/signal_ios_arm64.s
Normal file
56
src/runtime/cgo/signal_ios_arm64.s
Normal file
@@ -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)
|
||||
Reference in New Issue
Block a user