diff options
| author | Christopher Nelson <nadiasvertex@gmail.com> | 2015-12-13 08:02:29 -0500 |
|---|---|---|
| committer | Ian Lance Taylor <iant@golang.org> | 2016-04-04 03:38:25 +0000 |
| commit | ed8f0e5c33269de2f950d33ab7d50554b13f336e (patch) | |
| tree | 082a9afa5121f0ca714f2b45ecbcac58db86de10 /src/runtime | |
| parent | 386c0e6598eadab18e01d3fa60f8e21872cbe70c (diff) | |
| download | go-ed8f0e5c33269de2f950d33ab7d50554b13f336e.tar.xz | |
cmd/go: fix -buildmode=c-archive should work on windows
Add supporting code for runtime initialization, including both
32- and 64-bit x86 architectures.
Add .ctors section on Windows to PE .o files, and INITENTRY to .ctors
section to plug in to the GCC C/C++ startup initialization mechanism.
This allows the Go runtime to initialize itself. Add .text section
symbol for .ctor relocations. Note: This is unlikely to be useful for
MSVC-based toolchains.
Fixes #13494
Change-Id: I4286a96f70e5f5228acae88eef46e2bed95813f3
Reviewed-on: https://go-review.googlesource.com/18057
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/runtime')
| -rw-r--r-- | src/runtime/cgo/gcc_libinit_windows.c | 80 | ||||
| -rw-r--r-- | src/runtime/os1_windows.go | 16 | ||||
| -rw-r--r-- | src/runtime/rt0_windows_386.s | 34 | ||||
| -rw-r--r-- | src/runtime/rt0_windows_amd64.s | 31 | ||||
| -rw-r--r-- | src/runtime/testdata/testprogcgo/threadpanic_windows.c | 3 |
5 files changed, 155 insertions, 9 deletions
diff --git a/src/runtime/cgo/gcc_libinit_windows.c b/src/runtime/cgo/gcc_libinit_windows.c index eb798ce5e8..50887b844d 100644 --- a/src/runtime/cgo/gcc_libinit_windows.c +++ b/src/runtime/cgo/gcc_libinit_windows.c @@ -2,21 +2,89 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build cgo +#define WIN64_LEAN_AND_MEAN +#include <windows.h> +#include <process.h> + #include <stdio.h> #include <stdlib.h> +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; + +// 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) { - fprintf(stderr, "x_cgo_sys_thread_create not implemented"); - abort(); +x_cgo_sys_thread_create(void (*func)(void*), void* arg) { + uintptr_t thandle; + + thandle = _beginthread(func, 0, arg); + if(thandle == -1) { + fprintf(stderr, "runtime: failed to create new OS thread (%d)\n", errno); + abort(); + } +} + +int +_cgo_is_runtime_initialized() { + EnterCriticalSection(&runtime_init_cs); + int status = runtime_init_done; + LeaveCriticalSection(&runtime_init_cs); + return status; } void _cgo_wait_runtime_init_done() { - // TODO(spetrovic): implement this method. + _cgo_maybe_run_preinit(); + while (!_cgo_is_runtime_initialized()) { + WaitForSingleObject(runtime_init_wait, INFINITE); + } } void x_cgo_notify_runtime_init_done(void* dummy) { - // TODO(spetrovic): implement this method. -}
\ No newline at end of file + _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(); + } +} + diff --git a/src/runtime/os1_windows.go b/src/runtime/os1_windows.go index 3adaebe9de..e6b1a30ecf 100644 --- a/src/runtime/os1_windows.go +++ b/src/runtime/os1_windows.go @@ -396,8 +396,11 @@ func semacreate(mp *m) { mp.waitsema = stdcall4(_CreateEventA, 0, 0, 0, 0) } -// May run with m.p==nil, so write barriers are not allowed. -//go:nowritebarrier +// May run with m.p==nil, so write barriers are not allowed. This +// function is called by newosproc0, so it is also required to +// operate without stack guards. +//go:nowritebarrierc +//go:nosplit func newosproc(mp *m, stk unsafe.Pointer) { const _STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000 thandle := stdcall6(_CreateThread, 0, 0x20000, @@ -409,6 +412,15 @@ func newosproc(mp *m, stk unsafe.Pointer) { } } +// Used by the C library build mode. On Linux this function would allocate a +// stack, but that's not necessary for Windows. No stack guards are present +// and the GC has not been initialized, so write barriers will fail. +//go:nowritebarrierc +//go:nosplit +func newosproc0(mp *m, stk unsafe.Pointer) { + newosproc(mp, stk) +} + // Called to initialize a new m (including the bootstrap m). // Called on the parent thread (main thread in case of bootstrap), can allocate memory. func mpreinit(mp *m) { diff --git a/src/runtime/rt0_windows_386.s b/src/runtime/rt0_windows_386.s index 0150cc2918..b9407a9879 100644 --- a/src/runtime/rt0_windows_386.s +++ b/src/runtime/rt0_windows_386.s @@ -12,5 +12,39 @@ TEXT _rt0_386_windows(SB),NOSPLIT,$12 MOVL $-1, 0(SP) // return PC for main JMP _main(SB) +// When building with -buildmode=(c-shared or c-archive), this +// symbol is called. For dynamic libraries it is called when the +// library is loaded. For static libraries it is called when the +// final executable starts, during the C runtime initialization +// phase. +TEXT _rt0_386_windows_lib(SB),NOSPLIT,$0x1C + MOVL BP, 0x08(SP) + MOVL BX, 0x0C(SP) + MOVL AX, 0x10(SP) + MOVL CX, 0x14(SP) + MOVL DX, 0x18(SP) + + // Create a new thread to do the runtime initialization and return. + MOVL _cgo_sys_thread_create(SB), AX + MOVL $_rt0_386_windows_lib_go(SB), 0x00(SP) + MOVL $0, 0x04(SP) + + // Top two items on the stack are passed to _cgo_sys_thread_create + // as parameters. This is the calling convention on 32-bit Windows. + CALL AX + + MOVL 0x08(SP), BP + MOVL 0x0C(SP), BX + MOVL 0x10(SP), AX + MOVL 0x14(SP), CX + MOVL 0x18(SP), DX + RET + +TEXT _rt0_386_windows_lib_go(SB),NOSPLIT,$0 + MOVL $0, DI + MOVL $0, SI + MOVL $runtime·rt0_go(SB), AX + JMP AX + TEXT _main(SB),NOSPLIT,$0 JMP runtime·rt0_go(SB) diff --git a/src/runtime/rt0_windows_amd64.s b/src/runtime/rt0_windows_amd64.s index 95dce06d71..2f73b37f31 100644 --- a/src/runtime/rt0_windows_amd64.s +++ b/src/runtime/rt0_windows_amd64.s @@ -12,6 +12,37 @@ TEXT _rt0_amd64_windows(SB),NOSPLIT,$-8 MOVQ $main(SB), AX JMP AX +// When building with -buildmode=(c-shared or c-archive), this +// symbol is called. For dynamic libraries it is called when the +// library is loaded. For static libraries it is called when the +// final executable starts, during the C runtime initialization +// phase. +TEXT _rt0_amd64_windows_lib(SB),NOSPLIT,$0x28 + MOVQ BP, 0x00(SP) + MOVQ BX, 0x08(SP) + MOVQ AX, 0x10(SP) + MOVQ CX, 0x18(SP) + MOVQ DX, 0x20(SP) + + // Create a new thread to do the runtime initialization and return. + MOVQ _cgo_sys_thread_create(SB), AX + MOVQ $_rt0_amd64_windows_lib_go(SB), CX + MOVQ $0, DX + CALL AX + + MOVQ 0x00(SP), BP + MOVQ 0x08(SP), BX + MOVQ 0x10(SP), AX + MOVQ 0x18(SP), CX + MOVQ 0x20(SP), DX + RET + +TEXT _rt0_amd64_windows_lib_go(SB),NOSPLIT,$0 + MOVQ $0, DI + MOVQ $0, SI + MOVQ $runtime·rt0_go(SB), AX + JMP AX + TEXT main(SB),NOSPLIT,$-8 MOVQ $runtime·rt0_go(SB), AX JMP AX diff --git a/src/runtime/testdata/testprogcgo/threadpanic_windows.c b/src/runtime/testdata/testprogcgo/threadpanic_windows.c index cf960db53a..6f896634a6 100644 --- a/src/runtime/testdata/testprogcgo/threadpanic_windows.c +++ b/src/runtime/testdata/testprogcgo/threadpanic_windows.c @@ -2,12 +2,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <process.h> #include <stdlib.h> #include <stdio.h> void gopanic(void); -static void* +static unsigned int die(void* x) { gopanic(); |
