aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/internal/obj/objfile.go
diff options
context:
space:
mode:
authorKatie Hockman <katie@golang.org>2020-12-14 10:03:05 -0500
committerKatie Hockman <katie@golang.org>2020-12-14 10:06:13 -0500
commit0345ede87ee12698988973884cfc0fd3d499dffd (patch)
tree7123cff141ee5661208d2f5f437b8f5252ac7f6a /src/cmd/internal/obj/objfile.go
parent4651d6b267818b0e0d128a5443289717c4bb8cbc (diff)
parent0a02371b0576964e81c3b40d328db9a3ef3b031b (diff)
downloadgo-0345ede87ee12698988973884cfc0fd3d499dffd.tar.xz
[dev.fuzz] all: merge master into dev.fuzz
Change-Id: I5d8c8329ccc9d747bd81ade6b1cb7cb8ae2e94b2
Diffstat (limited to 'src/cmd/internal/obj/objfile.go')
-rw-r--r--src/cmd/internal/obj/objfile.go220
1 files changed, 167 insertions, 53 deletions
diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go
index 7bc4f4992e..bb58b4f0c2 100644
--- a/src/cmd/internal/obj/objfile.go
+++ b/src/cmd/internal/obj/objfile.go
@@ -16,6 +16,8 @@ import (
"encoding/binary"
"fmt"
"io"
+ "log"
+ "os"
"path/filepath"
"sort"
"strings"
@@ -147,14 +149,20 @@ func WriteObjFile(ctxt *Link, b *bio.Writer) {
// Data indexes
h.Offsets[goobj.BlkDataIdx] = w.Offset()
- dataOff := uint32(0)
+ dataOff := int64(0)
for _, list := range lists {
for _, s := range list {
- w.Uint32(dataOff)
- dataOff += uint32(len(s.P))
+ w.Uint32(uint32(dataOff))
+ dataOff += int64(len(s.P))
+ if file := s.File(); file != nil {
+ dataOff += int64(file.Size)
+ }
}
}
- w.Uint32(dataOff)
+ if int64(uint32(dataOff)) != dataOff {
+ log.Fatalf("data too large")
+ }
+ w.Uint32(uint32(dataOff))
// Relocs
h.Offsets[goobj.BlkReloc] = w.Offset()
@@ -179,14 +187,21 @@ func WriteObjFile(ctxt *Link, b *bio.Writer) {
for _, list := range lists {
for _, s := range list {
w.Bytes(s.P)
+ if file := s.File(); file != nil {
+ w.writeFile(ctxt, file)
+ }
}
}
// Pcdata
h.Offsets[goobj.BlkPcdata] = w.Offset()
for _, s := range ctxt.Text { // iteration order must match genFuncInfoSyms
- if s.Func != nil {
- pc := &s.Func.Pcln
+ // Because of the phase order, it's possible that we try to write an invalid
+ // object file, and the Pcln variables haven't been filled in. As such, we
+ // need to check that Pcsp exists, and assume the other pcln variables exist
+ // as well. Tests like test/fixedbugs/issue22200.go demonstrate this issue.
+ if fn := s.Func(); fn != nil && fn.Pcln.Pcsp != nil {
+ pc := &fn.Pcln
w.Bytes(pc.Pcsp.P)
w.Bytes(pc.Pcfile.P)
w.Bytes(pc.Pcline.P)
@@ -214,6 +229,7 @@ func WriteObjFile(ctxt *Link, b *bio.Writer) {
type writer struct {
*goobj.Writer
+ filebuf []byte
ctxt *Link
pkgpath string // the package import path (escaped), "" if unknown
pkglist []string // list of packages referenced, indexed by ctxt.pkgIdx
@@ -228,6 +244,35 @@ func (w *writer) init() {
}
}
+func (w *writer) writeFile(ctxt *Link, file *FileInfo) {
+ f, err := os.Open(file.Name)
+ if err != nil {
+ ctxt.Diag("%v", err)
+ return
+ }
+ defer f.Close()
+ if w.filebuf == nil {
+ w.filebuf = make([]byte, 1024)
+ }
+ buf := w.filebuf
+ written := int64(0)
+ for {
+ n, err := f.Read(buf)
+ w.Bytes(buf[:n])
+ written += int64(n)
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ ctxt.Diag("%v", err)
+ return
+ }
+ }
+ if written != file.Size {
+ ctxt.Diag("copy %s: unexpected length %d != %d", file.Name, written, file.Size)
+ }
+}
+
func (w *writer) StringTable() {
w.AddString("")
for _, p := range w.ctxt.Imports {
@@ -257,6 +302,10 @@ func (w *writer) StringTable() {
}
}
+// cutoff is the maximum data section size permitted by the linker
+// (see issue #9862).
+const cutoff = int64(2e9) // 2 GB (or so; looks better in errors than 2^31)
+
func (w *writer) Sym(s *LSym) {
abi := uint16(s.ABI())
if s.Static() {
@@ -299,8 +348,8 @@ func (w *writer) Sym(s *LSym) {
name = filepath.ToSlash(name)
}
var align uint32
- if s.Func != nil {
- align = uint32(s.Func.Align)
+ if fn := s.Func(); fn != nil {
+ align = uint32(fn.Align)
}
if s.ContentAddressable() {
// We generally assume data symbols are natually aligned,
@@ -321,6 +370,9 @@ func (w *writer) Sym(s *LSym) {
// don't bother setting align to 1.
}
}
+ if s.Size > cutoff {
+ w.ctxt.Diag("%s: symbol too large (%d bytes > %d bytes)", s.Name, s.Size, cutoff)
+ }
var o goobj.Sym
o.SetName(name, w.Writer)
o.SetABI(abi)
@@ -372,10 +424,29 @@ func contentHash64(s *LSym) goobj.Hash64Type {
// hashed symbols.
func (w *writer) contentHash(s *LSym) goobj.HashType {
h := sha1.New()
+ var tmp [14]byte
+
+ // Include the size of the symbol in the hash.
+ // This preserves the length of symbols, preventing the following two symbols
+ // from hashing the same:
+ //
+ // [2]int{1,2} ≠ [10]int{1,2,0,0,0...}
+ //
+ // In this case, if the smaller symbol is alive, the larger is not kept unless
+ // needed.
+ binary.LittleEndian.PutUint64(tmp[:8], uint64(s.Size))
+ h.Write(tmp[:8])
+
+ // Don't dedup type symbols with others, as they are in a different
+ // section.
+ if strings.HasPrefix(s.Name, "type.") {
+ h.Write([]byte{'T'})
+ } else {
+ h.Write([]byte{0})
+ }
// The compiler trims trailing zeros _sometimes_. We just do
// it always.
h.Write(bytes.TrimRight(s.P, "\x00"))
- var tmp [14]byte
for i := range s.R {
r := &s.R[i]
binary.LittleEndian.PutUint32(tmp[:4], uint32(r.Off))
@@ -447,25 +518,41 @@ func (w *writer) Aux(s *LSym) {
if s.Gotype != nil {
w.aux1(goobj.AuxGotype, s.Gotype)
}
- if s.Func != nil {
- w.aux1(goobj.AuxFuncInfo, s.Func.FuncInfoSym)
+ if fn := s.Func(); fn != nil {
+ w.aux1(goobj.AuxFuncInfo, fn.FuncInfoSym)
- for _, d := range s.Func.Pcln.Funcdata {
+ for _, d := range fn.Pcln.Funcdata {
w.aux1(goobj.AuxFuncdata, d)
}
- if s.Func.dwarfInfoSym != nil && s.Func.dwarfInfoSym.Size != 0 {
- w.aux1(goobj.AuxDwarfInfo, s.Func.dwarfInfoSym)
+ if fn.dwarfInfoSym != nil && fn.dwarfInfoSym.Size != 0 {
+ w.aux1(goobj.AuxDwarfInfo, fn.dwarfInfoSym)
}
- if s.Func.dwarfLocSym != nil && s.Func.dwarfLocSym.Size != 0 {
- w.aux1(goobj.AuxDwarfLoc, s.Func.dwarfLocSym)
+ if fn.dwarfLocSym != nil && fn.dwarfLocSym.Size != 0 {
+ w.aux1(goobj.AuxDwarfLoc, fn.dwarfLocSym)
}
- if s.Func.dwarfRangesSym != nil && s.Func.dwarfRangesSym.Size != 0 {
- w.aux1(goobj.AuxDwarfRanges, s.Func.dwarfRangesSym)
+ if fn.dwarfRangesSym != nil && fn.dwarfRangesSym.Size != 0 {
+ w.aux1(goobj.AuxDwarfRanges, fn.dwarfRangesSym)
}
- if s.Func.dwarfDebugLinesSym != nil && s.Func.dwarfDebugLinesSym.Size != 0 {
- w.aux1(goobj.AuxDwarfLines, s.Func.dwarfDebugLinesSym)
+ if fn.dwarfDebugLinesSym != nil && fn.dwarfDebugLinesSym.Size != 0 {
+ w.aux1(goobj.AuxDwarfLines, fn.dwarfDebugLinesSym)
}
+ if fn.Pcln.Pcsp != nil && fn.Pcln.Pcsp.Size != 0 {
+ w.aux1(goobj.AuxPcsp, fn.Pcln.Pcsp)
+ }
+ if fn.Pcln.Pcfile != nil && fn.Pcln.Pcfile.Size != 0 {
+ w.aux1(goobj.AuxPcfile, fn.Pcln.Pcfile)
+ }
+ if fn.Pcln.Pcline != nil && fn.Pcln.Pcline.Size != 0 {
+ w.aux1(goobj.AuxPcline, fn.Pcln.Pcline)
+ }
+ if fn.Pcln.Pcinline != nil && fn.Pcln.Pcinline.Size != 0 {
+ w.aux1(goobj.AuxPcinline, fn.Pcln.Pcinline)
+ }
+ for _, pcSym := range fn.Pcln.Pcdata {
+ w.aux1(goobj.AuxPcdata, pcSym)
+ }
+
}
}
@@ -532,21 +619,34 @@ func nAuxSym(s *LSym) int {
if s.Gotype != nil {
n++
}
- if s.Func != nil {
+ if fn := s.Func(); fn != nil {
// FuncInfo is an aux symbol, each Funcdata is an aux symbol
- n += 1 + len(s.Func.Pcln.Funcdata)
- if s.Func.dwarfInfoSym != nil && s.Func.dwarfInfoSym.Size != 0 {
+ n += 1 + len(fn.Pcln.Funcdata)
+ if fn.dwarfInfoSym != nil && fn.dwarfInfoSym.Size != 0 {
+ n++
+ }
+ if fn.dwarfLocSym != nil && fn.dwarfLocSym.Size != 0 {
+ n++
+ }
+ if fn.dwarfRangesSym != nil && fn.dwarfRangesSym.Size != 0 {
n++
}
- if s.Func.dwarfLocSym != nil && s.Func.dwarfLocSym.Size != 0 {
+ if fn.dwarfDebugLinesSym != nil && fn.dwarfDebugLinesSym.Size != 0 {
n++
}
- if s.Func.dwarfRangesSym != nil && s.Func.dwarfRangesSym.Size != 0 {
+ if fn.Pcln.Pcsp != nil && fn.Pcln.Pcsp.Size != 0 {
n++
}
- if s.Func.dwarfDebugLinesSym != nil && s.Func.dwarfDebugLinesSym.Size != 0 {
+ if fn.Pcln.Pcfile != nil && fn.Pcln.Pcfile.Size != 0 {
n++
}
+ if fn.Pcln.Pcline != nil && fn.Pcln.Pcline.Size != 0 {
+ n++
+ }
+ if fn.Pcln.Pcinline != nil && fn.Pcln.Pcinline.Size != 0 {
+ n++
+ }
+ n += len(fn.Pcln.Pcdata)
}
return n
}
@@ -554,33 +654,38 @@ func nAuxSym(s *LSym) int {
// generate symbols for FuncInfo.
func genFuncInfoSyms(ctxt *Link) {
infosyms := make([]*LSym, 0, len(ctxt.Text))
- var pcdataoff uint32
+ hashedsyms := make([]*LSym, 0, 4*len(ctxt.Text))
+ preparePcSym := func(s *LSym) *LSym {
+ if s == nil {
+ return s
+ }
+ s.PkgIdx = goobj.PkgIdxHashed
+ s.SymIdx = int32(len(hashedsyms) + len(ctxt.hasheddefs))
+ s.Set(AttrIndexed, true)
+ hashedsyms = append(hashedsyms, s)
+ return s
+ }
var b bytes.Buffer
symidx := int32(len(ctxt.defs))
for _, s := range ctxt.Text {
- if s.Func == nil {
+ fn := s.Func()
+ if fn == nil {
continue
}
o := goobj.FuncInfo{
- Args: uint32(s.Func.Args),
- Locals: uint32(s.Func.Locals),
- FuncID: objabi.FuncID(s.Func.FuncID),
+ Args: uint32(fn.Args),
+ Locals: uint32(fn.Locals),
+ FuncID: objabi.FuncID(fn.FuncID),
}
- pc := &s.Func.Pcln
- o.Pcsp = pcdataoff
- pcdataoff += uint32(len(pc.Pcsp.P))
- o.Pcfile = pcdataoff
- pcdataoff += uint32(len(pc.Pcfile.P))
- o.Pcline = pcdataoff
- pcdataoff += uint32(len(pc.Pcline.P))
- o.Pcinline = pcdataoff
- pcdataoff += uint32(len(pc.Pcinline.P))
- o.Pcdata = make([]uint32, len(pc.Pcdata))
- for i, pcd := range pc.Pcdata {
- o.Pcdata[i] = pcdataoff
- pcdataoff += uint32(len(pcd.P))
+ pc := &fn.Pcln
+ o.Pcsp = makeSymRef(preparePcSym(pc.Pcsp))
+ o.Pcfile = makeSymRef(preparePcSym(pc.Pcfile))
+ o.Pcline = makeSymRef(preparePcSym(pc.Pcline))
+ o.Pcinline = makeSymRef(preparePcSym(pc.Pcinline))
+ o.Pcdata = make([]goobj.SymRef, len(pc.Pcdata))
+ for i, pcSym := range pc.Pcdata {
+ o.Pcdata[i] = makeSymRef(preparePcSym(pcSym))
}
- o.PcdataEnd = pcdataoff
o.Funcdataoff = make([]uint32, len(pc.Funcdataoff))
for i, x := range pc.Funcdataoff {
o.Funcdataoff[i] = uint32(x)
@@ -614,10 +719,10 @@ func genFuncInfoSyms(ctxt *Link) {
isym.Set(AttrIndexed, true)
symidx++
infosyms = append(infosyms, isym)
- s.Func.FuncInfoSym = isym
+ fn.FuncInfoSym = isym
b.Reset()
- dwsyms := []*LSym{s.Func.dwarfRangesSym, s.Func.dwarfLocSym, s.Func.dwarfDebugLinesSym, s.Func.dwarfInfoSym}
+ dwsyms := []*LSym{fn.dwarfRangesSym, fn.dwarfLocSym, fn.dwarfDebugLinesSym, fn.dwarfInfoSym}
for _, s := range dwsyms {
if s == nil || s.Size == 0 {
continue
@@ -630,9 +735,9 @@ func genFuncInfoSyms(ctxt *Link) {
}
}
ctxt.defs = append(ctxt.defs, infosyms...)
+ ctxt.hasheddefs = append(ctxt.hasheddefs, hashedsyms...)
}
-// debugDumpAux is a dumper for selected aux symbols.
func writeAuxSymDebug(ctxt *Link, par *LSym, aux *LSym) {
// Most aux symbols (ex: funcdata) are not interesting--
// pick out just the DWARF ones for now.
@@ -663,7 +768,11 @@ func (ctxt *Link) writeSymDebug(s *LSym) {
}
func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) {
- fmt.Fprintf(ctxt.Bso, "%s ", name)
+ ver := ""
+ if ctxt.Debugasm > 1 {
+ ver = fmt.Sprintf("<%d>", s.ABI())
+ }
+ fmt.Fprintf(ctxt.Bso, "%s%s ", name, ver)
if s.Type != 0 {
fmt.Fprintf(ctxt.Bso, "%v ", s.Type)
}
@@ -684,14 +793,15 @@ func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) {
}
fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
if s.Type == objabi.STEXT {
- fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x funcid=%#x", uint64(s.Func.Args), uint64(s.Func.Locals), uint64(s.Func.FuncID))
+ fn := s.Func()
+ fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x funcid=%#x", uint64(fn.Args), uint64(fn.Locals), uint64(fn.FuncID))
if s.Leaf() {
fmt.Fprintf(ctxt.Bso, " leaf")
}
}
fmt.Fprintf(ctxt.Bso, "\n")
if s.Type == objabi.STEXT {
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
fmt.Fprintf(ctxt.Bso, "\t%#04x ", uint(int(p.Pc)))
if ctxt.Debugasm > 1 {
io.WriteString(ctxt.Bso, p.String())
@@ -726,15 +836,19 @@ func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) {
sort.Sort(relocByOff(s.R)) // generate stable output
for _, r := range s.R {
name := ""
+ ver := ""
if r.Sym != nil {
name = r.Sym.Name
+ if ctxt.Debugasm > 1 {
+ ver = fmt.Sprintf("<%d>", r.Sym.ABI())
+ }
} else if r.Type == objabi.R_TLS_LE {
name = "TLS"
}
if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) {
- fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(r.Add))
+ fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s%s+%x\n", int(r.Off), r.Siz, r.Type, name, ver, uint64(r.Add))
} else {
- fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, r.Add)
+ fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s%s+%d\n", int(r.Off), r.Siz, r.Type, name, ver, r.Add)
}
}
}