Commit 428062da authored by Dmitriy Vyukov's avatar Dmitriy Vyukov

ld: increase default stack size on Windows for cgo

Fixes #2437.

R=rsc, hectorchu, mattn.jp, alex.brainman, jdpoirier, snaury, n13m3y3r
CC=golang-dev
https://golang.org/cl/5371049
parent 5e435273
...@@ -274,6 +274,7 @@ loadlib(void) ...@@ -274,6 +274,7 @@ loadlib(void)
for(i=0; i<libraryp; i++) { for(i=0; i<libraryp; i++) {
if(debug['v']) if(debug['v'])
Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i].file, library[i].objref); Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i].file, library[i].objref);
iscgo |= strcmp(library[i].pkg, "runtime/cgo") == 0;
objfile(library[i].file, library[i].pkg); objfile(library[i].file, library[i].pkg);
} }
......
...@@ -125,6 +125,7 @@ EXTERN int32 nsymbol; ...@@ -125,6 +125,7 @@ EXTERN int32 nsymbol;
EXTERN char* thestring; EXTERN char* thestring;
EXTERN int ndynexp; EXTERN int ndynexp;
EXTERN int havedynamic; EXTERN int havedynamic;
EXTERN int iscgo;
EXTERN Segment segtext; EXTERN Segment segtext;
EXTERN Segment segdata; EXTERN Segment segdata;
......
...@@ -650,8 +650,21 @@ asmbpe(void) ...@@ -650,8 +650,21 @@ asmbpe(void)
// Commit size must be strictly less than reserve // Commit size must be strictly less than reserve
// size otherwise reserve will be rounded up to a // size otherwise reserve will be rounded up to a
// larger size, as verified with VMMap. // larger size, as verified with VMMap.
set(SizeOfStackReserve, 0x00010000);
set(SizeOfStackCommit, 0x0000ffff); // Go code would be OK with 64k stacks, but we need larger stacks for cgo.
// That default stack reserve size affects only the main thread,
// for other threads we specify stack size in runtime explicitly
// (runtime knows whether cgo is enabled or not).
// If you change stack reserve sizes here,
// change them in runtime/cgo/windows_386/amd64.c as well.
if(!iscgo) {
set(SizeOfStackReserve, 0x00010000);
set(SizeOfStackCommit, 0x0000ffff);
} else {
set(SizeOfStackReserve, pe64 ? 0x00200000 : 0x00100000);
// account for 2 guard pages
set(SizeOfStackCommit, (pe64 ? 0x00200000 : 0x00100000) - 0x2000);
}
set(SizeOfHeapReserve, 0x00100000); set(SizeOfHeapReserve, 0x00100000);
set(SizeOfHeapCommit, 0x00001000); set(SizeOfHeapCommit, 0x00001000);
set(NumberOfRvaAndSizes, 16); set(NumberOfRvaAndSizes, 16);
......
...@@ -21,15 +21,22 @@ TEXT _rt0_386(SB),7,$0 ...@@ -21,15 +21,22 @@ TEXT _rt0_386(SB),7,$0
MOVL AX, 120(SP) // save argc, argv away MOVL AX, 120(SP) // save argc, argv away
MOVL BX, 124(SP) MOVL BX, 124(SP)
// set default stack bounds.
// initcgo may update stackguard.
MOVL $runtime·g0(SB), BP
LEAL (-64*1024+104)(SP), BX
MOVL BX, g_stackguard(BP)
MOVL SP, g_stackbase(BP)
// if there is an initcgo, call it to let it // if there is an initcgo, call it to let it
// initialize and to set up GS. if not, // initialize and to set up GS. if not,
// we set up GS ourselves. // we set up GS ourselves.
MOVL initcgo(SB), AX MOVL initcgo(SB), AX
TESTL AX, AX TESTL AX, AX
JZ needtls JZ needtls
PUSHL $runtime·g0(SB) PUSHL BP
CALL AX CALL AX
POPL AX POPL BP
// skip runtime·ldt0setup(SB) and tls test after initcgo for non-windows // skip runtime·ldt0setup(SB) and tls test after initcgo for non-windows
CMPL runtime·iswindows(SB), $0 CMPL runtime·iswindows(SB), $0
JEQ ok JEQ ok
...@@ -59,16 +66,6 @@ ok: ...@@ -59,16 +66,6 @@ ok:
// save m->g0 = g0 // save m->g0 = g0
MOVL CX, m_g0(AX) MOVL CX, m_g0(AX)
// create istack out of the OS stack
// if there is an initcgo, it had setup stackguard for us
MOVL initcgo(SB), AX
TESTL AX, AX
JNZ stackok
LEAL (-64*1024+104)(SP), AX // TODO: 104?
MOVL AX, g_stackguard(CX)
stackok:
MOVL SP, g_stackbase(CX)
CALL runtime·emptyfunc(SB) // fault if stack check is wrong CALL runtime·emptyfunc(SB) // fault if stack check is wrong
// convention is D is always cleared // convention is D is always cleared
......
...@@ -12,13 +12,19 @@ TEXT _rt0_amd64(SB),7,$-8 ...@@ -12,13 +12,19 @@ TEXT _rt0_amd64(SB),7,$-8
ANDQ $~15, SP ANDQ $~15, SP
MOVQ AX, 16(SP) MOVQ AX, 16(SP)
MOVQ BX, 24(SP) MOVQ BX, 24(SP)
// create istack out of the given (operating system) stack.
// initcgo may update stackguard.
MOVQ $runtime·g0(SB), DI
LEAQ (-8192+104)(SP), BX
MOVQ BX, g_stackguard(DI)
MOVQ SP, g_stackbase(DI)
// if there is an initcgo, call it. // if there is an initcgo, call it.
MOVQ initcgo(SB), AX MOVQ initcgo(SB), AX
TESTQ AX, AX TESTQ AX, AX
JZ needtls JZ needtls
LEAQ runtime·g0(SB), DI CALL AX // g0 already in DI
CALL AX
CMPL runtime·iswindows(SB), $0 CMPL runtime·iswindows(SB), $0
JEQ ok JEQ ok
...@@ -44,16 +50,6 @@ ok: ...@@ -44,16 +50,6 @@ ok:
// save m->g0 = g0 // save m->g0 = g0
MOVQ CX, m_g0(AX) MOVQ CX, m_g0(AX)
// create istack out of the given (operating system) stack
// if there is an initcgo, it had setup stackguard for us
MOVQ initcgo(SB), AX
TESTQ AX, AX
JNZ stackok
LEAQ (-8192+104)(SP), AX
MOVQ AX, g_stackguard(CX)
stackok:
MOVQ SP, g_stackbase(CX)
CLD // convention is D is always left cleared CLD // convention is D is always left cleared
CALL runtime·check(SB) CALL runtime·check(SB)
......
...@@ -8,15 +8,16 @@ ...@@ -8,15 +8,16 @@
static void *threadentry(void*); static void *threadentry(void*);
/* From what I've read 1MB is default for 32-bit Linux. /* 1MB is default stack size for 32-bit Windows.
Allocation granularity on Windows is typically 64 KB. */ Allocation granularity on Windows is typically 64 KB.
The constant is also hardcoded in cmd/ld/pe.c (keep synchronized). */
#define STACKSIZE (1*1024*1024) #define STACKSIZE (1*1024*1024)
static void static void
xinitcgo(G *g) xinitcgo(G *g)
{ {
int tmp; int tmp;
g->stackguard = (uintptr)&tmp - STACKSIZE + 4096; g->stackguard = (uintptr)&tmp - STACKSIZE + 8*1024;
} }
void (*initcgo)(G*) = xinitcgo; void (*initcgo)(G*) = xinitcgo;
...@@ -24,8 +25,7 @@ void (*initcgo)(G*) = xinitcgo; ...@@ -24,8 +25,7 @@ void (*initcgo)(G*) = xinitcgo;
void void
libcgo_sys_thread_start(ThreadStart *ts) libcgo_sys_thread_start(ThreadStart *ts)
{ {
ts->g->stackguard = STACKSIZE; _beginthread(threadentry, 0, ts);
_beginthread(threadentry, STACKSIZE, ts);
} }
static void* static void*
...@@ -38,12 +38,7 @@ threadentry(void *v) ...@@ -38,12 +38,7 @@ threadentry(void *v)
free(v); free(v);
ts.g->stackbase = (uintptr)&ts; ts.g->stackbase = (uintptr)&ts;
ts.g->stackguard = (uintptr)&ts - STACKSIZE + 8*1024;
/*
* libcgo_sys_thread_start set stackguard to stack size;
* change to actual guard pointer.
*/
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
/* /*
* Set specific keys in thread local storage. * Set specific keys in thread local storage.
......
...@@ -8,15 +8,16 @@ ...@@ -8,15 +8,16 @@
static void *threadentry(void*); static void *threadentry(void*);
/* From what I've read 2MB is default for 64-bit Linux. /* 2MB is default stack size for 64-bit Windows.
Allocation granularity on Windows is typically 64 KB. */ Allocation granularity on Windows is typically 64 KB.
The constant is also hardcoded in cmd/ld/pe.c (keep synchronized). */
#define STACKSIZE (2*1024*1024) #define STACKSIZE (2*1024*1024)
static void static void
xinitcgo(G *g) xinitcgo(G *g)
{ {
int tmp; int tmp;
g->stackguard = (uintptr)&tmp - STACKSIZE + 4096; g->stackguard = (uintptr)&tmp - STACKSIZE + 8*1024;
} }
void (*initcgo)(G*) = xinitcgo; void (*initcgo)(G*) = xinitcgo;
...@@ -24,8 +25,7 @@ void (*initcgo)(G*) = xinitcgo; ...@@ -24,8 +25,7 @@ void (*initcgo)(G*) = xinitcgo;
void void
libcgo_sys_thread_start(ThreadStart *ts) libcgo_sys_thread_start(ThreadStart *ts)
{ {
ts->g->stackguard = STACKSIZE; _beginthread(threadentry, 0, ts);
_beginthread(threadentry, STACKSIZE, ts);
} }
static void* static void*
...@@ -38,12 +38,7 @@ threadentry(void *v) ...@@ -38,12 +38,7 @@ threadentry(void *v)
free(v); free(v);
ts.g->stackbase = (uintptr)&ts; ts.g->stackbase = (uintptr)&ts;
ts.g->stackguard = (uintptr)&ts - STACKSIZE + 8*1024;
/*
* libcgo_sys_thread_start set stackguard to stack size;
* change to actual guard pointer.
*/
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
/* /*
* Set specific keys in thread local storage. * Set specific keys in thread local storage.
......
...@@ -183,6 +183,8 @@ runtime·semacreate(void) ...@@ -183,6 +183,8 @@ runtime·semacreate(void)
return (uintptr)runtime·stdcall(runtime·CreateEvent, 4, (uintptr)0, (uintptr)0, (uintptr)0, (uintptr)0); return (uintptr)runtime·stdcall(runtime·CreateEvent, 4, (uintptr)0, (uintptr)0, (uintptr)0, (uintptr)0);
} }
#define STACK_SIZE_PARAM_IS_A_RESERVATION ((uintptr)0x00010000)
void void
runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void)) runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
{ {
...@@ -193,7 +195,8 @@ runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void)) ...@@ -193,7 +195,8 @@ runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
USED(fn); // assuming fn = mstart USED(fn); // assuming fn = mstart
thandle = runtime·stdcall(runtime·CreateThread, 6, thandle = runtime·stdcall(runtime·CreateThread, 6,
nil, nil, runtime·tstart_stdcall, m, nil, nil); nil, (uintptr)0x20000, runtime·tstart_stdcall, m,
STACK_SIZE_PARAM_IS_A_RESERVATION, nil);
if(thandle == nil) { if(thandle == nil) {
runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror()); runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror());
runtime·throw("runtime.newosproc"); runtime·throw("runtime.newosproc");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment