summaryrefslogtreecommitdiff
path: root/src/cmd/oldlink/internal/sym/symbol.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/oldlink/internal/sym/symbol.go')
-rw-r--r--src/cmd/oldlink/internal/sym/symbol.go543
1 files changed, 543 insertions, 0 deletions
diff --git a/src/cmd/oldlink/internal/sym/symbol.go b/src/cmd/oldlink/internal/sym/symbol.go
new file mode 100644
index 0000000000..2756acd211
--- /dev/null
+++ b/src/cmd/oldlink/internal/sym/symbol.go
@@ -0,0 +1,543 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sym
+
+import (
+ "cmd/internal/obj"
+ "cmd/internal/objabi"
+ "cmd/internal/sys"
+ "debug/elf"
+ "fmt"
+ "log"
+)
+
+// Symbol is an entry in the symbol table.
+type Symbol struct {
+ Name string
+ Type SymKind
+ Version int16
+ Attr Attribute
+ Dynid int32
+ Align int32
+ Elfsym int32
+ LocalElfsym int32
+ Value int64
+ Size int64
+ Sub *Symbol
+ Outer *Symbol
+ Gotype *Symbol
+ File string // actually package!
+ auxinfo *AuxSymbol
+ Sect *Section
+ FuncInfo *FuncInfo
+ Unit *CompilationUnit
+ // P contains the raw symbol data.
+ P []byte
+ R []Reloc
+}
+
+// AuxSymbol contains less-frequently used sym.Symbol fields.
+type AuxSymbol struct {
+ extname string
+ dynimplib string
+ dynimpvers string
+ localentry uint8
+ plt int32
+ got int32
+ // ElfType is set for symbols read from shared libraries by ldshlibsyms. It
+ // is not set for symbols defined by the packages being linked or by symbols
+ // read by ldelf (and so is left as elf.STT_NOTYPE).
+ elftype elf.SymType
+}
+
+const (
+ SymVerABI0 = 0
+ SymVerABIInternal = 1
+ SymVerStatic = 10 // Minimum version used by static (file-local) syms
+)
+
+func ABIToVersion(abi obj.ABI) int {
+ switch abi {
+ case obj.ABI0:
+ return SymVerABI0
+ case obj.ABIInternal:
+ return SymVerABIInternal
+ }
+ return -1
+}
+
+func VersionToABI(v int) (obj.ABI, bool) {
+ switch v {
+ case SymVerABI0:
+ return obj.ABI0, true
+ case SymVerABIInternal:
+ return obj.ABIInternal, true
+ }
+ return ^obj.ABI(0), false
+}
+
+func (s *Symbol) String() string {
+ if s.Version == 0 {
+ return s.Name
+ }
+ return fmt.Sprintf("%s<%d>", s.Name, s.Version)
+}
+
+func (s *Symbol) IsFileLocal() bool {
+ return s.Version >= SymVerStatic
+}
+
+func (s *Symbol) ElfsymForReloc() int32 {
+ // If putelfsym created a local version of this symbol, use that in all
+ // relocations.
+ if s.LocalElfsym != 0 {
+ return s.LocalElfsym
+ } else {
+ return s.Elfsym
+ }
+}
+
+func (s *Symbol) Length(_ interface{}) int64 {
+ return s.Size
+}
+
+func (s *Symbol) Grow(siz int64) {
+ if int64(int(siz)) != siz {
+ log.Fatalf("symgrow size %d too long", siz)
+ }
+ if int64(len(s.P)) >= siz {
+ return
+ }
+ if cap(s.P) < int(siz) {
+ p := make([]byte, 2*(siz+1))
+ s.P = append(p[:0], s.P...)
+ }
+ s.P = s.P[:siz]
+}
+
+func (s *Symbol) AddBytes(bytes []byte) int64 {
+ if s.Type == 0 {
+ s.Type = SDATA
+ }
+ s.Attr |= AttrReachable
+ s.P = append(s.P, bytes...)
+ s.Size = int64(len(s.P))
+
+ return s.Size
+}
+
+func (s *Symbol) AddUint8(v uint8) int64 {
+ off := s.Size
+ if s.Type == 0 {
+ s.Type = SDATA
+ }
+ s.Attr |= AttrReachable
+ s.Size++
+ s.P = append(s.P, v)
+
+ return off
+}
+
+func (s *Symbol) AddUint16(arch *sys.Arch, v uint16) int64 {
+ return s.AddUintXX(arch, uint64(v), 2)
+}
+
+func (s *Symbol) AddUint32(arch *sys.Arch, v uint32) int64 {
+ return s.AddUintXX(arch, uint64(v), 4)
+}
+
+func (s *Symbol) AddUint64(arch *sys.Arch, v uint64) int64 {
+ return s.AddUintXX(arch, v, 8)
+}
+
+func (s *Symbol) AddUint(arch *sys.Arch, v uint64) int64 {
+ return s.AddUintXX(arch, v, arch.PtrSize)
+}
+
+func (s *Symbol) SetUint8(arch *sys.Arch, r int64, v uint8) int64 {
+ return s.setUintXX(arch, r, uint64(v), 1)
+}
+
+func (s *Symbol) SetUint16(arch *sys.Arch, r int64, v uint16) int64 {
+ return s.setUintXX(arch, r, uint64(v), 2)
+}
+
+func (s *Symbol) SetUint32(arch *sys.Arch, r int64, v uint32) int64 {
+ return s.setUintXX(arch, r, uint64(v), 4)
+}
+
+func (s *Symbol) SetUint(arch *sys.Arch, r int64, v uint64) int64 {
+ return s.setUintXX(arch, r, v, int64(arch.PtrSize))
+}
+
+func (s *Symbol) addAddrPlus(arch *sys.Arch, t *Symbol, add int64, typ objabi.RelocType) int64 {
+ if s.Type == 0 {
+ s.Type = SDATA
+ }
+ s.Attr |= AttrReachable
+ i := s.Size
+ s.Size += int64(arch.PtrSize)
+ s.Grow(s.Size)
+ r := s.AddRel()
+ r.Sym = t
+ r.Off = int32(i)
+ r.Siz = uint8(arch.PtrSize)
+ r.Type = typ
+ r.Add = add
+ return i + int64(r.Siz)
+}
+
+func (s *Symbol) AddAddrPlus(arch *sys.Arch, t *Symbol, add int64) int64 {
+ return s.addAddrPlus(arch, t, add, objabi.R_ADDR)
+}
+
+func (s *Symbol) AddCURelativeAddrPlus(arch *sys.Arch, t *Symbol, add int64) int64 {
+ return s.addAddrPlus(arch, t, add, objabi.R_ADDRCUOFF)
+}
+
+func (s *Symbol) AddPCRelPlus(arch *sys.Arch, t *Symbol, add int64) int64 {
+ if s.Type == 0 {
+ s.Type = SDATA
+ }
+ s.Attr |= AttrReachable
+ i := s.Size
+ s.Size += 4
+ s.Grow(s.Size)
+ r := s.AddRel()
+ r.Sym = t
+ r.Off = int32(i)
+ r.Add = add
+ r.Type = objabi.R_PCREL
+ r.Siz = 4
+ if arch.Family == sys.S390X || arch.Family == sys.PPC64 {
+ r.InitExt()
+ }
+ if arch.Family == sys.S390X {
+ r.Variant = RV_390_DBL
+ }
+ return i + int64(r.Siz)
+}
+
+func (s *Symbol) AddAddr(arch *sys.Arch, t *Symbol) int64 {
+ return s.AddAddrPlus(arch, t, 0)
+}
+
+func (s *Symbol) SetAddrPlus(arch *sys.Arch, off int64, t *Symbol, add int64) int64 {
+ if s.Type == 0 {
+ s.Type = SDATA
+ }
+ s.Attr |= AttrReachable
+ if off+int64(arch.PtrSize) > s.Size {
+ s.Size = off + int64(arch.PtrSize)
+ s.Grow(s.Size)
+ }
+
+ r := s.AddRel()
+ r.Sym = t
+ r.Off = int32(off)
+ r.Siz = uint8(arch.PtrSize)
+ r.Type = objabi.R_ADDR
+ r.Add = add
+ return off + int64(r.Siz)
+}
+
+func (s *Symbol) SetAddr(arch *sys.Arch, off int64, t *Symbol) int64 {
+ return s.SetAddrPlus(arch, off, t, 0)
+}
+
+func (s *Symbol) AddSize(arch *sys.Arch, t *Symbol) int64 {
+ if s.Type == 0 {
+ s.Type = SDATA
+ }
+ s.Attr |= AttrReachable
+ i := s.Size
+ s.Size += int64(arch.PtrSize)
+ s.Grow(s.Size)
+ r := s.AddRel()
+ r.Sym = t
+ r.Off = int32(i)
+ r.Siz = uint8(arch.PtrSize)
+ r.Type = objabi.R_SIZE
+ return i + int64(r.Siz)
+}
+
+func (s *Symbol) AddAddrPlus4(t *Symbol, add int64) int64 {
+ if s.Type == 0 {
+ s.Type = SDATA
+ }
+ s.Attr |= AttrReachable
+ i := s.Size
+ s.Size += 4
+ s.Grow(s.Size)
+ r := s.AddRel()
+ r.Sym = t
+ r.Off = int32(i)
+ r.Siz = 4
+ r.Type = objabi.R_ADDR
+ r.Add = add
+ return i + int64(r.Siz)
+}
+
+func (s *Symbol) AddRel() *Reloc {
+ s.R = append(s.R, Reloc{})
+ return &s.R[len(s.R)-1]
+}
+
+func (s *Symbol) AddUintXX(arch *sys.Arch, v uint64, wid int) int64 {
+ off := s.Size
+ s.setUintXX(arch, off, v, int64(wid))
+ return off
+}
+
+func (s *Symbol) setUintXX(arch *sys.Arch, off int64, v uint64, wid int64) int64 {
+ if s.Type == 0 {
+ s.Type = SDATA
+ }
+ s.Attr |= AttrReachable
+ if s.Size < off+wid {
+ s.Size = off + wid
+ s.Grow(s.Size)
+ }
+
+ switch wid {
+ case 1:
+ s.P[off] = uint8(v)
+ case 2:
+ arch.ByteOrder.PutUint16(s.P[off:], uint16(v))
+ case 4:
+ arch.ByteOrder.PutUint32(s.P[off:], uint32(v))
+ case 8:
+ arch.ByteOrder.PutUint64(s.P[off:], v)
+ }
+
+ return off + wid
+}
+
+func (s *Symbol) makeAuxInfo() {
+ if s.auxinfo == nil {
+ s.auxinfo = &AuxSymbol{extname: s.Name, plt: -1, got: -1}
+ }
+}
+
+func (s *Symbol) Extname() string {
+ if s.auxinfo == nil {
+ return s.Name
+ }
+ return s.auxinfo.extname
+}
+
+func (s *Symbol) SetExtname(n string) {
+ if s.auxinfo == nil {
+ if s.Name == n {
+ return
+ }
+ s.makeAuxInfo()
+ }
+ s.auxinfo.extname = n
+}
+
+func (s *Symbol) Dynimplib() string {
+ if s.auxinfo == nil {
+ return ""
+ }
+ return s.auxinfo.dynimplib
+}
+
+func (s *Symbol) Dynimpvers() string {
+ if s.auxinfo == nil {
+ return ""
+ }
+ return s.auxinfo.dynimpvers
+}
+
+func (s *Symbol) SetDynimplib(lib string) {
+ if s.auxinfo == nil {
+ s.makeAuxInfo()
+ }
+ s.auxinfo.dynimplib = lib
+}
+
+func (s *Symbol) SetDynimpvers(vers string) {
+ if s.auxinfo == nil {
+ s.makeAuxInfo()
+ }
+ s.auxinfo.dynimpvers = vers
+}
+
+func (s *Symbol) ResetDyninfo() {
+ if s.auxinfo != nil {
+ s.auxinfo.dynimplib = ""
+ s.auxinfo.dynimpvers = ""
+ }
+}
+
+func (s *Symbol) Localentry() uint8 {
+ if s.auxinfo == nil {
+ return 0
+ }
+ return s.auxinfo.localentry
+}
+
+func (s *Symbol) SetLocalentry(val uint8) {
+ if s.auxinfo == nil {
+ if val != 0 {
+ return
+ }
+ s.makeAuxInfo()
+ }
+ s.auxinfo.localentry = val
+}
+
+func (s *Symbol) Plt() int32 {
+ if s.auxinfo == nil {
+ return -1
+ }
+ return s.auxinfo.plt
+}
+
+func (s *Symbol) SetPlt(val int32) {
+ if s.auxinfo == nil {
+ if val == -1 {
+ return
+ }
+ s.makeAuxInfo()
+ }
+ s.auxinfo.plt = val
+}
+
+func (s *Symbol) Got() int32 {
+ if s.auxinfo == nil {
+ return -1
+ }
+ return s.auxinfo.got
+}
+
+func (s *Symbol) SetGot(val int32) {
+ if s.auxinfo == nil {
+ if val == -1 {
+ return
+ }
+ s.makeAuxInfo()
+ }
+ s.auxinfo.got = val
+}
+
+func (s *Symbol) ElfType() elf.SymType {
+ if s.auxinfo == nil {
+ return elf.STT_NOTYPE
+ }
+ return s.auxinfo.elftype
+}
+
+func (s *Symbol) SetElfType(val elf.SymType) {
+ if s.auxinfo == nil {
+ if val == elf.STT_NOTYPE {
+ return
+ }
+ s.makeAuxInfo()
+ }
+ s.auxinfo.elftype = val
+}
+
+// SortSub sorts a linked-list (by Sub) of *Symbol by Value.
+// Used for sub-symbols when loading host objects (see e.g. ldelf.go).
+func SortSub(l *Symbol) *Symbol {
+ if l == nil || l.Sub == nil {
+ return l
+ }
+
+ l1 := l
+ l2 := l
+ for {
+ l2 = l2.Sub
+ if l2 == nil {
+ break
+ }
+ l2 = l2.Sub
+ if l2 == nil {
+ break
+ }
+ l1 = l1.Sub
+ }
+
+ l2 = l1.Sub
+ l1.Sub = nil
+ l1 = SortSub(l)
+ l2 = SortSub(l2)
+
+ /* set up lead element */
+ if l1.Value < l2.Value {
+ l = l1
+ l1 = l1.Sub
+ } else {
+ l = l2
+ l2 = l2.Sub
+ }
+
+ le := l
+
+ for {
+ if l1 == nil {
+ for l2 != nil {
+ le.Sub = l2
+ le = l2
+ l2 = l2.Sub
+ }
+
+ le.Sub = nil
+ break
+ }
+
+ if l2 == nil {
+ for l1 != nil {
+ le.Sub = l1
+ le = l1
+ l1 = l1.Sub
+ }
+
+ break
+ }
+
+ if l1.Value < l2.Value {
+ le.Sub = l1
+ le = l1
+ l1 = l1.Sub
+ } else {
+ le.Sub = l2
+ le = l2
+ l2 = l2.Sub
+ }
+ }
+
+ le.Sub = nil
+ return l
+}
+
+type FuncInfo struct {
+ Args int32
+ Locals int32
+ Pcsp Pcdata
+ Pcfile Pcdata
+ Pcline Pcdata
+ Pcinline Pcdata
+ Pcdata []Pcdata
+ Funcdata []*Symbol
+ Funcdataoff []int64
+ File []*Symbol
+ InlTree []InlinedCall
+}
+
+// InlinedCall is a node in a local inlining tree (FuncInfo.InlTree).
+type InlinedCall struct {
+ Parent int32 // index of parent in InlTree
+ File *Symbol // file of the inlined call
+ Line int32 // line number of the inlined call
+ Func string // name of the function that was inlined
+ ParentPC int32 // PC of the instruction just before the inlined body (offset from function start)
+}
+
+type Pcdata struct {
+ P []byte
+}