type Package struct {
ImportPath string // import path denoting this package
Imports []string // packages imported by this package
+ SymRefs []SymID // list of symbol names and versions refered to by this pack
Syms []*Sym // symbols defined by this package
MaxVersion int // maximum Version in any SymID in Syms
}
// readSymID reads a SymID from the input file.
func (r *objReader) readSymID() SymID {
+ i := r.readInt()
+ return r.p.SymRefs[i]
+}
+
+func (r *objReader) readRef() {
name, vers := r.readString(), r.readInt()
// In a symbol name in an object file, "". denotes the
if vers != 0 {
vers = r.p.MaxVersion
}
-
- return SymID{name, vers}
+ r.p.SymRefs = append(r.p.SymRefs, SymID{name, vers})
}
// readData reads a data reference from the input file.
r.p.Imports = append(r.p.Imports, s)
}
+ r.p.SymRefs = []SymID{{"", 0}}
+ for {
+ if b := r.readByte(); b != 0xfe {
+ if b != 0xff {
+ return r.error(errCorruptObject)
+ }
+ break
+ }
+
+ r.readRef()
+ }
+
// Symbols.
for {
if b := r.readByte(); b != 0xfe {
Leaf uint8
Seenglobl uint8
Onlist uint8
+ RefIdx int // Index of this symbol in the symbol reference list.
// ReflectMethod means the function may call reflect.Type.Method or
// reflect.Type.MethodByName. Matching is imprecise (as reflect.Type
Textp *LSym
Etextp *LSym
Errors int
+ RefsWritten int // Number of symbol references already written to object file.
// state for writing objects
Text *LSym
// - byte 1 - version number
// - sequence of strings giving dependencies (imported packages)
// - empty string (marks end of sequence)
+// - sequence of sybol references used by the defined symbols
+// - byte 0xff (marks end of sequence)
// - sequence of defined symbols
// - byte 0xff (marks end of sequence)
// - magic footer: "\xff\xffgo13ld"
// followed by that many bytes.
//
// A symbol reference is a string name followed by a version.
-// An empty name corresponds to a nil LSym* pointer.
+//
+// A symbol points to other symbols using an index into the symbol
+// reference sequence. Index 0 corresponds to a nil LSym* pointer.
+// In the symbol layout described below "symref index" stands for this
+// index.
//
// Each symbol is laid out as the following fields (taken from LSym*):
//
// - byte 0xfe (sanity check for synchronization)
// - type [int]
-// - name [string]
-// - version [int]
+// - name & version [symref index]
// - flags [int]
// 1 dupok
// - size [int]
-// - gotype [symbol reference]
+// - gotype [symref index]
// - p [data block]
// - nr [int]
// - r [nr relocations, sorted by off]
// - locals [int]
// - nosplit [int]
// - flags [int]
-// 1 leaf
-// 2 C function
+// 1<<0 leaf
+// 1<<1 C function
+// 1<<2 function may call reflect.Type.Method
// - nlocal [int]
// - local [nlocal automatics]
// - pcln [pcln table]
// - type [int]
// - add [int]
// - xadd [int]
-// - sym [symbol reference]
-// - xsym [symbol reference]
+// - sym [symref index]
+// - xsym [symref index]
//
// Each local has the encoding:
//
-// - asym [symbol reference]
+// - asym [symref index]
// - offset [int]
// - type [int]
-// - gotype [symbol reference]
+// - gotype [symref index]
//
// The pcln table has the encoding:
//
// - npcdata [int]
// - pcdata [npcdata data blocks]
// - nfuncdata [int]
-// - funcdata [nfuncdata symbol references]
+// - funcdata [nfuncdata symref index]
// - funcdatasym [nfuncdata ints]
// - nfile [int]
-// - file [nfile symbol references]
+// - file [nfile symref index]
//
// The file layout and meaning of type integers are architecture-independent.
//
// - The actual symbol memory images are interlaced with the symbol
// metadata. They should be separated, to reduce the I/O required to
// load just the metadata.
-// - The symbol references should be shortened, either with a symbol
-// table or by using a simple backward index to an earlier mentioned symbol.
package obj
}
wrstring(b, "")
+ // Emit symbol references.
+ for s := ctxt.Text; s != nil; s = s.Next {
+ writerefs(ctxt, b, s)
+ }
+ for s := ctxt.Data; s != nil; s = s.Next {
+ writerefs(ctxt, b, s)
+ }
+ Bputc(b, 0xff)
+
// Emit symbols.
for s := ctxt.Text; s != nil; s = s.Next {
writesym(ctxt, b, s)
fmt.Fprintf(b, "go13ld")
}
+func wrref(ctxt *Link, b *Biobuf, s *LSym, isPath bool) {
+ if s == nil || s.RefIdx != 0 {
+ return
+ }
+ Bputc(b, 0xfe)
+ if isPath {
+ wrstring(b, filepath.ToSlash(s.Name))
+ } else {
+ wrstring(b, s.Name)
+ }
+ wrint(b, int64(s.Version))
+ ctxt.RefsWritten++
+ s.RefIdx = ctxt.RefsWritten
+}
+
+func writerefs(ctxt *Link, b *Biobuf, s *LSym) {
+ wrref(ctxt, b, s, false)
+ wrref(ctxt, b, s.Gotype, false)
+ for i := range s.R {
+ wrref(ctxt, b, 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)
+ }
+ pc := s.Pcln
+ for _, d := range pc.Funcdata {
+ wrref(ctxt, b, d, false)
+ }
+ for _, f := range pc.File {
+ wrref(ctxt, b, f, true)
+ }
+ }
+}
+
func writesym(ctxt *Link, b *Biobuf, s *LSym) {
if ctxt.Debugasm != 0 {
fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
Bputc(b, 0xfe)
wrint(b, int64(s.Type))
- wrstring(b, s.Name)
- wrint(b, int64(s.Version))
+ wrsym(b, s)
flags := int64(s.Dupok)
if s.Local {
flags |= 2
wrint(b, pc.Funcdataoff[i])
}
wrint(b, int64(len(pc.File)))
- for i := 0; i < len(pc.File); i++ {
- wrpathsym(ctxt, b, pc.File[i])
+ for _, f := range pc.File {
+ wrsym(b, f)
}
}
}
b.w.WriteString(s)
}
-// wrpath writes a path just like a string, but on windows, it
-// translates '\\' to '/' in the process.
-func wrpath(ctxt *Link, b *Biobuf, p string) {
- wrstring(b, filepath.ToSlash(p))
-}
-
func wrdata(b *Biobuf, v []byte) {
wrint(b, int64(len(v)))
b.Write(v)
}
-func wrpathsym(ctxt *Link, b *Biobuf, s *LSym) {
- if s == nil {
- wrint(b, 0)
- wrint(b, 0)
- return
- }
-
- wrpath(ctxt, b, s.Name)
- wrint(b, int64(s.Version))
-}
-
func wrsym(b *Biobuf, s *LSym) {
if s == nil {
- wrint(b, 0)
wrint(b, 0)
return
}
-
- wrstring(b, s.Name)
- wrint(b, int64(s.Version))
+ if s.RefIdx == 0 {
+ log.Fatalln("writing an unreferenced symbol", s.Name)
+ }
+ wrint(b, int64(s.RefIdx))
}
// relocByOff sorts relocations by their offsets.
_64bit uintptr // size on 64bit platforms
}{
{Addr{}, 52, 80},
- {LSym{}, 92, 152},
+ {LSym{}, 100, 168},
{Prog{}, 196, 288},
}
Filesyms *LSym
Moduledata *LSym
LSymBatch []LSym
+ CurRefs []*LSym // List of symbol references for the file being read.
}
// The smallest possible offset from the hardware stack pointer to a local
package ld
-// Writing and reading of Go object files.
+// Reading of Go object files.
//
// Originally, Go object files were Plan 9 object files, but no longer.
// Now they are more like standard object files, in that each symbol is defined
// - byte 1 - version number
// - sequence of strings giving dependencies (imported packages)
// - empty string (marks end of sequence)
+// - sequence of sybol references used by the defined symbols
+// - byte 0xff (marks end of sequence)
// - sequence of defined symbols
// - byte 0xff (marks end of sequence)
// - magic footer: "\xff\xffgo13ld"
// followed by that many bytes.
//
// A symbol reference is a string name followed by a version.
-// An empty name corresponds to a nil LSym* pointer.
+//
+// A symbol points to other symbols using an index into the symbol
+// reference sequence. Index 0 corresponds to a nil LSym* pointer.
+// In the symbol layout described below "symref index" stands for this
+// index.
//
// Each symbol is laid out as the following fields (taken from LSym*):
//
// - byte 0xfe (sanity check for synchronization)
// - type [int]
-// - name [string]
-// - version [int]
+// - name & version [symref index]
// - flags [int]
// 1 dupok
// - size [int]
-// - gotype [symbol reference]
+// - gotype [symref index]
// - p [data block]
// - nr [int]
// - r [nr relocations, sorted by off]
// - type [int]
// - add [int]
// - xadd [int]
-// - sym [symbol reference]
-// - xsym [symbol reference]
+// - sym [symref index]
+// - xsym [symref index]
//
// Each local has the encoding:
//
-// - asym [symbol reference]
+// - asym [symref index]
// - offset [int]
// - type [int]
-// - gotype [symbol reference]
+// - gotype [symref index]
//
// The pcln table has the encoding:
//
// - npcdata [int]
// - pcdata [npcdata data blocks]
// - nfuncdata [int]
-// - funcdata [nfuncdata symbol references]
+// - funcdata [nfuncdata symref index]
// - funcdatasym [nfuncdata ints]
// - nfile [int]
-// - file [nfile symbol references]
+// - file [nfile symref index]
//
// The file layout and meaning of type integers are architecture-independent.
//
// - The actual symbol memory images are interlaced with the symbol
// metadata. They should be separated, to reduce the I/O required to
// load just the metadata.
-// - The symbol references should be shortened, either with a symbol
-// table or by using a simple backward index to an earlier mentioned symbol.
import (
"bytes"
addlib(ctxt, pkg, pn, lib)
}
+ ctxt.CurRefs = []*LSym{nil} // zeroth ref is nil
+ for {
+ c, err := f.Peek(1)
+ if err != nil {
+ log.Fatalf("%s: peeking: %v", pn, err)
+ }
+ if c[0] == 0xff {
+ obj.Bgetc(f)
+ break
+ }
+ readref(ctxt, f, pkg, pn)
+ }
+
for {
c, err := f.Peek(1)
if err != nil {
log.Fatalf("readsym out of sync")
}
t := rdint(f)
- name := rdsymName(f, pkg)
- v := rdint(f)
- if v != 0 && v != 1 {
- log.Fatalf("invalid symbol version %d", v)
- }
+ s := rdsym(ctxt, f, pkg)
flags := rdint(f)
dupok := flags&1 != 0
local := flags&2 != 0
data := rddata(f)
nreloc := rdint(f)
- if v != 0 {
- v = ctxt.Version
- }
- s := Linklookup(ctxt, name, v)
var dup *LSym
if s.Type != 0 && s.Type != obj.SXREF {
if (t == obj.SDATA || t == obj.SBSS || t == obj.SNOPTRBSS) && len(data) == 0 && nreloc == 0 {
log.Fatalf("bad sxref")
}
if t == 0 {
- log.Fatalf("missing type for %s in %s", name, pn)
+ log.Fatalf("missing type for %s in %s", s.Name, pn)
}
if t == obj.SBSS && (s.Type == obj.SRODATA || s.Type == obj.SNOPTRBSS) {
t = int(s.Type)
}
}
+func readref(ctxt *Link, f *obj.Biobuf, pkg string, pn string) {
+ if obj.Bgetc(f) != 0xfe {
+ log.Fatalf("readsym out of sync")
+ }
+ name := rdsymName(f, pkg)
+ v := rdint(f)
+ if v != 0 && v != 1 {
+ log.Fatalf("invalid symbol version %d", v)
+ }
+ if v == 1 {
+ v = ctxt.Version
+ }
+ lsym := Linklookup(ctxt, name, v)
+ ctxt.CurRefs = append(ctxt.CurRefs, lsym)
+}
+
func rdint64(f *obj.Biobuf) int64 {
var c int
}
func rdsym(ctxt *Link, f *obj.Biobuf, pkg string) *LSym {
- name := rdsymName(f, pkg)
- if name == "" {
+ i := rdint(f)
+ if i == 0 {
return nil
}
- v := rdint(f)
- if v != 0 {
- v = ctxt.Version
- }
- s := Linklookup(ctxt, name, v)
- if v != 0 {
+
+ s := ctxt.CurRefs[i]
+ if s == nil || s.Version != 0 {
return s
}