aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorqmuntal <quimmuntal@gmail.com>2025-09-30 17:23:49 +0200
committerQuim Muntal <quimmuntal@gmail.com>2026-02-13 09:11:10 -0800
commit8a0bc29bedd45324c52cfdc7717fabfc82673e4d (patch)
tree75ce69c04d6a554494bef8e64e7c271968f53083 /src
parent65b9017c0e955ad57fb42c3bf82aa0ff51ddbff5 (diff)
downloadgo-8a0bc29bedd45324c52cfdc7717fabfc82673e4d.tar.xz
runtime/cgo: deduplicate x_cgo_init and crosscall1
Most platforms share the same implementation for x_cgo_init and crosscall1. Solaris diverges too much and is left for a future CL. Cq-Include-Trybots: luci.golang.try:gotip-freebsd-amd64,gotip-darwin-amd64_14,gotip-darwin-arm64_15,gotip-netbsd-arm64,gotip-openbsd-ppc64,gotip-solaris-amd64,gotip-linux-ppc64_power10 Change-Id: Ib2eeb6456caa5c055e1ac1907c2fdf63db58dafc Reviewed-on: https://go-review.googlesource.com/c/go/+/708035 Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Michael Pratt <mpratt@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Junyang Shao <shaojunyang@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/runtime/cgo/gcc_darwin_amd64.c30
-rw-r--r--src/runtime/cgo/gcc_dragonfly_amd64.c29
-rw-r--r--src/runtime/cgo/gcc_freebsd.c57
-rw-r--r--src/runtime/cgo/gcc_freebsd_amd64.c41
-rw-r--r--src/runtime/cgo/gcc_ios_arm64.c (renamed from src/runtime/cgo/gcc_darwin_arm64.c)29
-rw-r--r--src/runtime/cgo/gcc_libinit.c24
-rw-r--r--src/runtime/cgo/gcc_linux.c37
-rw-r--r--src/runtime/cgo/gcc_linux_amd64.c63
-rw-r--r--src/runtime/cgo/gcc_linux_arm64.c58
-rw-r--r--src/runtime/cgo/gcc_linux_s390x.c34
-rw-r--r--src/runtime/cgo/gcc_netbsd.c70
-rw-r--r--src/runtime/cgo/gcc_openbsd.c31
-rw-r--r--src/runtime/cgo/gcc_ppc64x.c38
-rw-r--r--src/runtime/cgo/gcc_unix.c118
-rw-r--r--src/runtime/cgo/libcgo_unix.h5
15 files changed, 168 insertions, 496 deletions
diff --git a/src/runtime/cgo/gcc_darwin_amd64.c b/src/runtime/cgo/gcc_darwin_amd64.c
deleted file mode 100644
index 0a9198e29f..0000000000
--- a/src/runtime/cgo/gcc_darwin_amd64.c
+++ /dev/null
@@ -1,30 +0,0 @@
-// 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 "libcgo.h"
-#include "libcgo_unix.h"
-
-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);
-}
-
-
-extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
-void*
-threadentry(void *v)
-{
- ThreadStart ts;
-
- ts = *(ThreadStart*)v;
- free(v);
-
- crosscall1(ts.fn, setg_gcc, (void*)ts.g);
- return nil;
-}
diff --git a/src/runtime/cgo/gcc_dragonfly_amd64.c b/src/runtime/cgo/gcc_dragonfly_amd64.c
deleted file mode 100644
index 4851b2a6a0..0000000000
--- a/src/runtime/cgo/gcc_dragonfly_amd64.c
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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>
-#include "libcgo.h"
-#include "libcgo_unix.h"
-
-static void (*setg_gcc)(void*);
-
-void
-x_cgo_init(G *g, void (*setg)(void*))
-{
- setg_gcc = setg;
- _cgo_set_stacklo(g, NULL);
-}
-
-extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
-void*
-threadentry(void *v)
-{
- ThreadStart ts;
-
- ts = *(ThreadStart*)v;
- free(v);
-
- crosscall1(ts.fn, setg_gcc, (void*)ts.g);
- return nil;
-}
diff --git a/src/runtime/cgo/gcc_freebsd.c b/src/runtime/cgo/gcc_freebsd.c
index b5adecc5f1..606d6bd591 100644
--- a/src/runtime/cgo/gcc_freebsd.c
+++ b/src/runtime/cgo/gcc_freebsd.c
@@ -1,41 +1,16 @@
-// 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 <machine/sysarch.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 (*setg_gcc)(void*);
-
-void
-x_cgo_init(G *g, void (*setg)(void*))
-{
- setg_gcc = setg;
- _cgo_set_stacklo(g, NULL);
-}
-
-extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
-void*
-threadentry(void *v)
-{
- ThreadStart ts;
-
- ts = *(ThreadStart*)v;
- free(v);
-
- crosscall1(ts.fn, setg_gcc, ts.g);
- return nil;
-}
+// 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
+
+#include <machine/sysarch.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
diff --git a/src/runtime/cgo/gcc_freebsd_amd64.c b/src/runtime/cgo/gcc_freebsd_amd64.c
deleted file mode 100644
index 0fa81495a3..0000000000
--- a/src/runtime/cgo/gcc_freebsd_amd64.c
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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 <errno.h>
-#include <string.h>
-#include "libcgo.h"
-#include "libcgo_unix.h"
-
-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);
-}
-
-extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
-void*
-threadentry(void *v)
-{
- ThreadStart ts;
-
- ts = *(ThreadStart*)v;
- _cgo_tsan_acquire();
- free(v);
- _cgo_tsan_release();
-
- crosscall1(ts.fn, setg_gcc, (void*)ts.g);
- return nil;
-}
diff --git a/src/runtime/cgo/gcc_darwin_arm64.c b/src/runtime/cgo/gcc_ios_arm64.c
index e502851fc1..32f517d464 100644
--- a/src/runtime/cgo/gcc_darwin_arm64.c
+++ b/src/runtime/cgo/gcc_ios_arm64.c
@@ -9,7 +9,6 @@
#include <stdlib.h>
#include "libcgo.h"
-#include "libcgo_unix.h"
#include <TargetConditionals.h>
@@ -18,27 +17,16 @@
#include <CoreFoundation/CFString.h>
#endif
-static void (*setg_gcc)(void*);
+#if TARGET_OS_IPHONE
-extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
-void*
-threadentry(void *v)
+static void
+threadentry_platform(void)
{
- 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
@@ -101,16 +89,15 @@ init_working_dir()
#endif // TARGET_OS_IPHONE
-void
-x_cgo_init(G *g, void (*setg)(void*))
+static void
+init_platform()
{
- //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
}
+
+void (*x_cgo_init_platform)(void) = init_platform;
+void (*x_cgo_threadentry_platform)(void) = threadentry_platform;
diff --git a/src/runtime/cgo/gcc_libinit.c b/src/runtime/cgo/gcc_libinit.c
index 4b163c2d19..9d2402636e 100644
--- a/src/runtime/cgo/gcc_libinit.c
+++ b/src/runtime/cgo/gcc_libinit.c
@@ -83,30 +83,6 @@ _cgo_wait_runtime_init_done(void) {
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) {
diff --git a/src/runtime/cgo/gcc_linux.c b/src/runtime/cgo/gcc_linux.c
deleted file mode 100644
index cdccbf3454..0000000000
--- a/src/runtime/cgo/gcc_linux.c
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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 <string.h>
-#include "libcgo.h"
-#include "libcgo_unix.h"
-
-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);
- }
-}
-
-extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
-void*
-threadentry(void *v)
-{
- ThreadStart ts;
-
- ts = *(ThreadStart*)v;
- free(v);
-
- crosscall1(ts.fn, setg_gcc, ts.g);
- return nil;
-}
diff --git a/src/runtime/cgo/gcc_linux_amd64.c b/src/runtime/cgo/gcc_linux_amd64.c
deleted file mode 100644
index 35c4f76457..0000000000
--- a/src/runtime/cgo/gcc_linux_amd64.c
+++ /dev/null
@@ -1,63 +0,0 @@
-// 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 <errno.h>
-#include <string.h> // strerror
-#include <stdlib.h>
-#include "libcgo.h"
-#include "libcgo_unix.h"
-
-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);
- }
-}
-
-
-extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
-void*
-threadentry(void *v)
-{
- ThreadStart ts;
-
- ts = *(ThreadStart*)v;
- _cgo_tsan_acquire();
- free(v);
- _cgo_tsan_release();
-
- crosscall1(ts.fn, setg_gcc, (void*)ts.g);
- return nil;
-}
diff --git a/src/runtime/cgo/gcc_linux_arm64.c b/src/runtime/cgo/gcc_linux_arm64.c
deleted file mode 100644
index bd4b36a553..0000000000
--- a/src/runtime/cgo/gcc_linux_arm64.c
+++ /dev/null
@@ -1,58 +0,0 @@
-// 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 <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include "libcgo.h"
-#include "libcgo_unix.h"
-
-void (*x_cgo_inittls)(void **tlsg, void **tlsbase) __attribute__((common));
-static void (*setg_gcc)(void*);
-
-extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
-void*
-threadentry(void *v)
-{
- ThreadStart ts;
-
- ts = *(ThreadStart*)v;
- free(v);
-
- crosscall1(ts.fn, setg_gcc, (void*)ts.g);
- return nil;
-}
-
-void
-x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
-{
- uintptr *pbounds;
-
- /* The memory sanitizer distributed with versions of clang
- before 3.8 has a bug: if you call mmap before malloc, mmap
- may return an address that is later overwritten by the msan
- library. Avoid this problem by forcing a call to malloc
- here, before we ever call malloc.
-
- This is only required for the memory sanitizer, so it's
- unfortunate that we always run it. It should be possible
- to remove this when we no longer care about versions of
- clang before 3.8. The test for this is
- misc/cgo/testsanitizers.
-
- GCC works hard to eliminate a seemingly unnecessary call to
- malloc, so we actually use the memory we allocate. */
-
- setg_gcc = setg;
- pbounds = (uintptr*)malloc(2 * sizeof(uintptr));
- if (pbounds == NULL) {
- fatalf("malloc failed: %s", strerror(errno));
- }
- _cgo_set_stacklo(g, pbounds);
- free(pbounds);
-
- if (x_cgo_inittls) {
- x_cgo_inittls(tlsg, tlsbase);
- }
-}
diff --git a/src/runtime/cgo/gcc_linux_s390x.c b/src/runtime/cgo/gcc_linux_s390x.c
deleted file mode 100644
index 8f055e3087..0000000000
--- a/src/runtime/cgo/gcc_linux_s390x.c
+++ /dev/null
@@ -1,34 +0,0 @@
-// 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 <string.h>
-#include "libcgo.h"
-#include "libcgo_unix.h"
-
-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);
-}
-
-extern void crosscall_s390x(void (*fn)(void), void *g);
-
-void*
-threadentry(void *v)
-{
- ThreadStart ts;
-
- ts = *(ThreadStart*)v;
- free(v);
-
- // Save g for this thread in C TLS
- setg_gcc((void*)ts.g);
-
- crosscall_s390x(ts.fn, (void*)ts.g);
- return nil;
-}
diff --git a/src/runtime/cgo/gcc_netbsd.c b/src/runtime/cgo/gcc_netbsd.c
index c8c0969108..4e92c86f86 100644
--- a/src/runtime/cgo/gcc_netbsd.c
+++ b/src/runtime/cgo/gcc_netbsd.c
@@ -1,44 +1,26 @@
-// 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 <signal.h>
-#include <string.h>
-#include "libcgo.h"
-#include "libcgo_unix.h"
-
-static void (*setg_gcc)(void*);
-
-void
-x_cgo_init(G *g, void (*setg)(void*))
-{
- setg_gcc = setg;
- _cgo_set_stacklo(g, NULL);
-}
-
-extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
-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;
-}
+// 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
+
+#include <string.h>
+#include <signal.h>
+
+static void
+threadentry_platform(void)
+{
+ // 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.
+ stack_t ss;
+ memset(&ss, 0, sizeof ss);
+ ss.ss_flags = SS_DISABLE;
+ sigaltstack(&ss, NULL);
+}
+
+void (*x_cgo_threadentry_platform)(void) = threadentry_platform;
diff --git a/src/runtime/cgo/gcc_openbsd.c b/src/runtime/cgo/gcc_openbsd.c
deleted file mode 100644
index 166b9cd756..0000000000
--- a/src/runtime/cgo/gcc_openbsd.c
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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 <string.h>
-#include "libcgo.h"
-#include "libcgo_unix.h"
-
-static void (*setg_gcc)(void*);
-
-void
-x_cgo_init(G *g, void (*setg)(void*))
-{
- setg_gcc = setg;
- _cgo_set_stacklo(g, NULL);
-}
-
-extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
-void*
-threadentry(void *v)
-{
- ThreadStart ts;
-
- ts = *(ThreadStart*)v;
- free(v);
-
- crosscall1(ts.fn, setg_gcc, ts.g);
- return nil;
-}
diff --git a/src/runtime/cgo/gcc_ppc64x.c b/src/runtime/cgo/gcc_ppc64x.c
deleted file mode 100644
index 6f5a0bd9ad..0000000000
--- a/src/runtime/cgo/gcc_ppc64x.c
+++ /dev/null
@@ -1,38 +0,0 @@
-// 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 <string.h>
-#include "libcgo.h"
-#include "libcgo_unix.h"
-
-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);
-}
-
-extern void crosscall_ppc64(void (*fn)(void), void *g);
-
-void*
-threadentry(void *v)
-{
- ThreadStart ts;
-
- ts = *(ThreadStart*)v;
- _cgo_tsan_acquire();
- free(v);
- _cgo_tsan_release();
-
- // Save g for this thread in C TLS
- setg_gcc((void*)ts.g);
-
- crosscall_ppc64(ts.fn, (void*)ts.g);
- return nil;
-}
diff --git a/src/runtime/cgo/gcc_unix.c b/src/runtime/cgo/gcc_unix.c
new file mode 100644
index 0000000000..6004f8ca11
--- /dev/null
+++ b/src/runtime/cgo/gcc_unix.c
@@ -0,0 +1,118 @@
+// 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 unix && !solaris
+
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include "libcgo.h"
+#include "libcgo_unix.h"
+
+// Platform-specific hooks.
+void (*x_cgo_inittls)(void **tlsg, void **tlsbase) __attribute__((weak));
+void (*x_cgo_init_platform)(void) __attribute__((weak));
+void (*x_cgo_threadentry_platform)(void) __attribute__((weak));
+
+static void (*setg_gcc)(void*);
+
+// _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.
+static void
+_cgo_set_stacklo(G *g)
+{
+ uintptr bounds[2];
+
+ x_cgo_getstackbound(bounds);
+
+ g->stacklo = bounds[0];
+
+ // 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();
+ }
+}
+
+static void
+clang_init()
+{
+#if defined(__linux__) && (defined(__x86_64__) || defined(__aarch64__))
+ /* 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
+ cmd/cgo/internal/testsanitizers . */
+ uintptr *p;
+ p = (uintptr*)malloc(sizeof(uintptr));
+ if (p == NULL) {
+ fatalf("malloc failed: %s", strerror(errno));
+ }
+ /* GCC works hard to eliminate a seemingly unnecessary call to
+ malloc, so we actually touch the memory we allocate. */
+ ((volatile char *)p)[0] = 0;
+ free(p);
+#endif
+}
+
+void
+x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
+{
+ clang_init();
+ setg_gcc = setg;
+ _cgo_set_stacklo(g);
+
+ if (x_cgo_inittls) {
+ x_cgo_inittls(tlsg, tlsbase);
+ }
+ if (x_cgo_init_platform) {
+ x_cgo_init_platform();
+ }
+}
+
+// TODO: change crosscall_ppc64 and crosscall_s390x so that it matches crosscall1
+// signature and behavior.
+#if defined(__powerpc64__)
+extern void crosscall_ppc64(void (*fn)(void), void *g);
+#elif defined(__s390x__)
+extern void crosscall_s390x(void (*fn)(void), void *g);
+#else
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+#endif
+
+void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ _cgo_tsan_acquire();
+ free(v);
+ _cgo_tsan_release();
+
+ if (x_cgo_threadentry_platform != NULL) {
+ x_cgo_threadentry_platform();
+ }
+
+#if defined(__powerpc64__)
+ // Save g for this thread in C TLS
+ setg_gcc((void*)ts.g);
+ crosscall_ppc64(ts.fn, (void*)ts.g);
+#elif defined(__s390x__)
+ // Save g for this thread in C TLS
+ setg_gcc((void*)ts.g);
+ crosscall_s390x(ts.fn, (void*)ts.g);
+#else
+ crosscall1(ts.fn, setg_gcc, ts.g);
+#endif
+ return NULL;
+}
diff --git a/src/runtime/cgo/libcgo_unix.h b/src/runtime/cgo/libcgo_unix.h
index 5ce0224523..604fd5dc1b 100644
--- a/src/runtime/cgo/libcgo_unix.h
+++ b/src/runtime/cgo/libcgo_unix.h
@@ -5,11 +5,6 @@
#include <pthread.h>
/*
- * 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*);