[dev.power64] cmd/ld, runtime: detect, fix nosplit overflows

LGTM=minux
R=minux
CC=golang-codereviews
https://golang.org/cl/121690043
This commit is contained in:
Russ Cox 2014-08-14 15:29:37 -04:00
parent 6edd1c6d1a
commit ed68c7df55
4 changed files with 34 additions and 27 deletions

View File

@ -1026,7 +1026,7 @@ static LSym *newstack;
enum enum
{ {
HasLinkRegister = (thechar == '5'), HasLinkRegister = (thechar == '5' || thechar == '9'),
}; };
// TODO: Record enough information in new object files to // TODO: Record enough information in new object files to
@ -1035,7 +1035,7 @@ enum
static int static int
callsize(void) callsize(void)
{ {
if(thechar == '5') if(HasLinkRegister)
return 0; return 0;
return RegSize; return RegSize;
} }
@ -1046,9 +1046,6 @@ dostkcheck(void)
Chain ch; Chain ch;
LSym *s; LSym *s;
if(thechar == '9')
return;
morestack = linklookup(ctxt, "runtime.morestack", 0); morestack = linklookup(ctxt, "runtime.morestack", 0);
newstack = linklookup(ctxt, "runtime.newstack", 0); newstack = linklookup(ctxt, "runtime.newstack", 0);
@ -1072,19 +1069,19 @@ dostkcheck(void)
continue; continue;
if(s->nosplit) { if(s->nosplit) {
ctxt->cursym = s; ctxt->cursym = s;
ch.sym = s; ch.sym = s;
stkcheck(&ch, 0); stkcheck(&ch, 0);
} }
} }
for(s = ctxt->textp; s != nil; s = s->next) { for(s = ctxt->textp; s != nil; s = s->next) {
if(!s->nosplit) { if(!s->nosplit) {
ctxt->cursym = s; ctxt->cursym = s;
ch.sym = s; ch.sym = s;
stkcheck(&ch, 0); stkcheck(&ch, 0);
}
} }
} }
}
static int static int
stkcheck(Chain *up, int depth) stkcheck(Chain *up, int depth)
@ -1102,7 +1099,7 @@ stkcheck(Chain *up, int depth)
// function at top of safe zone once. // function at top of safe zone once.
if(limit == StackLimit-callsize()) { if(limit == StackLimit-callsize()) {
if(s->stkcheck) if(s->stkcheck)
return 0; return 0;
s->stkcheck = 1; s->stkcheck = 1;
} }
@ -1161,8 +1158,8 @@ stkcheck(Chain *up, int depth)
// to StackLimit beyond the frame size. // to StackLimit beyond the frame size.
if(strncmp(r->sym->name, "runtime.morestack", 17) == 0) { if(strncmp(r->sym->name, "runtime.morestack", 17) == 0) {
limit = StackLimit + s->locals; limit = StackLimit + s->locals;
if(thechar == '5') if(HasLinkRegister)
limit += 4; // saved LR limit += RegSize;
} }
break; break;
@ -1181,7 +1178,7 @@ stkcheck(Chain *up, int depth)
break; break;
} }
} }
} }
return 0; return 0;
} }
@ -1210,7 +1207,7 @@ stkprint(Chain *ch, int limit)
else else
print("\t%d\tguaranteed after split check in %s\n", ch->limit, name); print("\t%d\tguaranteed after split check in %s\n", ch->limit, name);
} else { } else {
stkprint(ch->up, ch->limit + (!HasLinkRegister)*PtrSize); stkprint(ch->up, ch->limit + (!HasLinkRegister)*RegSize);
if(!HasLinkRegister) if(!HasLinkRegister)
print("\t%d\ton entry to %s\n", ch->limit, name); print("\t%d\ton entry to %s\n", ch->limit, name);
} }

View File

@ -49,9 +49,22 @@ runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
runtime·futex(addr, FUTEX_WAIT, val, nil, nil, 0); runtime·futex(addr, FUTEX_WAIT, val, nil, nil, 0);
return; 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_nsec = 0;
ts.tv_sec = runtime·timediv(ns, 1000000000LL, (int32*)&ts.tv_nsec); ts.tv_sec = runtime·timediv(ns, 1000000000LL, (int32*)&ts.tv_nsec);
#endif
runtime·futex(addr, FUTEX_WAIT, val, &ts, nil, 0); runtime·futex(addr, FUTEX_WAIT, val, &ts, nil, 0);
} }

View File

@ -39,22 +39,18 @@ func concatstrings(a []string) string {
return s return s
} }
//go:nosplit
func concatstring2(a [2]string) string { func concatstring2(a [2]string) string {
return concatstrings(a[:]) return concatstrings(a[:])
} }
//go:nosplit
func concatstring3(a [3]string) string { func concatstring3(a [3]string) string {
return concatstrings(a[:]) return concatstrings(a[:])
} }
//go:nosplit
func concatstring4(a [4]string) string { func concatstring4(a [4]string) string {
return concatstrings(a[:]) return concatstrings(a[:])
} }
//go:nosplit
func concatstring5(a [5]string) string { func concatstring5(a [5]string) string {
return concatstrings(a[:]) return concatstrings(a[:])
} }

View File

@ -126,8 +126,9 @@ main 136 nosplit; REJECT
# Calling a nosplit function from a nosplit function requires # Calling a nosplit function from a nosplit function requires
# having room for the saved caller PC and the called frame. # 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 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 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 120 nosplit call f; f 0 nosplit; REJECT amd64
main 124 nosplit call f; f 0 nosplit; REJECT amd64 386 main 124 nosplit call f; f 0 nosplit; REJECT amd64 386
main 128 nosplit call f; f 0 nosplit; REJECT 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 # Calling a splitting function from a nosplit function requires
# having room for the saved caller PC of the call but also the # 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 # saved caller PC for the call to morestack.
# in less space. # Again the ARM and Power64 work in less space.
main 104 nosplit call f; f 0 call f main 104 nosplit call f; f 0 call f
main 108 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 main 112 nosplit call f; f 0 call f; REJECT amd64
@ -235,7 +236,7 @@ TestCases:
switch goarch { switch goarch {
case "power64", "power64le": case "power64", "power64le":
ptrSize = 8 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": case "arm":
fmt.Fprintf(&buf, "#define CALL BL\n#define REGISTER (R0)\n") fmt.Fprintf(&buf, "#define CALL BL\n#define REGISTER (R0)\n")
case "amd64": case "amd64":