From 014f3e1e094c4a173ce503e5dfe1bc0619f2f4a8 Mon Sep 17 00:00:00 2001 From: Shahar Kohanim Date: Thu, 31 Mar 2016 12:59:05 +0300 Subject: [PATCH] cmd/internal/obj: more idiomatic object writer Change-Id: I41722ee605ea76a6b52e8a7e1e10f2293cef1a7a Reviewed-on: https://go-review.googlesource.com/21371 Reviewed-by: David Crawshaw --- src/cmd/internal/obj/link.go | 1 - src/cmd/internal/obj/objfile.go | 463 +++++++++++++++++--------------- 2 files changed, 243 insertions(+), 221 deletions(-) diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index cfe7c958cdd..24f028f7378 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -658,7 +658,6 @@ type Link struct { Textp *LSym Etextp *LSym Errors int - RefsWritten int // Number of symbol references already written to object file. // state for writing objects Text []*LSym diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go index aba832f27b4..a8d86b52cdf 100644 --- a/src/cmd/internal/obj/objfile.go +++ b/src/cmd/internal/obj/objfile.go @@ -108,6 +108,7 @@ package obj import ( + "bufio" "fmt" "log" "path/filepath" @@ -120,7 +121,7 @@ import ( // does not write out object files. func Writeobjdirect(ctxt *Link, b *Biobuf) { Flushplist(ctxt) - Writeobjfile(ctxt, b) + WriteObjFile(ctxt, b) } func Flushplist(ctxt *Link) { @@ -309,18 +310,32 @@ func flushplist(ctxt *Link, freeProgs bool) { } } -type sectionLengths struct { - data int - reloc int - pcdata int - autom int - funcdata int - file int +// objWriter writes Go object files. +type objWriter struct { + wr *bufio.Writer + ctxt *Link + // Temporary buffer for zigzag int writing. + varintbuf [10]uint8 + + // Provide the the index of a symbol reference by symbol name. + // One map for versioned symbols and one for unversioned symbols. + // Used for deduplicating the symbol reference list. + refIdx map[string]int + vrefIdx map[string]int + + // Number of objects written of each type. + nRefs int + nData int + nReloc int + nPcdata int + nAutom int + nFuncdata int + nFile int } -func (l *sectionLengths) add(s *LSym) { - l.data += len(s.P) - l.reloc += len(s.R) +func (w *objWriter) addLengths(s *LSym) { + w.nData += len(s.P) + w.nReloc += len(s.R) if s.Type != STEXT { return @@ -336,102 +351,106 @@ func (l *sectionLengths) add(s *LSym) { data += len(pc.Pcdata[i].P) } - l.data += data - l.pcdata += len(pc.Pcdata) + w.nData += data + w.nPcdata += len(pc.Pcdata) autom := 0 for a := s.Autom; a != nil; a = a.Link { autom++ } - l.autom += autom - l.funcdata += len(pc.Funcdataoff) - l.file += len(pc.File) + w.nAutom += autom + w.nFuncdata += len(pc.Funcdataoff) + w.nFile += len(pc.File) } -func wrlengths(b *Biobuf, sl sectionLengths) { - wrint(b, int64(sl.data)) - wrint(b, int64(sl.reloc)) - wrint(b, int64(sl.pcdata)) - wrint(b, int64(sl.autom)) - wrint(b, int64(sl.funcdata)) - wrint(b, int64(sl.file)) +func (w *objWriter) writeLengths() { + w.writeInt(int64(w.nData)) + w.writeInt(int64(w.nReloc)) + w.writeInt(int64(w.nPcdata)) + w.writeInt(int64(w.nAutom)) + w.writeInt(int64(w.nFuncdata)) + w.writeInt(int64(w.nFile)) } -func Writeobjfile(ctxt *Link, b *Biobuf) { - // Emit header. - Bputc(b, 0) - - Bputc(b, 0) - fmt.Fprintf(b, "go13ld") - Bputc(b, 1) // version - - // Emit autolib. - for _, pkg := range ctxt.Imports { - wrstring(b, pkg) +func newObjWriter(ctxt *Link, b *Biobuf) *objWriter { + return &objWriter{ + ctxt: ctxt, + wr: b.w, + vrefIdx: make(map[string]int), + refIdx: make(map[string]int), } - wrstring(b, "") +} - var lengths sectionLengths +func WriteObjFile(ctxt *Link, b *Biobuf) { + w := newObjWriter(ctxt, b) - // Emit symbol references. + // Magic header + w.wr.WriteString("\x00\x00go13ld") + + // Version + w.wr.WriteByte(1) + + // Autolib + for _, pkg := range ctxt.Imports { + w.writeString(pkg) + } + w.writeString("") + + // Symbol references for _, s := range ctxt.Text { - writerefs(ctxt, b, s) - lengths.add(s) + w.writeRefs(s) + w.addLengths(s) } for _, s := range ctxt.Data { - writerefs(ctxt, b, s) - lengths.add(s) + w.writeRefs(s) + w.addLengths(s) } - Bputc(b, 0xff) + // End symbol references + w.wr.WriteByte(0xff) - wrlengths(b, lengths) + // Lengths + w.writeLengths() - // Write data block + // Data block for _, s := range ctxt.Text { - b.w.Write(s.P) + w.wr.Write(s.P) pc := s.Pcln - b.w.Write(pc.Pcsp.P) - b.w.Write(pc.Pcfile.P) - b.w.Write(pc.Pcline.P) + w.wr.Write(pc.Pcsp.P) + w.wr.Write(pc.Pcfile.P) + w.wr.Write(pc.Pcline.P) for i := 0; i < len(pc.Pcdata); i++ { - b.w.Write(pc.Pcdata[i].P) + w.wr.Write(pc.Pcdata[i].P) } } for _, s := range ctxt.Data { - b.w.Write(s.P) + w.wr.Write(s.P) } - // Emit symbols. + // Symbols for _, s := range ctxt.Text { - writesym(ctxt, b, s) + w.writeSym(s) } for _, s := range ctxt.Data { - writesym(ctxt, b, s) + w.writeSym(s) } - // Emit footer. - Bputc(b, 0xff) - - Bputc(b, 0xff) - fmt.Fprintf(b, "go13ld") + // Magic footer + w.wr.WriteString("\xff\xffgo13ld") } -// Provide the the index of a symbol reference by symbol name. -// One map for versioned symbols and one for unversioned symbols. -// Used for deduplicating the symbol reference list. -var refIdx = make(map[string]int) -var vrefIdx = make(map[string]int) +// Symbols are prefixed so their content doesn't get confused with the magic footer. +const symPrefix = 0xfe -func wrref(ctxt *Link, b *Biobuf, s *LSym, isPath bool) { +func (w *objWriter) writeRef(s *LSym, isPath bool) { if s == nil || s.RefIdx != 0 { return } var m map[string]int switch s.Version { case 0: - m = refIdx + m = w.refIdx case 1: - m = vrefIdx + m = w.vrefIdx default: log.Fatalf("%s: invalid version number %d", s.Name, s.Version) } @@ -441,111 +460,117 @@ func wrref(ctxt *Link, b *Biobuf, s *LSym, isPath bool) { s.RefIdx = idx return } - Bputc(b, 0xfe) + w.wr.WriteByte(symPrefix) if isPath { - wrstring(b, filepath.ToSlash(s.Name)) + w.writeString(filepath.ToSlash(s.Name)) } else { - wrstring(b, s.Name) + w.writeString(s.Name) } - wrint(b, int64(s.Version)) - ctxt.RefsWritten++ - s.RefIdx = ctxt.RefsWritten - m[s.Name] = ctxt.RefsWritten + w.writeInt(int64(s.Version)) + w.nRefs++ + s.RefIdx = w.nRefs + m[s.Name] = w.nRefs } -func writerefs(ctxt *Link, b *Biobuf, s *LSym) { - wrref(ctxt, b, s, false) - wrref(ctxt, b, s.Gotype, false) +func (w *objWriter) writeRefs(s *LSym) { + w.writeRef(s, false) + w.writeRef(s.Gotype, false) for i := range s.R { - wrref(ctxt, b, s.R[i].Sym, false) + w.writeRef(s.R[i].Sym, false) } if s.Type == STEXT { for a := s.Autom; a != nil; a = a.Link { - wrref(ctxt, b, a.Asym, false) - wrref(ctxt, b, a.Gotype, false) + w.writeRef(a.Asym, false) + w.writeRef(a.Gotype, false) } pc := s.Pcln for _, d := range pc.Funcdata { - wrref(ctxt, b, d, false) + w.writeRef(d, false) } for _, f := range pc.File { - wrref(ctxt, b, f, true) + w.writeRef(f, true) } } } -func writesym(ctxt *Link, b *Biobuf, s *LSym) { - if ctxt.Debugasm != 0 { - fmt.Fprintf(ctxt.Bso, "%s ", s.Name) - if s.Version != 0 { - fmt.Fprintf(ctxt.Bso, "v=%d ", s.Version) +func (w *objWriter) writeSymDebug(s *LSym) { + ctxt := w.ctxt + fmt.Fprintf(ctxt.Bso, "%s ", s.Name) + if s.Version != 0 { + fmt.Fprintf(ctxt.Bso, "v=%d ", s.Version) + } + if s.Type != 0 { + fmt.Fprintf(ctxt.Bso, "t=%d ", s.Type) + } + if s.Dupok { + fmt.Fprintf(ctxt.Bso, "dupok ") + } + if s.Cfunc { + fmt.Fprintf(ctxt.Bso, "cfunc ") + } + if s.Nosplit { + fmt.Fprintf(ctxt.Bso, "nosplit ") + } + fmt.Fprintf(ctxt.Bso, "size=%d", s.Size) + if s.Type == STEXT { + fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Args), uint64(s.Locals)) + if s.Leaf { + fmt.Fprintf(ctxt.Bso, " leaf") } - if s.Type != 0 { - fmt.Fprintf(ctxt.Bso, "t=%d ", s.Type) + } + + fmt.Fprintf(ctxt.Bso, "\n") + for p := s.Text; p != nil; p = p.Link { + fmt.Fprintf(ctxt.Bso, "\t%#04x %v\n", uint(int(p.Pc)), p) + } + var c int + var j int + for i := 0; i < len(s.P); { + fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i)) + for j = i; j < i+16 && j < len(s.P); j++ { + fmt.Fprintf(ctxt.Bso, " %02x", s.P[j]) } - if s.Dupok { - fmt.Fprintf(ctxt.Bso, "dupok ") + for ; j < i+16; j++ { + fmt.Fprintf(ctxt.Bso, " ") } - if s.Cfunc { - fmt.Fprintf(ctxt.Bso, "cfunc ") - } - if s.Nosplit { - fmt.Fprintf(ctxt.Bso, "nosplit ") - } - fmt.Fprintf(ctxt.Bso, "size=%d", s.Size) - if s.Type == STEXT { - fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Args), uint64(s.Locals)) - if s.Leaf { - fmt.Fprintf(ctxt.Bso, " leaf") + fmt.Fprintf(ctxt.Bso, " ") + for j = i; j < i+16 && j < len(s.P); j++ { + c = int(s.P[j]) + if ' ' <= c && c <= 0x7e { + fmt.Fprintf(ctxt.Bso, "%c", c) + } else { + fmt.Fprintf(ctxt.Bso, ".") } } fmt.Fprintf(ctxt.Bso, "\n") - for p := s.Text; p != nil; p = p.Link { - fmt.Fprintf(ctxt.Bso, "\t%#04x %v\n", uint(int(p.Pc)), p) - } - var c int - var j int - for i := 0; i < len(s.P); { - fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i)) - for j = i; j < i+16 && j < len(s.P); j++ { - fmt.Fprintf(ctxt.Bso, " %02x", s.P[j]) - } - for ; j < i+16; j++ { - fmt.Fprintf(ctxt.Bso, " ") - } - fmt.Fprintf(ctxt.Bso, " ") - for j = i; j < i+16 && j < len(s.P); j++ { - c = int(s.P[j]) - if ' ' <= c && c <= 0x7e { - fmt.Fprintf(ctxt.Bso, "%c", c) - } else { - fmt.Fprintf(ctxt.Bso, ".") - } - } - - fmt.Fprintf(ctxt.Bso, "\n") - i += 16 - } - - sort.Sort(relocByOff(s.R)) // generate stable output - for _, r := range s.R { - name := "" - if r.Sym != nil { - name = r.Sym.Name - } - if ctxt.Arch.Thechar == '5' || ctxt.Arch.Thechar == '9' { - fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(int64(r.Add))) - } else { - fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, int64(r.Add)) - } - } + i += 16 } - Bputc(b, 0xfe) - wrint(b, int64(s.Type)) - wrsym(b, s) + sort.Sort(relocByOff(s.R)) // generate stable output + for _, r := range s.R { + name := "" + if r.Sym != nil { + name = r.Sym.Name + } + if ctxt.Arch.Thechar == '5' || ctxt.Arch.Thechar == '9' { + fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(int64(r.Add))) + } else { + fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, int64(r.Add)) + } + } +} + +func (w *objWriter) writeSym(s *LSym) { + ctxt := w.ctxt + if ctxt.Debugasm != 0 { + w.writeSymDebug(s) + } + + w.wr.WriteByte(symPrefix) + w.writeInt(int64(s.Type)) + w.writeRefIndex(s) flags := int64(0) if s.Dupok { flags |= 1 @@ -553,112 +578,110 @@ func writesym(ctxt *Link, b *Biobuf, s *LSym) { if s.Local { flags |= 1 << 1 } - wrint(b, flags) - wrint(b, s.Size) - wrsym(b, s.Gotype) - wrint(b, int64(len(s.P))) + w.writeInt(flags) + w.writeInt(s.Size) + w.writeRefIndex(s.Gotype) + w.writeInt(int64(len(s.P))) - wrint(b, int64(len(s.R))) + w.writeInt(int64(len(s.R))) var r *Reloc for i := 0; i < len(s.R); i++ { r = &s.R[i] - wrint(b, int64(r.Off)) - wrint(b, int64(r.Siz)) - wrint(b, int64(r.Type)) - wrint(b, r.Add) - wrsym(b, r.Sym) + w.writeInt(int64(r.Off)) + w.writeInt(int64(r.Siz)) + w.writeInt(int64(r.Type)) + w.writeInt(r.Add) + w.writeRefIndex(r.Sym) } - if s.Type == STEXT { - wrint(b, int64(s.Args)) - wrint(b, int64(s.Locals)) - if s.Nosplit { - wrint(b, 1) - } else { - wrint(b, 0) - } - flags := int64(0) - if s.Leaf { - flags |= 1 - } - if s.Cfunc { - flags |= 1 << 1 - } - if s.ReflectMethod { - flags |= 1 << 2 - } - wrint(b, flags) - n := 0 - for a := s.Autom; a != nil; a = a.Link { - n++ - } - wrint(b, int64(n)) - for a := s.Autom; a != nil; a = a.Link { - wrsym(b, a.Asym) - wrint(b, int64(a.Aoffset)) - if a.Name == NAME_AUTO { - wrint(b, A_AUTO) - } else if a.Name == NAME_PARAM { - wrint(b, A_PARAM) - } else { - log.Fatalf("%s: invalid local variable type %d", s.Name, a.Name) - } - wrsym(b, a.Gotype) - } + if s.Type != STEXT { + return + } - pc := s.Pcln - wrint(b, int64(len(pc.Pcsp.P))) - wrint(b, int64(len(pc.Pcfile.P))) - wrint(b, int64(len(pc.Pcline.P))) - wrint(b, int64(len(pc.Pcdata))) - for i := 0; i < len(pc.Pcdata); i++ { - wrint(b, int64(len(pc.Pcdata[i].P))) - } - wrint(b, int64(len(pc.Funcdataoff))) - for i := 0; i < len(pc.Funcdataoff); i++ { - wrsym(b, pc.Funcdata[i]) - } - for i := 0; i < len(pc.Funcdataoff); i++ { - wrint(b, pc.Funcdataoff[i]) - } - wrint(b, int64(len(pc.File))) - for _, f := range pc.File { - wrsym(b, f) + w.writeInt(int64(s.Args)) + w.writeInt(int64(s.Locals)) + if s.Nosplit { + w.writeInt(1) + } else { + w.writeInt(0) + } + flags = int64(0) + if s.Leaf { + flags |= 1 + } + if s.Cfunc { + flags |= 1 << 1 + } + if s.ReflectMethod { + flags |= 1 << 2 + } + w.writeInt(flags) + n := 0 + for a := s.Autom; a != nil; a = a.Link { + n++ + } + w.writeInt(int64(n)) + for a := s.Autom; a != nil; a = a.Link { + w.writeRefIndex(a.Asym) + w.writeInt(int64(a.Aoffset)) + if a.Name == NAME_AUTO { + w.writeInt(A_AUTO) + } else if a.Name == NAME_PARAM { + w.writeInt(A_PARAM) + } else { + log.Fatalf("%s: invalid local variable type %d", s.Name, a.Name) } + w.writeRefIndex(a.Gotype) + } + + pc := s.Pcln + w.writeInt(int64(len(pc.Pcsp.P))) + w.writeInt(int64(len(pc.Pcfile.P))) + w.writeInt(int64(len(pc.Pcline.P))) + w.writeInt(int64(len(pc.Pcdata))) + for i := 0; i < len(pc.Pcdata); i++ { + w.writeInt(int64(len(pc.Pcdata[i].P))) + } + w.writeInt(int64(len(pc.Funcdataoff))) + for i := 0; i < len(pc.Funcdataoff); i++ { + w.writeRefIndex(pc.Funcdata[i]) + } + for i := 0; i < len(pc.Funcdataoff); i++ { + w.writeInt(pc.Funcdataoff[i]) + } + w.writeInt(int64(len(pc.File))) + for _, f := range pc.File { + w.writeRefIndex(f) } } -// Reusable buffer to avoid allocations. -// This buffer was responsible for 15% of gc's allocations. -var varintbuf [10]uint8 - -func wrint(b *Biobuf, sval int64) { +func (w *objWriter) writeInt(sval int64) { var v uint64 uv := (uint64(sval) << 1) ^ uint64(int64(sval>>63)) - p := varintbuf[:] + p := w.varintbuf[:] for v = uv; v >= 0x80; v >>= 7 { p[0] = uint8(v | 0x80) p = p[1:] } p[0] = uint8(v) p = p[1:] - b.Write(varintbuf[:len(varintbuf)-len(p)]) + w.wr.Write(w.varintbuf[:len(w.varintbuf)-len(p)]) } -func wrstring(b *Biobuf, s string) { - wrint(b, int64(len(s))) - b.w.WriteString(s) +func (w *objWriter) writeString(s string) { + w.writeInt(int64(len(s))) + w.wr.WriteString(s) } -func wrsym(b *Biobuf, s *LSym) { +func (w *objWriter) writeRefIndex(s *LSym) { if s == nil { - wrint(b, 0) + w.writeInt(0) return } if s.RefIdx == 0 { log.Fatalln("writing an unreferenced symbol", s.Name) } - wrint(b, int64(s.RefIdx)) + w.writeInt(int64(s.RefIdx)) } // relocByOff sorts relocations by their offsets.