aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/internal/obj
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2021-01-28 15:21:33 -0500
committerRuss Cox <rsc@golang.org>2021-02-19 00:02:30 +0000
commit4dd77bdc910494adcd57fe9d87cd46f72d8d8985 (patch)
treef74e8882e580d3f5ef0e87826f63ca5648019627 /src/cmd/internal/obj
parentaa0388f2ed937669e9f938da8a65c75ea144ebfd (diff)
downloadgo-4dd77bdc910494adcd57fe9d87cd46f72d8d8985.tar.xz
cmd/asm, cmd/link, runtime: introduce FuncInfo flag bits
The runtime traceback code has its own definition of which functions mark the top frame of a stack, separate from the TOPFRAME bits that exist in the assembly and are passed along in DWARF information. It's error-prone and redundant to have two different sources of truth. This CL provides the actual TOPFRAME bits to the runtime, so that the runtime can use those bits instead of reinventing its own category. This CL also adds a new bit, SPWRITE, which marks functions that write directly to SP (anything but adding and subtracting constants). Such functions must stop a traceback, because the traceback has no way to rederive the SP on entry. Again, the runtime has its own definition which is mostly correct, but also missing some functions. During ordinary goroutine context switches, such functions do not appear on the stack, so the incompleteness in the runtime usually doesn't matter. But profiling signals can arrive at any moment, and the runtime may crash during traceback if it attempts to unwind an SP-writing frame and gets out-of-sync with the actual stack. The runtime contains code to try to detect likely candidates but again it is incomplete. Deriving the SPWRITE bit automatically from the actual assembly code provides the complete truth, and passing it to the runtime lets the runtime use it. This CL is part of a stack adding windows/arm64 support (#36439), intended to land in the Go 1.17 cycle. This CL is, however, not windows/arm64-specific. It is cleanup meant to make the port (and future ports) easier. Change-Id: I227f53b23ac5b3dabfcc5e8ee3f00df4e113cf58 Reviewed-on: https://go-review.googlesource.com/c/go/+/288800 Trust: Russ Cox <rsc@golang.org> Trust: Jason A. Donenfeld <Jason@zx2c4.com> Reviewed-by: Cherry Zhang <cherryyz@google.com> Reviewed-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'src/cmd/internal/obj')
-rw-r--r--src/cmd/internal/obj/arm/obj5.go16
-rw-r--r--src/cmd/internal/obj/arm64/obj7.go16
-rw-r--r--src/cmd/internal/obj/link.go23
-rw-r--r--src/cmd/internal/obj/mips/obj0.go16
-rw-r--r--src/cmd/internal/obj/objfile.go12
-rw-r--r--src/cmd/internal/obj/plist.go10
-rw-r--r--src/cmd/internal/obj/ppc64/obj9.go16
-rw-r--r--src/cmd/internal/obj/riscv/obj.go16
-rw-r--r--src/cmd/internal/obj/s390x/objz.go16
-rw-r--r--src/cmd/internal/obj/util.go2
-rw-r--r--src/cmd/internal/obj/x86/obj6.go15
11 files changed, 141 insertions, 17 deletions
diff --git a/src/cmd/internal/obj/arm/obj5.go b/src/cmd/internal/obj/arm/obj5.go
index 29d3a5867d..7de04302d9 100644
--- a/src/cmd/internal/obj/arm/obj5.go
+++ b/src/cmd/internal/obj/arm/obj5.go
@@ -34,6 +34,7 @@ import (
"cmd/internal/obj"
"cmd/internal/objabi"
"cmd/internal/sys"
+ "log"
)
var progedit_tlsfallback *obj.LSym
@@ -613,6 +614,21 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.From.Reg = REGSP
}
}
+
+ if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
+ f := c.cursym.Func()
+ if f.FuncFlag&objabi.FuncFlag_SPWRITE == 0 {
+ c.cursym.Func().FuncFlag |= objabi.FuncFlag_SPWRITE
+ if ctxt.Debugvlog || !ctxt.IsAsm {
+ ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p)
+ if !ctxt.IsAsm {
+ ctxt.Diag("invalid auto-SPWRITE in non-assembly")
+ ctxt.DiagFlush()
+ log.Fatalf("bad SPWRITE")
+ }
+ }
+ }
+ }
}
}
diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go
index 0baf51973a..3b88543852 100644
--- a/src/cmd/internal/obj/arm64/obj7.go
+++ b/src/cmd/internal/obj/arm64/obj7.go
@@ -35,6 +35,7 @@ import (
"cmd/internal/objabi"
"cmd/internal/src"
"cmd/internal/sys"
+ "log"
"math"
)
@@ -970,6 +971,21 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p = q5
}
}
+
+ if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
+ f := c.cursym.Func()
+ if f.FuncFlag&objabi.FuncFlag_SPWRITE == 0 {
+ c.cursym.Func().FuncFlag |= objabi.FuncFlag_SPWRITE
+ if ctxt.Debugvlog || !ctxt.IsAsm {
+ ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p)
+ if !ctxt.IsAsm {
+ ctxt.Diag("invalid auto-SPWRITE in non-assembly")
+ ctxt.DiagFlush()
+ log.Fatalf("bad SPWRITE")
+ }
+ }
+ }
+ }
}
}
diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go
index 8206902328..a48db3bdc8 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -454,6 +454,7 @@ type FuncInfo struct {
Locals int32
Align int32
FuncID objabi.FuncID
+ FuncFlag objabi.FuncFlag
Text *Prog
Autot map[*LSym]struct{}
Pcln Pcln
@@ -619,10 +620,6 @@ const (
// target of an inline during compilation
AttrWasInlined
- // TopFrame means that this function is an entry point and unwinders should not
- // keep unwinding beyond this frame.
- AttrTopFrame
-
// Indexed indicates this symbol has been assigned with an index (when using the
// new object file format).
AttrIndexed
@@ -663,7 +660,6 @@ func (a *Attribute) NeedCtxt() bool { return a.load()&AttrNeedCtxt !=
func (a *Attribute) NoFrame() bool { return a.load()&AttrNoFrame != 0 }
func (a *Attribute) Static() bool { return a.load()&AttrStatic != 0 }
func (a *Attribute) WasInlined() bool { return a.load()&AttrWasInlined != 0 }
-func (a *Attribute) TopFrame() bool { return a.load()&AttrTopFrame != 0 }
func (a *Attribute) Indexed() bool { return a.load()&AttrIndexed != 0 }
func (a *Attribute) UsedInIface() bool { return a.load()&AttrUsedInIface != 0 }
func (a *Attribute) ContentAddressable() bool { return a.load()&AttrContentAddressable != 0 }
@@ -713,14 +709,13 @@ var textAttrStrings = [...]struct {
{bit: AttrNoFrame, s: "NOFRAME"},
{bit: AttrStatic, s: "STATIC"},
{bit: AttrWasInlined, s: ""},
- {bit: AttrTopFrame, s: "TOPFRAME"},
{bit: AttrIndexed, s: ""},
{bit: AttrContentAddressable, s: ""},
{bit: AttrABIWrapper, s: "ABIWRAPPER"},
}
-// TextAttrString formats a for printing in as part of a TEXT prog.
-func (a Attribute) TextAttrString() string {
+// String formats a for printing in as part of a TEXT prog.
+func (a Attribute) String() string {
var s string
for _, x := range textAttrStrings {
if a&x.bit != 0 {
@@ -746,6 +741,18 @@ func (a Attribute) TextAttrString() string {
return s
}
+// TextAttrString formats the symbol attributes for printing in as part of a TEXT prog.
+func (s *LSym) TextAttrString() string {
+ attr := s.Attribute.String()
+ if s.Func().FuncFlag&objabi.FuncFlag_TOPFRAME != 0 {
+ if attr != "" {
+ attr += "|"
+ }
+ attr += "TOPFRAME"
+ }
+ return attr
+}
+
func (s *LSym) String() string {
return s.Name
}
diff --git a/src/cmd/internal/obj/mips/obj0.go b/src/cmd/internal/obj/mips/obj0.go
index 135a8df3aa..91bba90d41 100644
--- a/src/cmd/internal/obj/mips/obj0.go
+++ b/src/cmd/internal/obj/mips/obj0.go
@@ -35,6 +35,7 @@ import (
"cmd/internal/sys"
"encoding/binary"
"fmt"
+ "log"
"math"
)
@@ -536,6 +537,21 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.From.Reg = REGSP
}
}
+
+ if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
+ f := c.cursym.Func()
+ if f.FuncFlag&objabi.FuncFlag_SPWRITE == 0 {
+ c.cursym.Func().FuncFlag |= objabi.FuncFlag_SPWRITE
+ if ctxt.Debugvlog || !ctxt.IsAsm {
+ ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p)
+ if !ctxt.IsAsm {
+ ctxt.Diag("invalid auto-SPWRITE in non-assembly")
+ ctxt.DiagFlush()
+ log.Fatalf("bad SPWRITE")
+ }
+ }
+ }
+ }
}
if c.ctxt.Arch.Family == sys.MIPS {
diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go
index bb58b4f0c2..85f0570e5d 100644
--- a/src/cmd/internal/obj/objfile.go
+++ b/src/cmd/internal/obj/objfile.go
@@ -330,9 +330,6 @@ func (w *writer) Sym(s *LSym) {
if s.ReflectMethod() {
flag |= goobj.SymFlagReflectMethod
}
- if s.TopFrame() {
- flag |= goobj.SymFlagTopFrame
- }
if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' && s.Type == objabi.SRODATA {
flag |= goobj.SymFlagGoType
}
@@ -673,9 +670,10 @@ func genFuncInfoSyms(ctxt *Link) {
continue
}
o := goobj.FuncInfo{
- Args: uint32(fn.Args),
- Locals: uint32(fn.Locals),
- FuncID: objabi.FuncID(fn.FuncID),
+ Args: uint32(fn.Args),
+ Locals: uint32(fn.Locals),
+ FuncID: fn.FuncID,
+ FuncFlag: fn.FuncFlag,
}
pc := &fn.Pcln
o.Pcsp = makeSymRef(preparePcSym(pc.Pcsp))
@@ -788,7 +786,7 @@ func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) {
if s.NoSplit() {
fmt.Fprintf(ctxt.Bso, "nosplit ")
}
- if s.TopFrame() {
+ if s.Func() != nil && s.Func().FuncFlag&objabi.FuncFlag_TOPFRAME != 0 {
fmt.Fprintf(ctxt.Bso, "topframe ")
}
fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
diff --git a/src/cmd/internal/obj/plist.go b/src/cmd/internal/obj/plist.go
index 679ce7eb8f..177083261c 100644
--- a/src/cmd/internal/obj/plist.go
+++ b/src/cmd/internal/obj/plist.go
@@ -134,6 +134,7 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) {
}
name := strings.Replace(s.Name, "\"\"", ctxt.Pkgpath, -1)
s.Func().FuncID = objabi.GetFuncID(name, flag&WRAPPER != 0)
+ s.Func().FuncFlag = toFuncFlag(flag)
s.Set(AttrOnList, true)
s.Set(AttrDuplicateOK, flag&DUPOK != 0)
s.Set(AttrNoSplit, flag&NOSPLIT != 0)
@@ -142,7 +143,6 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) {
s.Set(AttrABIWrapper, flag&ABIWRAPPER != 0)
s.Set(AttrNeedCtxt, flag&NEEDCTXT != 0)
s.Set(AttrNoFrame, flag&NOFRAME != 0)
- s.Set(AttrTopFrame, flag&TOPFRAME != 0)
s.Type = objabi.STEXT
ctxt.Text = append(ctxt.Text, s)
@@ -150,6 +150,14 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) {
ctxt.dwarfSym(s)
}
+func toFuncFlag(flag int) objabi.FuncFlag {
+ var out objabi.FuncFlag
+ if flag&TOPFRAME != 0 {
+ out |= objabi.FuncFlag_TOPFRAME
+ }
+ return out
+}
+
func (ctxt *Link) Globl(s *LSym, size int64, flag int) {
if s.OnList() {
ctxt.Diag("symbol %s listed multiple times", s.Name)
diff --git a/src/cmd/internal/obj/ppc64/obj9.go b/src/cmd/internal/obj/ppc64/obj9.go
index fddf552156..a77be29cf0 100644
--- a/src/cmd/internal/obj/ppc64/obj9.go
+++ b/src/cmd/internal/obj/ppc64/obj9.go
@@ -34,6 +34,7 @@ import (
"cmd/internal/objabi"
"cmd/internal/src"
"cmd/internal/sys"
+ "log"
)
func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
@@ -984,6 +985,21 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.From.Reg = REGSP
}
}
+
+ if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 && p.As != ACMPU {
+ f := c.cursym.Func()
+ if f.FuncFlag&objabi.FuncFlag_SPWRITE == 0 {
+ c.cursym.Func().FuncFlag |= objabi.FuncFlag_SPWRITE
+ if ctxt.Debugvlog || !ctxt.IsAsm {
+ ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p)
+ if !ctxt.IsAsm {
+ ctxt.Diag("invalid auto-SPWRITE in non-assembly")
+ ctxt.DiagFlush()
+ log.Fatalf("bad SPWRITE")
+ }
+ }
+ }
+ }
}
}
diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go
index 5ef334dd6a..d104f1cfa5 100644
--- a/src/cmd/internal/obj/riscv/obj.go
+++ b/src/cmd/internal/obj/riscv/obj.go
@@ -25,6 +25,7 @@ import (
"cmd/internal/objabi"
"cmd/internal/sys"
"fmt"
+ "log"
)
func buildop(ctxt *obj.Link) {}
@@ -716,6 +717,21 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.Spadj = int32(-p.From.Offset)
}
}
+
+ if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
+ f := cursym.Func()
+ if f.FuncFlag&objabi.FuncFlag_SPWRITE == 0 {
+ f.FuncFlag |= objabi.FuncFlag_SPWRITE
+ if ctxt.Debugvlog || !ctxt.IsAsm {
+ ctxt.Logf("auto-SPWRITE: %s %v\n", cursym.Name, p)
+ if !ctxt.IsAsm {
+ ctxt.Diag("invalid auto-SPWRITE in non-assembly")
+ ctxt.DiagFlush()
+ log.Fatalf("bad SPWRITE")
+ }
+ }
+ }
+ }
}
// Rewrite MOV pseudo-instructions. This cannot be done in
diff --git a/src/cmd/internal/obj/s390x/objz.go b/src/cmd/internal/obj/s390x/objz.go
index 970cf827d6..a02c4fc17f 100644
--- a/src/cmd/internal/obj/s390x/objz.go
+++ b/src/cmd/internal/obj/s390x/objz.go
@@ -33,6 +33,7 @@ import (
"cmd/internal/obj"
"cmd/internal/objabi"
"cmd/internal/sys"
+ "log"
"math"
)
@@ -545,6 +546,21 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.From.Reg = REGSP
}
}
+
+ if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
+ f := c.cursym.Func()
+ if f.FuncFlag&objabi.FuncFlag_SPWRITE == 0 {
+ c.cursym.Func().FuncFlag |= objabi.FuncFlag_SPWRITE
+ if ctxt.Debugvlog || !ctxt.IsAsm {
+ ctxt.Logf("auto-SPWRITE: %s\n", c.cursym.Name)
+ if !ctxt.IsAsm {
+ ctxt.Diag("invalid auto-SPWRITE in non-assembly")
+ ctxt.DiagFlush()
+ log.Fatalf("bad SPWRITE")
+ }
+ }
+ }
+ }
}
if wasSplit {
c.stacksplitPost(pLast, pPre, pPreempt, autosize) // emit post part of split check
diff --git a/src/cmd/internal/obj/util.go b/src/cmd/internal/obj/util.go
index b9bacb7a22..1c34b4e833 100644
--- a/src/cmd/internal/obj/util.go
+++ b/src/cmd/internal/obj/util.go
@@ -187,7 +187,7 @@ func (p *Prog) WriteInstructionString(w io.Writer) {
// In short, print one of these two:
// TEXT foo(SB), DUPOK|NOSPLIT, $0
// TEXT foo(SB), $0
- s := p.From.Sym.Attribute.TextAttrString()
+ s := p.From.Sym.TextAttrString()
if s != "" {
fmt.Fprintf(w, "%s%s", sep, s)
sep = ", "
diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go
index 84de58a4c4..bc3a3b4bbe 100644
--- a/src/cmd/internal/obj/x86/obj6.go
+++ b/src/cmd/internal/obj/x86/obj6.go
@@ -35,6 +35,7 @@ import (
"cmd/internal/objabi"
"cmd/internal/src"
"cmd/internal/sys"
+ "log"
"math"
"strings"
)
@@ -839,6 +840,20 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
switch p.As {
default:
+ if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_SP && p.As != ACMPL && p.As != ACMPQ {
+ f := cursym.Func()
+ if f.FuncFlag&objabi.FuncFlag_SPWRITE == 0 {
+ f.FuncFlag |= objabi.FuncFlag_SPWRITE
+ if ctxt.Debugvlog || !ctxt.IsAsm {
+ ctxt.Logf("auto-SPWRITE: %s %v\n", cursym.Name, p)
+ if !ctxt.IsAsm {
+ ctxt.Diag("invalid auto-SPWRITE in non-assembly")
+ ctxt.DiagFlush()
+ log.Fatalf("bad SPWRITE")
+ }
+ }
+ }
+ }
continue
case APUSHL, APUSHFL: