]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.link] all: merge branch 'master' into dev.link
authorCherry Zhang <cherryyz@google.com>
Fri, 31 Jan 2020 19:45:52 +0000 (14:45 -0500)
committerCherry Zhang <cherryyz@google.com>
Fri, 31 Jan 2020 19:45:52 +0000 (14:45 -0500)
It has been a while we have not done this.

Merge conflict resolution:
- deleted/rewritten code modified on master
  - CL 214286, ported in CL 217317
    (cmd/internal/obj/objfile.go)
  - CL 210678, it already includes a fix to new code
    (cmd/link/internal/ld/deadcode.go)
  - CL 209317, applied in this CL
    (cmd/link/internal/loadelf/ldelf.go)

Change-Id: Ie927ea6a1d69ce49e8d03e56148cb2725e377876

1  2 
src/cmd/compile/internal/gc/main.go
src/cmd/dist/buildtool.go
src/cmd/link/internal/ld/deadcode2.go
src/cmd/link/internal/loadelf/ldelf.go

index aa690921bce8c0c7fccfe3f2b01a58778ba1973f,fad2bdfcd45980d1fadfa35f9d0da69116cd8ed5..9b89d7b8b1f0f253fe519bbf618fb11f65a921f5
@@@ -277,6 -277,7 +277,6 @@@ func Main(archInit func(*Arch)) 
        flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`")
        flag.BoolVar(&smallFrames, "smallframes", false, "reduce the size limit for stack allocated objects")
        flag.BoolVar(&Ctxt.UseBASEntries, "dwarfbasentries", Ctxt.UseBASEntries, "use base address selection entries in DWARF")
 -      flag.BoolVar(&Ctxt.Flag_newobj, "newobj", false, "use new object file format")
        flag.StringVar(&jsonLogOpt, "json", "", "version,destination for JSON compiler/optimizer logging")
  
        objabi.Flagparse(usage)
        // Record flags that affect the build result. (And don't
        // record flags that don't, since that would cause spurious
        // changes in the binary.)
 -      recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes", "newobj")
 +      recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes")
  
        if smallFrames {
                maxStackVarSize = 128 * 1024
        types.Sconv = func(s *types.Sym, flag, mode int) string {
                return sconv(s, FmtFlag(flag), fmtMode(mode))
        }
-       types.Tconv = func(t *types.Type, flag, mode, depth int) string {
-               return tconv(t, FmtFlag(flag), fmtMode(mode), depth)
+       types.Tconv = func(t *types.Type, flag, mode int) string {
+               return tconv(t, FmtFlag(flag), fmtMode(mode))
        }
        types.FormatSym = func(sym *types.Sym, s fmt.State, verb rune, mode int) {
                symFormat(sym, s, verb, fmtMode(mode))
index 12baccbc4fce8c96fdce85aedd0f0a14269f4251,a07e64b472b38762026acc82ee41a5ba654b254d..118800e8da57d36f784b388282c6af8f71f6da07
@@@ -45,10 -45,11 +45,11 @@@ var bootstrapDirs = []string
        "cmd/compile/internal/mips",
        "cmd/compile/internal/mips64",
        "cmd/compile/internal/ppc64",
-       "cmd/compile/internal/types",
+       "cmd/compile/internal/riscv64",
        "cmd/compile/internal/s390x",
        "cmd/compile/internal/ssa",
        "cmd/compile/internal/syntax",
+       "cmd/compile/internal/types",
        "cmd/compile/internal/x86",
        "cmd/compile/internal/wasm",
        "cmd/internal/bio",
@@@ -80,6 -81,7 +81,6 @@@
        "cmd/link/internal/loadxcoff",
        "cmd/link/internal/mips",
        "cmd/link/internal/mips64",
 -      "cmd/link/internal/objfile",
        "cmd/link/internal/ppc64",
        "cmd/link/internal/riscv64",
        "cmd/link/internal/s390x",
index 915ad1d9440aeeb699f855ec40fd79ab2260769d,9197c700f586d41b96812ae83c4996be56b63d93..3d3a03215e50f67bc85e25ef5830986f443fbb82
@@@ -113,7 -113,7 +113,7 @@@ func (d *deadcodePass2) init() 
        }
  
        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)
@@@ -195,9 -195,9 +195,9 @@@ func (d *deadcodePass2) flood() 
  }
  
  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
                }
@@@ -239,7 -239,7 +239,7 @@@ func deadcode2(ctxt *Link) 
                // 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)
                                }
                        }
                }
@@@ -318,7 -318,7 +318,7 @@@ func (d *deadcodePass2) decodeMethodSig
                        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(')')
@@@ -391,6 -391,47 +391,6 @@@ func (d *deadcodePass2) decodetypeMetho
        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.
index 7d613c7a6d983b4bec579c43b71ddbe83f919162,1962d76338f8c08321b785f342e9993c7d6e24a7..b1e420cc30cfe662ffec3e6f3314ae86de1cfd14
@@@ -1,4 -1,4 +1,4 @@@
 -// 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.
  
@@@ -282,7 -282,7 +282,7 @@@ type ElfSect struct 
        align   uint64
        entsize uint64
        base    []byte
 -      sym     *sym.Symbol
 +      sym     loader.Sym
  }
  
  type ElfObj struct {
@@@ -320,7 -320,7 +320,7 @@@ type ElfSym struct 
        type_ uint8
        other uint8
        shndx uint16
 -      sym   *sym.Symbol
 +      sym   loader.Sym
  }
  
  var ElfMagic = [4]uint8{0x7F, 'E', 'L', 'F'}
@@@ -452,22 -452,32 +452,22 @@@ func parseArmAttributes(e binary.ByteOr
        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
@@@ -1015,7 -1031,7 +1028,7 @@@ func elfmap(elfobj *ElfObj, sect *ElfSe
        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
  
@@@ -1148,18 -1160,36 +1161,36 @@@ func relSize(arch *sys.Arch, pn string
        // 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