Commit 014f3e1e authored by Shahar Kohanim's avatar Shahar Kohanim Committed by Brad Fitzpatrick

cmd/internal/obj: more idiomatic object writer

Change-Id: I41722ee605ea76a6b52e8a7e1e10f2293cef1a7a
Reviewed-on: https://go-review.googlesource.com/21371Reviewed-by: 's avatarDavid Crawshaw <crawshaw@golang.org>
parent b91cc530
......@@ -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
......
......@@ -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)
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,42 +460,42 @@ 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 {
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)
......@@ -541,11 +560,17 @@ func writesym(ctxt *Link, b *Biobuf, s *LSym) {
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)
}
Bputc(b, 0xfe)
wrint(b, int64(s.Type))
wrsym(b, s)
w.wr.WriteByte(symPrefix)
w.writeInt(int64(s.Type))
w.writeRefIndex(s)
flags := int64(0)
if s.Dupok {
flags |= 1
......@@ -553,31 +578,34 @@ 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.Type != STEXT {
return
}
w.writeInt(int64(s.Args))
w.writeInt(int64(s.Locals))
if s.Nosplit {
wrint(b, 1)
w.writeInt(1)
} else {
wrint(b, 0)
w.writeInt(0)
}
flags := int64(0)
flags = int64(0)
if s.Leaf {
flags |= 1
}
......@@ -587,78 +615,73 @@ func writesym(ctxt *Link, b *Biobuf, s *LSym) {
if s.ReflectMethod {
flags |= 1 << 2
}
wrint(b, flags)
w.writeInt(flags)
n := 0
for a := s.Autom; a != nil; a = a.Link {
n++
}
wrint(b, int64(n))
w.writeInt(int64(n))
for a := s.Autom; a != nil; a = a.Link {
wrsym(b, a.Asym)
wrint(b, int64(a.Aoffset))
w.writeRefIndex(a.Asym)
w.writeInt(int64(a.Aoffset))
if a.Name == NAME_AUTO {
wrint(b, A_AUTO)
w.writeInt(A_AUTO)
} else if a.Name == NAME_PARAM {
wrint(b, A_PARAM)
w.writeInt(A_PARAM)
} else {
log.Fatalf("%s: invalid local variable type %d", s.Name, a.Name)
}
wrsym(b, a.Gotype)
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)))
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++ {
wrint(b, int64(len(pc.Pcdata[i].P)))
w.writeInt(int64(len(pc.Pcdata[i].P)))
}
wrint(b, int64(len(pc.Funcdataoff)))
w.writeInt(int64(len(pc.Funcdataoff)))
for i := 0; i < len(pc.Funcdataoff); i++ {
wrsym(b, pc.Funcdata[i])
w.writeRefIndex(pc.Funcdata[i])
}
for i := 0; i < len(pc.Funcdataoff); i++ {
wrint(b, pc.Funcdataoff[i])
w.writeInt(pc.Funcdataoff[i])
}
wrint(b, int64(len(pc.File)))
w.writeInt(int64(len(pc.File)))
for _, f := range pc.File {
wrsym(b, f)
}
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.
......
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