diff options
-rw-r--r-- | src/cmd/ld/lib.c | 33 | ||||
-rw-r--r-- | src/pkg/runtime/os_linux.c | 15 | ||||
-rw-r--r-- | src/pkg/runtime/string.go | 4 | ||||
-rw-r--r-- | test/nosplit.go | 9 |
4 files changed, 34 insertions, 27 deletions
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index b4134da36..5db41f9a7 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -1026,7 +1026,7 @@ static LSym *newstack; enum { - HasLinkRegister = (thechar == '5'), + HasLinkRegister = (thechar == '5' || thechar == '9'), }; // TODO: Record enough information in new object files to @@ -1035,7 +1035,7 @@ enum static int callsize(void) { - if(thechar == '5') + if(HasLinkRegister) return 0; return RegSize; } @@ -1046,9 +1046,6 @@ dostkcheck(void) Chain ch; LSym *s; - if(thechar == '9') - return; - morestack = linklookup(ctxt, "runtime.morestack", 0); newstack = linklookup(ctxt, "runtime.newstack", 0); @@ -1072,19 +1069,19 @@ dostkcheck(void) continue; if(s->nosplit) { - ctxt->cursym = s; - ch.sym = s; - stkcheck(&ch, 0); - } + ctxt->cursym = s; + ch.sym = s; + stkcheck(&ch, 0); + } } for(s = ctxt->textp; s != nil; s = s->next) { if(!s->nosplit) { - ctxt->cursym = s; - ch.sym = s; - stkcheck(&ch, 0); + ctxt->cursym = s; + ch.sym = s; + stkcheck(&ch, 0); + } } } -} static int stkcheck(Chain *up, int depth) @@ -1102,7 +1099,7 @@ stkcheck(Chain *up, int depth) // function at top of safe zone once. if(limit == StackLimit-callsize()) { if(s->stkcheck) - return 0; + return 0; s->stkcheck = 1; } @@ -1161,8 +1158,8 @@ stkcheck(Chain *up, int depth) // to StackLimit beyond the frame size. if(strncmp(r->sym->name, "runtime.morestack", 17) == 0) { limit = StackLimit + s->locals; - if(thechar == '5') - limit += 4; // saved LR + if(HasLinkRegister) + limit += RegSize; } break; @@ -1181,7 +1178,7 @@ stkcheck(Chain *up, int depth) break; } } - } + } return 0; } @@ -1210,7 +1207,7 @@ stkprint(Chain *ch, int limit) else print("\t%d\tguaranteed after split check in %s\n", ch->limit, name); } else { - stkprint(ch->up, ch->limit + (!HasLinkRegister)*PtrSize); + stkprint(ch->up, ch->limit + (!HasLinkRegister)*RegSize); if(!HasLinkRegister) print("\t%d\ton entry to %s\n", ch->limit, name); } diff --git a/src/pkg/runtime/os_linux.c b/src/pkg/runtime/os_linux.c index 1751ea83b..8aadee721 100644 --- a/src/pkg/runtime/os_linux.c +++ b/src/pkg/runtime/os_linux.c @@ -49,9 +49,22 @@ runtime·futexsleep(uint32 *addr, uint32 val, int64 ns) runtime·futex(addr, FUTEX_WAIT, val, nil, nil, 0); return; } - // NOTE: tv_nsec is int64 on amd64, so this assumes a little-endian system. + + // It's difficult to live within the no-split stack limits here. + // On ARM and 386, a 64-bit divide invokes a general software routine + // that needs more stack than we can afford. So we use timediv instead. + // But on real 64-bit systems, where words are larger but the stack limit + // is not, even timediv is too heavy, and we really need to use just an + // ordinary machine instruction. + // Sorry for the #ifdef. + // For what it's worth, the #ifdef eliminated an implicit little-endian assumption. +#ifdef _64BIT + ts.tv_sec = ns / 1000000000LL; + ts.tv_nsec = ns % 1000000000LL; +#else ts.tv_nsec = 0; ts.tv_sec = runtime·timediv(ns, 1000000000LL, (int32*)&ts.tv_nsec); +#endif runtime·futex(addr, FUTEX_WAIT, val, &ts, nil, 0); } diff --git a/src/pkg/runtime/string.go b/src/pkg/runtime/string.go index c5b091748..69874e909 100644 --- a/src/pkg/runtime/string.go +++ b/src/pkg/runtime/string.go @@ -39,22 +39,18 @@ func concatstrings(a []string) string { return s } -//go:nosplit func concatstring2(a [2]string) string { return concatstrings(a[:]) } -//go:nosplit func concatstring3(a [3]string) string { return concatstrings(a[:]) } -//go:nosplit func concatstring4(a [4]string) string { return concatstrings(a[:]) } -//go:nosplit func concatstring5(a [5]string) string { return concatstrings(a[:]) } diff --git a/test/nosplit.go b/test/nosplit.go index de279efdd..b5399ad38 100644 --- a/test/nosplit.go +++ b/test/nosplit.go @@ -126,8 +126,9 @@ main 136 nosplit; REJECT # Calling a nosplit function from a nosplit function requires # having room for the saved caller PC and the called frame. # Because ARM doesn't save LR in the leaf, it gets an extra 4 bytes. +# Because Power64 doesn't save LR in the leaf, it gets an extra 8 bytes. main 112 nosplit call f; f 0 nosplit -main 116 nosplit call f; f 0 nosplit; REJECT amd64 +main 116 nosplit call f; f 0 nosplit main 120 nosplit call f; f 0 nosplit; REJECT amd64 main 124 nosplit call f; f 0 nosplit; REJECT amd64 386 main 128 nosplit call f; f 0 nosplit; REJECT @@ -136,8 +137,8 @@ main 136 nosplit call f; f 0 nosplit; REJECT # Calling a splitting function from a nosplit function requires # having room for the saved caller PC of the call but also the -# saved caller PC for the call to morestack. Again the ARM works -# in less space. +# saved caller PC for the call to morestack. +# Again the ARM and Power64 work in less space. main 104 nosplit call f; f 0 call f main 108 nosplit call f; f 0 call f main 112 nosplit call f; f 0 call f; REJECT amd64 @@ -235,7 +236,7 @@ TestCases: switch goarch { case "power64", "power64le": ptrSize = 8 - fmt.Fprintf(&buf, "#define CALL BL\n#define REGISTER (R0)\n#define RET RETURN\n") + fmt.Fprintf(&buf, "#define CALL BL\n#define REGISTER (CTR)\n#define RET RETURN\n") case "arm": fmt.Fprintf(&buf, "#define CALL BL\n#define REGISTER (R0)\n") case "amd64": |