package obj
import (
+ "bufio"
"fmt"
"log"
"path/filepath"
// does not write out object files.
func Writeobjdirect(ctxt *Link, b *Biobuf) {
Flushplist(ctxt)
- Writeobjfile(ctxt, b)
+ WriteObjFile(ctxt, b)
}
func Flushplist(ctxt *Link) {
}
}
-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
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)
}
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
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.