]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/obj: more idiomatic object writer
authorShahar Kohanim <skohanim@gmail.com>
Thu, 31 Mar 2016 09:59:05 +0000 (12:59 +0300)
committerBrad Fitzpatrick <bradfitz@golang.org>
Fri, 1 Apr 2016 09:39:50 +0000 (09:39 +0000)
Change-Id: I41722ee605ea76a6b52e8a7e1e10f2293cef1a7a
Reviewed-on: https://go-review.googlesource.com/21371
Reviewed-by: David Crawshaw <crawshaw@golang.org>
src/cmd/internal/obj/link.go
src/cmd/internal/obj/objfile.go

index cfe7c958cdd9b5c960a3627c31745eeb11d3b0c7..24f028f7378f13de2fc686a4b06688239d840734 100644 (file)
@@ -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
index aba832f27b4e025ae1aac562f40f056a6680290d..a8d86b52cdfac60a01491e5b32ec06ef10f22603 100644 (file)
 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)
+func newObjWriter(ctxt *Link, b *Biobuf) *objWriter {
+       return &objWriter{
+               ctxt:    ctxt,
+               wr:      b.w,
+               vrefIdx: make(map[string]int),
+               refIdx:  make(map[string]int),
+       }
+}
+
+func WriteObjFile(ctxt *Link, b *Biobuf) {
+       w := newObjWriter(ctxt, b)
 
-       Bputc(b, 0)
-       fmt.Fprintf(b, "go13ld")
-       Bputc(b, 1) // version
+       // Magic header
+       w.wr.WriteString("\x00\x00go13ld")
 
-       // Emit autolib.
+       // Version
+       w.wr.WriteByte(1)
+
+       // Autolib
        for _, pkg := range ctxt.Imports {
-               wrstring(b, pkg)
+               w.writeString(pkg)
        }
-       wrstring(b, "")
-
-       var lengths sectionLengths
+       w.writeString("")
 
-       // Emit symbol references.
+       // 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)
-               }
-               if s.Type != 0 {
-                       fmt.Fprintf(ctxt.Bso, "t=%d ", s.Type)
-               }
-               if s.Dupok {
-                       fmt.Fprintf(ctxt.Bso, "dupok ")
+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.Cfunc {
-                       fmt.Fprintf(ctxt.Bso, "cfunc ")
+       }
+
+       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.Nosplit {
-                       fmt.Fprintf(ctxt.Bso, "nosplit ")
+               for ; j < i+16; j++ {
+                       fmt.Fprintf(ctxt.Bso, "   ")
                }
-               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, ".")
-                               }
-                       }
+               i += 16
+       }
 
-                       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
                }
-
-               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))
-                       }
+               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))
                }
        }
+}
 
-       Bputc(b, 0xfe)
-       wrint(b, int64(s.Type))
-       wrsym(b, s)
+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)
+       if s.Type != STEXT {
+               return
+       }
+
+       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 {
-                       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)
+                       log.Fatalf("%s: invalid local variable type %d", s.Name, a.Name)
                }
+               w.writeRefIndex(a.Gotype)
+       }
 
-               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)
-               }
+       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.