// - There are SymID in the object file that should really just be strings.
import (
+ "bufio"
"bytes"
"cmd/internal/obj"
+ "io"
"log"
"strconv"
"strings"
endmagic = "\xff\xffgo13ld"
)
-func ldobjfile(ctxt *Link, f *obj.Biobuf, pkg string, length int64, pn string) {
+var emptyPkg = []byte(`"".`)
+
+// objReader reads Go object files.
+type objReader struct {
+ rd *bufio.Reader
+ ctxt *Link
+ pkg string
+ pn string
+ // List of symbol references for the file being read.
+ dupSym *LSym
+
+ // rdBuf is used by readString and readSymName as scratch for reading strings.
+ rdBuf []byte
+
+ refs []*LSym
+ data []byte
+ reloc []Reloc
+ pcdata []Pcdata
+ autom []Auto
+ funcdata []*LSym
+ funcdataoff []int64
+ file []*LSym
+}
+
+func LoadObjFile(ctxt *Link, f *obj.Biobuf, pkg string, length int64, pn string) {
start := obj.Boffset(f)
- ctxt.IncVersion()
+ r := &objReader{
+ rd: f.Reader(),
+ pkg: pkg,
+ ctxt: ctxt,
+ pn: pn,
+ dupSym: &LSym{Name: ".dup"},
+ }
+ r.loadObjFile()
+ if obj.Boffset(f) != start+length {
+ log.Fatalf("%s: unexpected end at %d, want %d", pn, int64(obj.Boffset(f)), int64(start+length))
+ }
+}
+
+func (r *objReader) loadObjFile() {
+ // Increment context version, versions are used to differentiate static files in different packages
+ r.ctxt.IncVersion()
+
+ // Magic header
var buf [8]uint8
- obj.Bread(f, buf[:])
+ r.readFull(buf[:])
if string(buf[:]) != startmagic {
- log.Fatalf("%s: invalid file start %x %x %x %x %x %x %x %x", pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7])
+ log.Fatalf("%s: invalid file start %x %x %x %x %x %x %x %x", r.pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7])
}
- c := obj.Bgetc(f)
- if c != 1 {
- log.Fatalf("%s: invalid file version number %d", pn, c)
+
+ // Version
+ c, err := r.rd.ReadByte()
+ if err != nil || c != 1 {
+ log.Fatalf("%s: invalid file version number %d", r.pn, c)
}
- var lib string
+ // Autolib
for {
- lib = rdstring(f)
+ lib := r.readString()
if lib == "" {
break
}
- addlib(ctxt, pkg, pn, lib)
+ addlib(r.ctxt, r.pkg, r.pn, lib)
}
- ctxt.CurRefs = []*LSym{nil} // zeroth ref is nil
+ // Symbol references
+ r.refs = []*LSym{nil} // zeroth ref is nil
for {
- c, err := f.Peek(1)
+ c, err := r.rd.Peek(1)
if err != nil {
- log.Fatalf("%s: peeking: %v", pn, err)
+ log.Fatalf("%s: peeking: %v", r.pn, err)
}
if c[0] == 0xff {
- obj.Bgetc(f)
+ r.rd.ReadByte()
break
}
- readref(ctxt, f, pkg, pn)
+ r.readRef()
}
- sl := rdslices(f)
+ // Lengths
+ r.readSlices()
- obj.Bread(f, sl.data)
+ // Data section
+ r.readFull(r.data)
+ // Defined symbols
for {
- c, err := f.Peek(1)
+ c, err := r.rd.Peek(1)
if err != nil {
- log.Fatalf("%s: peeking: %v", pn, err)
+ log.Fatalf("%s: peeking: %v", r.pn, err)
}
if c[0] == 0xff {
break
}
- readsym(ctxt, f, sl, pkg, pn)
+ r.readSym()
}
+ // Magic footer
buf = [8]uint8{}
- obj.Bread(f, buf[:])
+ r.readFull(buf[:])
if string(buf[:]) != endmagic {
- log.Fatalf("%s: invalid file end", pn)
- }
-
- if obj.Boffset(f) != start+length {
- log.Fatalf("%s: unexpected end at %d, want %d", pn, int64(obj.Boffset(f)), int64(start+length))
+ log.Fatalf("%s: invalid file end", r.pn)
}
}
-var dupSym = &LSym{Name: ".dup"}
-
-type slices struct {
- data []byte
- reloc []Reloc
- pcdata []Pcdata
- autom []Auto
- funcdata []*LSym
- funcdataoff []int64
- file []*LSym
+func (r *objReader) readSlices() {
+ n := r.readInt()
+ r.data = make([]byte, n)
+ n = r.readInt()
+ r.reloc = make([]Reloc, n)
+ n = r.readInt()
+ r.pcdata = make([]Pcdata, n)
+ n = r.readInt()
+ r.autom = make([]Auto, n)
+ n = r.readInt()
+ r.funcdata = make([]*LSym, n)
+ r.funcdataoff = make([]int64, n)
+ n = r.readInt()
+ r.file = make([]*LSym, n)
}
-func rdslices(f *obj.Biobuf) *slices {
- sl := &slices{}
-
- n := rdint(f)
- sl.data = make([]byte, n)
- n = rdint(f)
- sl.reloc = make([]Reloc, n)
- n = rdint(f)
- sl.pcdata = make([]Pcdata, n)
- n = rdint(f)
- sl.autom = make([]Auto, n)
- n = rdint(f)
- sl.funcdata = make([]*LSym, n)
- sl.funcdataoff = make([]int64, n)
- n = rdint(f)
- sl.file = make([]*LSym, n)
- return sl
-}
+// Symbols are prefixed so their content doesn't get confused with the magic footer.
+const symPrefix = 0xfe
-func readsym(ctxt *Link, f *obj.Biobuf, sl *slices, pkg string, pn string) {
- if obj.Bgetc(f) != 0xfe {
- log.Fatalln("readsym out of sync")
+func (r *objReader) readSym() {
+ if c, err := r.rd.ReadByte(); c != symPrefix || err != nil {
+ log.Fatalln("readSym out of sync")
}
- t := rdint(f)
- s := rdsym(ctxt, f, pkg)
- flags := rdint(f)
+ t := r.readInt()
+ s := r.readSymIndex()
+ flags := r.readInt()
dupok := flags&1 != 0
local := flags&2 != 0
- size := rdint(f)
- typ := rdsym(ctxt, f, pkg)
- data := rddata(f, &sl.data)
- nreloc := rdint(f)
+ size := r.readInt()
+ typ := r.readSymIndex()
+ data := r.readData()
+ nreloc := r.readInt()
isdup := false
var dup *LSym
goto overwrite
}
if s.Type != obj.SBSS && s.Type != obj.SNOPTRBSS && !dupok && !s.Attr.DuplicateOK() {
- log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, pn)
+ log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, r.pn)
}
if len(s.P) > 0 {
dup = s
- s = dupSym
+ s = r.dupSym
isdup = true
}
}
overwrite:
- s.File = pkg
+ s.File = r.pkg
if dupok {
s.Attr |= AttrDuplicateOK
}
log.Fatalf("bad sxref")
}
if t == 0 {
- log.Fatalf("missing type for %s in %s", s.Name, pn)
+ log.Fatalf("missing type for %s in %s", s.Name, r.pn)
}
if t == obj.SBSS && (s.Type == obj.SRODATA || s.Type == obj.SNOPTRBSS) {
t = int(s.Type)
}
s.P = data
if nreloc > 0 {
- s.R = sl.reloc[:nreloc:nreloc]
+ s.R = r.reloc[:nreloc:nreloc]
if !isdup {
- sl.reloc = sl.reloc[nreloc:]
+ r.reloc = r.reloc[nreloc:]
}
- var r *Reloc
for i := 0; i < nreloc; i++ {
- r = &s.R[i]
- r.Off = rdint32(f)
- r.Siz = rduint8(f)
- r.Type = rdint32(f)
- r.Add = rdint64(f)
- r.Sym = rdsym(ctxt, f, pkg)
+ s.R[i] = Reloc{
+ Off: r.readInt32(),
+ Siz: r.readUint8(),
+ Type: r.readInt32(),
+ Add: r.readInt64(),
+ Sym: r.readSymIndex(),
+ }
}
}
if s.Type == obj.STEXT {
- s.Args = rdint32(f)
- s.Locals = rdint32(f)
- if rduint8(f) != 0 {
+ s.Args = r.readInt32()
+ s.Locals = r.readInt32()
+ if r.readUint8() != 0 {
s.Attr |= AttrNoSplit
}
- flags := rdint(f)
+ flags := r.readInt()
if flags&(1<<2) != 0 {
s.Attr |= AttrReflectMethod
}
- n := rdint(f)
- s.Autom = sl.autom[:n:n]
+ n := r.readInt()
+ s.Autom = r.autom[:n:n]
if !isdup {
- sl.autom = sl.autom[n:]
+ r.autom = r.autom[n:]
}
for i := 0; i < n; i++ {
s.Autom[i] = Auto{
- Asym: rdsym(ctxt, f, pkg),
- Aoffset: rdint32(f),
- Name: rdint16(f),
- Gotype: rdsym(ctxt, f, pkg),
+ Asym: r.readSymIndex(),
+ Aoffset: r.readInt32(),
+ Name: r.readInt16(),
+ Gotype: r.readSymIndex(),
}
}
s.Pcln = new(Pcln)
pc := s.Pcln
- pc.Pcsp.P = rddata(f, &sl.data)
- pc.Pcfile.P = rddata(f, &sl.data)
- pc.Pcline.P = rddata(f, &sl.data)
- n = rdint(f)
- pc.Pcdata = sl.pcdata[:n:n]
+ pc.Pcsp.P = r.readData()
+ pc.Pcfile.P = r.readData()
+ pc.Pcline.P = r.readData()
+ n = r.readInt()
+ pc.Pcdata = r.pcdata[:n:n]
if !isdup {
- sl.pcdata = sl.pcdata[n:]
+ r.pcdata = r.pcdata[n:]
}
for i := 0; i < n; i++ {
- pc.Pcdata[i].P = rddata(f, &sl.data)
+ pc.Pcdata[i].P = r.readData()
}
- n = rdint(f)
- pc.Funcdata = sl.funcdata[:n:n]
- pc.Funcdataoff = sl.funcdataoff[:n:n]
+ n = r.readInt()
+ pc.Funcdata = r.funcdata[:n:n]
+ pc.Funcdataoff = r.funcdataoff[:n:n]
if !isdup {
- sl.funcdata = sl.funcdata[n:]
- sl.funcdataoff = sl.funcdataoff[n:]
+ r.funcdata = r.funcdata[n:]
+ r.funcdataoff = r.funcdataoff[n:]
}
for i := 0; i < n; i++ {
- pc.Funcdata[i] = rdsym(ctxt, f, pkg)
+ pc.Funcdata[i] = r.readSymIndex()
}
for i := 0; i < n; i++ {
- pc.Funcdataoff[i] = rdint64(f)
+ pc.Funcdataoff[i] = r.readInt64()
}
- n = rdint(f)
- pc.File = sl.file[:n:n]
+ n = r.readInt()
+ pc.File = r.file[:n:n]
if !isdup {
- sl.file = sl.file[n:]
+ r.file = r.file[n:]
}
for i := 0; i < n; i++ {
- pc.File[i] = rdsym(ctxt, f, pkg)
+ pc.File[i] = r.readSymIndex()
}
if !isdup {
log.Fatalf("symbol %s listed multiple times", s.Name)
}
s.Attr |= AttrOnList
- if ctxt.Etextp != nil {
- ctxt.Etextp.Next = s
+ if r.ctxt.Etextp != nil {
+ r.ctxt.Etextp.Next = s
} else {
- ctxt.Textp = s
+ r.ctxt.Textp = s
}
- ctxt.Etextp = s
+ r.ctxt.Etextp = s
}
}
}
-func readref(ctxt *Link, f *obj.Biobuf, pkg string, pn string) {
- if obj.Bgetc(f) != 0xfe {
- log.Fatalf("readsym out of sync")
+func (r *objReader) readFull(b []byte) {
+ _, err := io.ReadFull(r.rd, b)
+ if err != nil {
+ log.Fatalf("%s: error reading %s", r.pn, err)
+ }
+}
+
+func (r *objReader) readRef() {
+ if c, err := r.rd.ReadByte(); c != symPrefix || err != nil {
+ log.Fatalf("readSym out of sync")
}
- name := rdsymName(f, pkg)
- v := rdint(f)
+ name := r.readSymName()
+ v := r.readInt()
if v != 0 && v != 1 {
log.Fatalf("invalid symbol version %d", v)
}
if v == 1 {
- v = ctxt.Version
+ v = r.ctxt.Version
}
- s := Linklookup(ctxt, name, v)
- ctxt.CurRefs = append(ctxt.CurRefs, s)
+ s := Linklookup(r.ctxt, name, v)
+ r.refs = append(r.refs, s)
if s == nil || v != 0 {
return
if uint64(uint32(x)) != x {
log.Panicf("$-symbol %s too large: %d", s.Name, x)
}
- Adduint32(ctxt, s, uint32(x))
+ Adduint32(r.ctxt, s, uint32(x))
case "$f64.", "$i64.":
- Adduint64(ctxt, s, x)
+ Adduint64(r.ctxt, s, x)
default:
log.Panicf("unrecognized $-symbol: %s", s.Name)
}
}
}
-func rdint64(f *obj.Biobuf) int64 {
- r := f.Reader()
+func (r *objReader) readInt64() int64 {
uv := uint64(0)
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
log.Fatalf("corrupt input")
}
- c, err := r.ReadByte()
+ c, err := r.rd.ReadByte()
if err != nil {
log.Fatalln("error reading input: ", err)
}
return int64(uv>>1) ^ (int64(uint64(uv)<<63) >> 63)
}
-func rdint(f *obj.Biobuf) int {
- n := rdint64(f)
+func (r *objReader) readInt() int {
+ n := r.readInt64()
if int64(int(n)) != n {
log.Panicf("%v out of range for int", n)
}
return int(n)
}
-func rdint32(f *obj.Biobuf) int32 {
- n := rdint64(f)
+func (r *objReader) readInt32() int32 {
+ n := r.readInt64()
if int64(int32(n)) != n {
log.Panicf("%v out of range for int32", n)
}
return int32(n)
}
-func rdint16(f *obj.Biobuf) int16 {
- n := rdint64(f)
+func (r *objReader) readInt16() int16 {
+ n := r.readInt64()
if int64(int16(n)) != n {
log.Panicf("%v out of range for int16", n)
}
return int16(n)
}
-func rduint8(f *obj.Biobuf) uint8 {
- n := rdint64(f)
+func (r *objReader) readUint8() uint8 {
+ n := r.readInt64()
if int64(uint8(n)) != n {
log.Panicf("%v out of range for uint8", n)
}
return uint8(n)
}
-// rdBuf is used by rdstring and rdsymName as scratch for reading strings.
-var rdBuf []byte
-var emptyPkg = []byte(`"".`)
-
-func rdstring(f *obj.Biobuf) string {
- n := rdint(f)
- if len(rdBuf) < n {
- rdBuf = make([]byte, n)
+func (r *objReader) readString() string {
+ n := r.readInt()
+ if len(r.rdBuf) < n {
+ r.rdBuf = make([]byte, n)
}
- obj.Bread(f, rdBuf[:n])
- return string(rdBuf[:n])
+ r.readFull(r.rdBuf[:n])
+ return string(r.rdBuf[:n])
}
-func rddata(f *obj.Biobuf, buf *[]byte) []byte {
- n := rdint(f)
- p := (*buf)[:n:n]
- *buf = (*buf)[n:]
+func (r *objReader) readData() []byte {
+ n := r.readInt()
+ p := r.data[:n:n]
+ r.data = r.data[n:]
return p
}
-// rdsymName reads a symbol name, replacing all "". with pkg.
-func rdsymName(f *obj.Biobuf, pkg string) string {
- n := rdint(f)
+// readSymName reads a symbol name, replacing all "". with pkg.
+func (r *objReader) readSymName() string {
+ rdBuf := r.rdBuf
+ pkg := r.pkg
+ n := r.readInt()
if n == 0 {
- rdint64(f)
+ r.readInt64()
return ""
}
rdBuf = make([]byte, n, 2*n)
}
origName := rdBuf[:n]
- obj.Bread(f, origName)
+ r.readFull(origName)
adjName := rdBuf[n:n]
for {
i := bytes.Index(origName, emptyPkg)
}
name := string(adjName)
if len(adjName) > len(rdBuf) {
- rdBuf = adjName // save the larger buffer for reuse
+ r.rdBuf = adjName // save the larger buffer for reuse
}
return name
}
-func rdsym(ctxt *Link, f *obj.Biobuf, pkg string) *LSym {
- i := rdint(f)
- return ctxt.CurRefs[i]
+// Reads the index of a symbol reference and resolves it to a symbol
+func (r *objReader) readSymIndex() *LSym {
+ i := r.readInt()
+ return r.refs[i]
}