}
for _, name := range names {
- // Mark symbol as an data/ABI0 symbol.
+ // Mark symbol as a data/ABI0 symbol.
d.mark(d.ldr.Lookup(name, 0), 0)
// Also mark any Go functions (internal ABI).
d.mark(d.ldr.Lookup(name, sym.SymVerABIInternal), 0)
}
func (d *deadcodePass2) mark(symIdx, parent loader.Sym) {
- if symIdx != 0 && !d.ldr.Reachable.Has(symIdx) {
+ if symIdx != 0 && !d.ldr.AttrReachable(symIdx) {
d.wq.push(symIdx)
- d.ldr.Reachable.Set(symIdx)
+ d.ldr.SetAttrReachable(symIdx, true)
if d.ctxt.Reachparent != nil {
d.ldr.Reachparent[symIdx] = parent
}
// Methods might be called via reflection. Give up on
// static analysis, mark all exported methods of
// all reachable types as reachable.
- d.reflectSeen = d.reflectSeen || (callSym != 0 && ldr.Reachable.Has(callSym)) || (methSym != 0 && ldr.Reachable.Has(methSym))
+ d.reflectSeen = d.reflectSeen || (callSym != 0 && ldr.AttrReachable(callSym)) || (methSym != 0 && ldr.AttrReachable(methSym))
// Mark all methods that could satisfy a discovered
// interface as reachable. We recheck old marked interfaces
s := loader.Sym(i)
if ldr.IsItabLink(s) {
relocs := ldr.Relocs(s)
- if relocs.Count > 0 && ldr.Reachable.Has(relocs.At(0).Sym) {
- ldr.Reachable.Set(s)
+ if relocs.Count > 0 && ldr.AttrReachable(relocs.At(0).Sym) {
+ ldr.SetAttrReachable(s, true)
}
}
}
if i > 0 {
buf.WriteString(", ")
}
- a := d.decodetypeFuncInType2(ldr, arch, mtypSym, d.rtmp, i)
+ a := decodetypeFuncInType2(ldr, arch, mtypSym, d.rtmp, i)
buf.WriteString(ldr.SymName(a))
}
buf.WriteString(") (")
if i > 0 {
buf.WriteString(", ")
}
- a := d.decodetypeFuncOutType2(ldr, arch, mtypSym, d.rtmp, i)
+ a := decodetypeFuncOutType2(ldr, arch, mtypSym, d.rtmp, i)
buf.WriteString(ldr.SymName(a))
}
buf.WriteRune(')')
return d.decodeMethodSig2(ldr, arch, symIdx, symRelocs, off, sizeofMethod, mcount)
}
-func decodeReloc2(ldr *loader.Loader, symIdx loader.Sym, symRelocs []loader.Reloc, off int32) loader.Reloc {
- for j := 0; j < len(symRelocs); j++ {
- rel := symRelocs[j]
- if rel.Off == off {
- return rel
- }
- }
- return loader.Reloc{}
-}
-
-func decodeRelocSym2(ldr *loader.Loader, symIdx loader.Sym, symRelocs []loader.Reloc, off int32) loader.Sym {
- return decodeReloc2(ldr, symIdx, symRelocs, off).Sym
-}
-
-// decodetypeName2 decodes the name from a reflect.name.
-func decodetypeName2(ldr *loader.Loader, symIdx loader.Sym, symRelocs []loader.Reloc, off int) string {
- r := decodeRelocSym2(ldr, symIdx, symRelocs, int32(off))
- if r == 0 {
- return ""
- }
-
- data := ldr.Data(r)
- namelen := int(uint16(data[1])<<8 | uint16(data[2]))
- return string(data[3 : 3+namelen])
-}
-
-func (d *deadcodePass2) decodetypeFuncInType2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc, i int) loader.Sym {
- uadd := commonsize(arch) + 4
- if arch.PtrSize == 8 {
- uadd += 4
- }
- if decodetypeHasUncommon(arch, ldr.Data(symIdx)) {
- uadd += uncommonSize()
- }
- return decodeRelocSym2(ldr, symIdx, symRelocs, int32(uadd+i*arch.PtrSize))
-}
-
-func (d *deadcodePass2) decodetypeFuncOutType2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc, i int) loader.Sym {
- return d.decodetypeFuncInType2(ldr, arch, symIdx, symRelocs, i+decodetypeFuncInCount(arch, ldr.Data(symIdx)))
-}
-
// readRelocs reads the relocations for the specified symbol into the
// deadcode relocs work array. Use with care, since the work array
// is a singleton.
-// Copyright 2017 The Go Authors. All rights reserved.
+// Copyright 2019 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.
align uint64
entsize uint64
base []byte
- sym *sym.Symbol
+ sym loader.Sym
}
type ElfObj struct {
type_ uint8
other uint8
shndx uint16
- sym *sym.Symbol
+ sym loader.Sym
}
var ElfMagic = [4]uint8{0x7F, 'E', 'L', 'F'}
return found, ehdrFlags, nil
}
-func Load(l *loader.Loader, arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string, flags uint32) ([]*sym.Symbol, uint32, error) {
- newSym := func(name string, version int) *sym.Symbol {
- return l.Create(name, syms)
- }
- lookup := func(name string, version int) *sym.Symbol {
- return l.LookupOrCreate(name, version, syms)
- }
- return load(arch, syms.IncVersion(), newSym, lookup, f, pkg, length, pn, flags)
-}
-
-func LoadOld(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string, flags uint32) ([]*sym.Symbol, uint32, error) {
- return load(arch, syms.IncVersion(), syms.Newsym, syms.Lookup, f, pkg, length, pn, flags)
-}
-
-type lookupFunc func(string, int) *sym.Symbol
-
-// load loads the ELF file pn from f.
-// Symbols are written into syms, and a slice of the text symbols is returned.
+// Load loads the ELF file pn from f.
+// Symbols are installed into the loader, and a slice of the text symbols is returned.
//
// On ARM systems, Load will attempt to determine what ELF header flags to
// emit by scanning the attributes in the ELF file being loaded. The
// parameter initEhdrFlags contains the current header flags for the output
// object, and the returned ehdrFlags contains what this Load function computes.
// TODO: find a better place for this logic.
-func load(arch *sys.Arch, localSymVersion int, newSym, lookup lookupFunc, f *bio.Reader, pkg string, length int64, pn string, initEhdrFlags uint32) (textp []*sym.Symbol, ehdrFlags uint32, err error) {
- errorf := func(str string, args ...interface{}) ([]*sym.Symbol, uint32, error) {
+func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader, pkg string, length int64, pn string, initEhdrFlags uint32) (textp []loader.Sym, ehdrFlags uint32, err error) {
+ newSym := func(name string, version int) loader.Sym {
+ return l.CreateExtSym(name)
+ }
+ lookup := func(name string, version int) loader.Sym {
+ return l.LookupOrCreateSym(name, version)
+ }
+ errorf := func(str string, args ...interface{}) ([]loader.Sym, uint32, error) {
return nil, 0, fmt.Errorf("loadelf: %s: %v", pn, fmt.Sprintf(str, args...))
}
}
sectsymNames[name] = true
- s := lookup(name, localSymVersion)
+ sb, _ := l.MakeSymbolUpdater(lookup(name, localSymVersion))
switch int(sect.flags) & (ElfSectFlagAlloc | ElfSectFlagWrite | ElfSectFlagExec) {
default:
return errorf("%s: unexpected flags for ELF section %s", pn, sect.name)
case ElfSectFlagAlloc:
- s.Type = sym.SRODATA
+ sb.SetType(sym.SRODATA)
case ElfSectFlagAlloc + ElfSectFlagWrite:
if sect.type_ == ElfSectNobits {
- s.Type = sym.SNOPTRBSS
+ sb.SetType(sym.SNOPTRBSS)
} else {
- s.Type = sym.SNOPTRDATA
+ sb.SetType(sym.SNOPTRDATA)
}
case ElfSectFlagAlloc + ElfSectFlagExec:
- s.Type = sym.STEXT
+ sb.SetType(sym.STEXT)
}
if sect.name == ".got" || sect.name == ".toc" {
- s.Type = sym.SELFGOT
+ sb.SetType(sym.SELFGOT)
}
if sect.type_ == ElfSectProgbits {
- s.P = sect.base
- s.P = s.P[:sect.size]
+ sb.SetData(sect.base[:sect.size])
}
- s.Size = int64(sect.size)
- s.Align = int32(sect.align)
- sect.sym = s
+ sb.SetSize(int64(sect.size))
+ sb.SetAlign(int32(sect.align))
+
+ sect.sym = sb.Sym()
}
// enter sub-symbols into symbol table.
// symbol 0 is the null symbol.
- symbols := make([]*sym.Symbol, elfobj.nsymtab)
+ symbols := make([]loader.Sym, elfobj.nsymtab)
for i := 1; i < elfobj.nsymtab; i++ {
var elfsym ElfSym
- if err := readelfsym(newSym, lookup, arch, elfobj, i, &elfsym, 1, localSymVersion); err != nil {
+ if err := readelfsym(newSym, lookup, l, arch, elfobj, i, &elfsym, 1, localSymVersion); err != nil {
return errorf("%s: malformed elf file: %v", pn, err)
}
symbols[i] = elfsym.sym
continue
}
if elfsym.shndx == ElfSymShnCommon || elfsym.type_ == ElfSymTypeCommon {
- s := elfsym.sym
- if uint64(s.Size) < elfsym.size {
- s.Size = int64(elfsym.size)
+ sb, ns := l.MakeSymbolUpdater(elfsym.sym)
+ if uint64(sb.Size()) < elfsym.size {
+ sb.SetSize(int64(elfsym.size))
}
- if s.Type == 0 || s.Type == sym.SXREF {
- s.Type = sym.SNOPTRBSS
+ if sb.Type() == 0 || sb.Type() == sym.SXREF {
+ sb.SetType(sym.SNOPTRBSS)
}
+ symbols[i] = ns
+ elfsym.sym = ns
continue
}
}
// even when we pass needSym == 1 to readelfsym, it might still return nil to skip some unwanted symbols
- if elfsym.sym == nil {
+ if elfsym.sym == 0 {
continue
}
sect = &elfobj.sect[elfsym.shndx]
- if sect.sym == nil {
+ if sect.sym == 0 {
if strings.HasPrefix(elfsym.name, ".Linfo_string") { // clang does this
continue
}
}
s := elfsym.sym
- if s.Outer != nil {
- if s.Attr.DuplicateOK() {
+ if l.OuterSym(s) != 0 {
+ if l.AttrDuplicateOK(s) {
continue
}
- return errorf("duplicate symbol reference: %s in both %s and %s", s.Name, s.Outer.Name, sect.sym.Name)
+ return errorf("duplicate symbol reference: %s in both %s and %s",
+ l.SymName(s), l.SymName(l.OuterSym(s)), l.SymName(sect.sym))
}
- s.Sub = sect.sym.Sub
- sect.sym.Sub = s
- s.Type = sect.sym.Type
- s.Attr |= sym.AttrSubSymbol
- if !s.Attr.CgoExportDynamic() {
- s.SetDynimplib("") // satisfy dynimport
+ sectsb, _ := l.MakeSymbolUpdater(sect.sym)
+ sb, _ := l.MakeSymbolUpdater(s)
+
+ sb.SetType(sectsb.Type())
+ sectsb.PrependSub(s)
+ if !l.AttrCgoExportDynamic(s) {
+ sb.SetDynimplib("") // satisfy dynimport
}
- s.Value = int64(elfsym.value)
- s.Size = int64(elfsym.size)
- s.Outer = sect.sym
- if sect.sym.Type == sym.STEXT {
- if s.Attr.External() && !s.Attr.DuplicateOK() {
- return errorf("%v: duplicate symbol definition", s)
+ sb.SetValue(int64(elfsym.value))
+ sb.SetSize(int64(elfsym.size))
+ if sectsb.Type() == sym.STEXT {
+ if l.AttrExternal(s) && !l.AttrDuplicateOK(s) {
+ return errorf("%s: duplicate symbol definition", sb.Name())
}
- s.Attr |= sym.AttrExternal
+ l.SetAttrExternal(s, true)
}
if elfobj.machine == ElfMachPower64 {
flag := int(elfsym.other) >> 5
if 2 <= flag && flag <= 6 {
- s.SetLocalentry(1 << uint(flag-2))
+ l.SetSymLocalentry(s, 1<<uint(flag-2))
} else if flag == 7 {
- return errorf("%v: invalid sym.other 0x%x", s, elfsym.other)
+ return errorf("%s: invalid sym.other 0x%x", sb.Name(), elfsym.other)
}
}
}
// This keeps textp in increasing address order.
for i := uint(0); i < elfobj.nsect; i++ {
s := elfobj.sect[i].sym
- if s == nil {
+ if s == 0 {
continue
}
- if s.Sub != nil {
- s.Sub = sym.SortSub(s.Sub)
+ sb, _ := l.MakeSymbolUpdater(s)
+ s = sb.Sym()
+ if l.SubSym(s) != 0 {
+ sb.SortSub()
}
- if s.Type == sym.STEXT {
- if s.Attr.OnList() {
- return errorf("symbol %s listed multiple times", s.Name)
+ if sb.Type() == sym.STEXT {
+ if l.AttrOnList(s) {
+ return errorf("symbol %s listed multiple times",
+ l.SymName(s))
}
- s.Attr |= sym.AttrOnList
+ l.SetAttrOnList(s, true)
textp = append(textp, s)
- for s = s.Sub; s != nil; s = s.Sub {
- if s.Attr.OnList() {
- return errorf("symbol %s listed multiple times", s.Name)
+ for ss := l.SubSym(s); ss != 0; ss = l.SubSym(ss) {
+ if l.AttrOnList(ss) {
+ return errorf("symbol %s listed multiple times",
+ l.SymName(ss))
}
- s.Attr |= sym.AttrOnList
- textp = append(textp, s)
+ l.SetAttrOnList(ss, true)
+ textp = append(textp, ss)
}
}
}
rela = 1
}
n := int(rsect.size / uint64(4+4*is64) / uint64(2+rela))
- r := make([]sym.Reloc, n)
+ r := make([]loader.Reloc, n)
p := rsect.base
for j := 0; j < n; j++ {
var add uint64
+ var symIdx int
+ var relocType uint64
+
rp := &r[j]
- var info uint64
if is64 != 0 {
// 64-bit rel/rela
rp.Off = int32(e.Uint64(p))
p = p[8:]
- info = e.Uint64(p)
+ switch arch.Family {
+ case sys.MIPS64:
+ // https://www.linux-mips.org/pub/linux/mips/doc/ABI/elf64-2.4.pdf
+ // The doc shows it's different with general Linux ELF
+ symIdx = int(e.Uint32(p))
+ relocType = uint64(p[7])
+ default:
+ info := e.Uint64(p)
+ relocType = info & 0xffffffff
+ symIdx = int(info >> 32)
+ }
p = p[8:]
if rela != 0 {
add = e.Uint64(p)
rp.Off = int32(e.Uint32(p))
p = p[4:]
- info = uint64(e.Uint32(p))
- info = info>>8<<32 | info&0xff // convert to 64-bit info
+ info := e.Uint32(p)
+ relocType = uint64(info & 0xff)
+ symIdx = int(info >> 8)
p = p[4:]
if rela != 0 {
add = uint64(e.Uint32(p))
}
}
- if info&0xffffffff == 0 { // skip R_*_NONE relocation
+ if relocType == 0 { // skip R_*_NONE relocation
j--
n--
continue
}
- if info>>32 == 0 { // absolute relocation, don't bother reading the null symbol
+ if symIdx == 0 { // absolute relocation, don't bother reading the null symbol
- rp.Sym = nil
+ rp.Sym = 0
} else {
var elfsym ElfSym
- if err := readelfsym(newSym, lookup, l, arch, elfobj, int(info>>32), &elfsym, 0, 0); err != nil {
- if err := readelfsym(newSym, lookup, arch, elfobj, symIdx, &elfsym, 0, 0); err != nil {
++ if err := readelfsym(newSym, lookup, l, arch, elfobj, int(symIdx), &elfsym, 0, 0); err != nil {
return errorf("malformed elf file: %v", err)
}
- elfsym.sym = symbols[info>>32]
+ elfsym.sym = symbols[symIdx]
- if elfsym.sym == nil {
- return errorf("malformed elf file: %s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", sect.sym.Name, j, symIdx, elfsym.name, elfsym.shndx, elfsym.type_)
+ if elfsym.sym == 0 {
- return errorf("malformed elf file: %s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", l.SymName(sect.sym), j, int(info>>32), elfsym.name, elfsym.shndx, elfsym.type_)
++ return errorf("malformed elf file: %s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", l.SymName(sect.sym), j, int(symIdx), elfsym.name, elfsym.shndx, elfsym.type_)
}
rp.Sym = elfsym.sym
}
- rp.Type = objabi.ElfRelocOffset + objabi.RelocType(info)
- rp.Size, err = relSize(arch, pn, uint32(info))
+ rp.Type = objabi.ElfRelocOffset + objabi.RelocType(relocType)
- rp.Siz, err = relSize(arch, pn, uint32(relocType))
++ rp.Size, err = relSize(arch, pn, uint32(relocType))
if err != nil {
return nil, 0, err
}
rp.Add = int64(add)
} else {
// load addend from image
- if rp.Siz == 4 {
+ if rp.Size == 4 {
rp.Add = int64(e.Uint32(sect.base[rp.Off:]))
- } else if rp.Siz == 8 {
+ } else if rp.Size == 8 {
rp.Add = int64(e.Uint64(sect.base[rp.Off:]))
} else {
- return errorf("invalid rela size %d", rp.Siz)
+ return errorf("invalid rela size %d", rp.Size)
}
}
- if rp.Siz == 2 {
+ if rp.Size == 2 {
rp.Add = int64(int16(rp.Add))
}
- if rp.Siz == 4 {
+ if rp.Size == 4 {
rp.Add = int64(int32(rp.Add))
}
}
//print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add);
- sort.Sort(sym.RelocByOff(r[:n]))
+ sort.Sort(loader.RelocByOff(r[:n]))
// just in case
- s := sect.sym
- s.R = r
- s.R = s.R[:n]
+ sb, _ := l.MakeSymbolUpdater(sect.sym)
+ r = r[:n]
+ sb.SetRelocs(r)
}
return textp, ehdrFlags, nil
return nil
}
-func readelfsym(newSym, lookup lookupFunc, arch *sys.Arch, elfobj *ElfObj, i int, elfsym *ElfSym, needSym int, localSymVersion int) (err error) {
+func readelfsym(newSym, lookup func(string, int) loader.Sym, l *loader.Loader, arch *sys.Arch, elfobj *ElfObj, i int, elfsym *ElfSym, needSym int, localSymVersion int) (err error) {
if i >= elfobj.nsymtab || i < 0 {
err = fmt.Errorf("invalid elf symbol index")
return err
elfsym.other = b.Other
}
- var s *sym.Symbol
+ var s loader.Sym
+
if elfsym.name == "_GLOBAL_OFFSET_TABLE_" {
elfsym.name = ".got"
}
// TODO(minux): correctly handle __i686.get_pc_thunk.bx without
// set dupok generally. See https://golang.org/cl/5823055
// comment #5 for details.
- if s != nil && elfsym.other == 2 {
- s.Attr |= sym.AttrDuplicateOK | sym.AttrVisibilityHidden
+ if s != 0 && elfsym.other == 2 {
+ if !l.IsExternal(s) {
+ _, s = l.MakeSymbolUpdater(s)
+ }
+ l.SetAttrDuplicateOK(s, true)
+ l.SetAttrVisibilityHidden(s, true)
}
}
// so put it in the hash table.
if needSym != 0 {
s = lookup(elfsym.name, localSymVersion)
- s.Attr |= sym.AttrVisibilityHidden
+ l.SetAttrVisibilityHidden(s, true)
}
-
break
}
// reduce mem use, but also (possibly) make it harder
// to debug problems.
s = newSym(elfsym.name, localSymVersion)
-
- s.Attr |= sym.AttrVisibilityHidden
+ l.SetAttrVisibilityHidden(s, true)
}
case ElfSymBindWeak:
if needSym != 0 {
s = lookup(elfsym.name, 0)
if elfsym.other == 2 {
- s.Attr |= sym.AttrVisibilityHidden
+ l.SetAttrVisibilityHidden(s, true)
}
// Allow weak symbols to be duplicated when already defined.
- if s.Outer != nil {
- s.Attr |= sym.AttrDuplicateOK
+ if l.OuterSym(s) != 0 {
+ l.SetAttrDuplicateOK(s, true)
}
}
// TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
// sense and should be removed when someone has thought about it properly.
- if s != nil && s.Type == 0 && !s.Attr.VisibilityHidden() && elfsym.type_ != ElfSymTypeSection {
- s.Type = sym.SXREF
+ if s != 0 && l.SymType(s) == 0 && !l.AttrVisibilityHidden(s) && elfsym.type_ != ElfSymTypeSection {
+ sb, _ := l.MakeSymbolUpdater(s)
+ sb.SetType(sym.SXREF)
}
elfsym.sym = s
// performance.
const (
- AMD64 = uint32(sys.AMD64)
- ARM = uint32(sys.ARM)
- ARM64 = uint32(sys.ARM64)
- I386 = uint32(sys.I386)
- PPC64 = uint32(sys.PPC64)
- S390X = uint32(sys.S390X)
+ AMD64 = uint32(sys.AMD64)
+ ARM = uint32(sys.ARM)
+ ARM64 = uint32(sys.ARM64)
+ I386 = uint32(sys.I386)
+ PPC64 = uint32(sys.PPC64)
+ S390X = uint32(sys.S390X)
+ MIPS = uint32(sys.MIPS)
+ MIPS64 = uint32(sys.MIPS64)
)
switch uint32(arch.Family) | elftype<<16 {
default:
return 0, fmt.Errorf("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype)
+ case MIPS | uint32(elf.R_MIPS_HI16)<<16,
+ MIPS | uint32(elf.R_MIPS_LO16)<<16,
+ MIPS | uint32(elf.R_MIPS_GOT16)<<16,
+ MIPS | uint32(elf.R_MIPS_GPREL16)<<16,
+ MIPS | uint32(elf.R_MIPS_GOT_PAGE)<<16,
+ MIPS | uint32(elf.R_MIPS_JALR)<<16,
+ MIPS | uint32(elf.R_MIPS_GOT_OFST)<<16,
+ MIPS64 | uint32(elf.R_MIPS_HI16)<<16,
+ MIPS64 | uint32(elf.R_MIPS_LO16)<<16,
+ MIPS64 | uint32(elf.R_MIPS_GOT16)<<16,
+ MIPS64 | uint32(elf.R_MIPS_GPREL16)<<16,
+ MIPS64 | uint32(elf.R_MIPS_GOT_PAGE)<<16,
+ MIPS64 | uint32(elf.R_MIPS_JALR)<<16,
+ MIPS64 | uint32(elf.R_MIPS_GOT_OFST)<<16:
+ return 4, nil
+
case S390X | uint32(elf.R_390_8)<<16:
return 1, nil