Commit ca19e55f authored by Josh Bleecher Snyder's avatar Josh Bleecher Snyder

cmd/link: make stkcheck more flexible

stkcheck is flow-insensitive: It processes calls in PC order.
Since morestack was always the first call in a function,
it was a safe, conservative approximation to simply adjust stack
space as we went, recognizing morestack when it showed up.

Subsequent CLS will rearrange the function prologue;
morestack may no longer be the first call in a function.

Introducing flow-sensitivity to stkcheck would allow this,
and possibly allow a smaller stackguard.
It is also a high risk change and possibly expensive.

Instead, assume that all calls to morestack occur as
part of the function prologue, no matter where they
are located in the program text.

Updates #10587.

Change-Id: I4dcdd4256a980fc4bc433a68a10989ff57f7034f
Reviewed-on: https://go-review.googlesource.com/10496
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent 73d109c5
...@@ -1529,6 +1529,41 @@ func stkcheck(up *Chain, depth int) int { ...@@ -1529,6 +1529,41 @@ func stkcheck(up *Chain, depth int) int {
var ch Chain var ch Chain
ch.up = up ch.up = up
// Check for a call to morestack anywhere and treat it
// as occurring at function entry.
// The decision about whether to call morestack occurs
// in the prolog, but the call site is near the end
// of the function on some architectures.
// This is needed because the stack check is flow-insensitive,
// so it incorrectly thinks the call to morestack happens wherever it shows up.
// This check will be wrong if there are any hand-inserted calls to morestack.
// There are not any now, nor should there ever be.
for _, r := range s.R {
if r.Sym == nil || !strings.HasPrefix(r.Sym.Name, "runtime.morestack") {
continue
}
// Ignore non-calls to morestack, such as the jump to morestack
// found in the implementation of morestack_noctxt.
switch r.Type {
default:
continue
case obj.R_CALL, obj.R_CALLARM, obj.R_CALLARM64, obj.R_CALLPOWER:
}
// Ensure we have enough stack to call morestack.
ch.limit = limit - callsize()
ch.sym = r.Sym
if stkcheck(&ch, depth+1) < 0 {
return -1
}
// Bump up the limit.
limit = int(obj.StackLimit + s.Locals)
if haslinkregister() {
limit += Thearch.Regsize
}
break // there can be only one
}
// Walk through sp adjustments in function, consuming relocs. // Walk through sp adjustments in function, consuming relocs.
ri := 0 ri := 0
...@@ -1551,23 +1586,18 @@ func stkcheck(up *Chain, depth int) int { ...@@ -1551,23 +1586,18 @@ func stkcheck(up *Chain, depth int) int {
switch r.Type { switch r.Type {
// Direct call. // Direct call.
case obj.R_CALL, obj.R_CALLARM, obj.R_CALLARM64, obj.R_CALLPOWER: case obj.R_CALL, obj.R_CALLARM, obj.R_CALLARM64, obj.R_CALLPOWER:
ch.limit = int(int32(limit) - pcsp.value - int32(callsize())) // We handled calls to morestack already.
if strings.HasPrefix(r.Sym.Name, "runtime.morestack") {
continue
}
ch.limit = int(int32(limit) - pcsp.value - int32(callsize()))
ch.sym = r.Sym ch.sym = r.Sym
if stkcheck(&ch, depth+1) < 0 { if stkcheck(&ch, depth+1) < 0 {
return -1 return -1
} }
// If this is a call to morestack, we've just raised our limit back // Indirect call. Assume it is a call to a splitting function,
// to StackLimit beyond the frame size.
if strings.HasPrefix(r.Sym.Name, "runtime.morestack") {
limit = int(obj.StackLimit + s.Locals)
if haslinkregister() {
limit += Thearch.Regsize
}
}
// Indirect call. Assume it is a call to a splitting function,
// so we have to make sure it can call morestack. // so we have to make sure it can call morestack.
// Arrange the data structures to report both calls, so that // Arrange the data structures to report both calls, so that
// if there is an error, stkprint shows all the steps involved. // if there is an error, stkprint shows all the steps involved.
......
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