[lld] r268178 - ELF: New symbol table design.

Rafael EspĂ­ndola via llvm-commits llvm-commits at lists.llvm.org
Sun May 1 10:31:24 PDT 2016


This is really awesome. Thank you so much.

Cheers,
Rafael


On 1 May 2016 at 00:55, Peter Collingbourne via llvm-commits
<llvm-commits at lists.llvm.org> wrote:
> Author: pcc
> Date: Sat Apr 30 23:55:03 2016
> New Revision: 268178
>
> URL: http://llvm.org/viewvc/llvm-project?rev=268178&view=rev
> Log:
> ELF: New symbol table design.
>
> This patch implements a new design for the symbol table that stores
> SymbolBodies within a memory region of the Symbol object. Symbols are mutated
> by constructing SymbolBodies in place over existing SymbolBodies, rather
> than by mutating pointers. As mentioned in the initial proposal [1], this
> memory layout helps reduce the cache miss rate by improving memory locality.
>
> Performance numbers:
>
>            old(s) new(s)
> Without debug info:
> chrome      7.178  6.432 (-11.5%)
> LLVMgold.so 0.505  0.502 (-0.5%)
> clang       0.954  0.827 (-15.4%)
> llvm-as     0.052  0.045 (-15.5%)
> With debug info:
> scylla      5.695  5.613 (-1.5%)
> clang      14.396 14.143 (-1.8%)
>
> Performance counter results show that the fewer required indirections is
> indeed the cause of the improved performance. For example, when linking
> chrome, stalled cycles decreases from 14,556,444,002 to 12,959,238,310, and
> instructions per cycle increases from 0.78 to 0.83. We are also executing
> many fewer instructions (15,516,401,933 down to 15,002,434,310), probably
> because we spend less time allocating SymbolBodies.
>
> The new mechanism by which symbols are added to the symbol table is by calling
> add* functions on the SymbolTable.
>
> In this patch, I handle local symbols by storing them inside "unparented"
> SymbolBodies. This is suboptimal, but if we do want to try to avoid allocating
> these SymbolBodies, we can probably do that separately.
>
> I also removed a few members from the SymbolBody class that were only being
> used to pass information from the input file to the symbol table.
>
> This patch implements the new design for the ELF linker only. I intend to
> prepare a similar patch for the COFF linker.
>
> [1] http://lists.llvm.org/pipermail/llvm-dev/2016-April/098832.html
>
> Differential Revision: http://reviews.llvm.org/D19752
>
> Modified:
>     lld/trunk/ELF/Driver.cpp
>     lld/trunk/ELF/InputFiles.cpp
>     lld/trunk/ELF/InputFiles.h
>     lld/trunk/ELF/LTO.cpp
>     lld/trunk/ELF/MarkLive.cpp
>     lld/trunk/ELF/OutputSections.cpp
>     lld/trunk/ELF/SymbolTable.cpp
>     lld/trunk/ELF/SymbolTable.h
>     lld/trunk/ELF/Symbols.cpp
>     lld/trunk/ELF/Symbols.h
>     lld/trunk/ELF/Writer.cpp
>     lld/trunk/docs/NewLLD.rst
>     lld/trunk/test/ELF/lto/common2.ll
>     lld/trunk/test/ELF/relocation-copy-alias.s
>
> Modified: lld/trunk/ELF/Driver.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=268178&r1=268177&r2=268178&view=diff
> ==============================================================================
> --- lld/trunk/ELF/Driver.cpp (original)
> +++ lld/trunk/ELF/Driver.cpp Sat Apr 30 23:55:03 2016
> @@ -447,6 +447,7 @@ void LinkerDriver::createFiles(opt::Inpu
>  // all linker scripts have already been parsed.
>  template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
>    SymbolTable<ELFT> Symtab;
> +  elf::Symtab<ELFT>::X = &Symtab;
>
>    std::unique_ptr<TargetInfo> TI(createTarget());
>    Target = TI.get();
> @@ -468,7 +469,7 @@ template <class ELFT> void LinkerDriver:
>    if (!Config->Entry.empty()) {
>      StringRef S = Config->Entry;
>      if (S.getAsInteger(0, Config->EntryAddr))
> -      Config->EntrySym = Symtab.addUndefined(S)->Backref;
> +      Config->EntrySym = Symtab.addUndefined(S);
>    }
>
>    for (std::unique_ptr<InputFile> &F : Files)
>
> Modified: lld/trunk/ELF/InputFiles.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.cpp?rev=268178&r1=268177&r2=268178&view=diff
> ==============================================================================
> --- lld/trunk/ELF/InputFiles.cpp (original)
> +++ lld/trunk/ELF/InputFiles.cpp Sat Apr 30 23:55:03 2016
> @@ -11,6 +11,7 @@
>  #include "Driver.h"
>  #include "Error.h"
>  #include "InputSection.h"
> +#include "SymbolTable.h"
>  #include "Symbols.h"
>  #include "llvm/ADT/STLExtras.h"
>  #include "llvm/CodeGen/Analysis.h"
> @@ -330,11 +331,14 @@ SymbolBody *elf::ObjectFile<ELFT>::creat
>
>    switch (Sym->st_shndx) {
>    case SHN_UNDEF:
> -    return new (Alloc) Undefined(Name, Binding, Sym->st_other, Sym->getType(),
> -                                 /*IsBitcode*/ false);
> +    return Symtab<ELFT>::X
> +        ->addUndefined(Name, Binding, Sym->st_other, Sym->getType(), this)
> +        ->body();
>    case SHN_COMMON:
> -    return new (Alloc) DefinedCommon(Name, Sym->st_size, Sym->st_value, Binding,
> -                                     Sym->st_other, Sym->getType());
> +    return Symtab<ELFT>::X
> +        ->addCommon(Name, Sym->st_size, Sym->st_value, Binding, Sym->st_other,
> +                    Sym->getType(), this)
> +        ->body();
>    }
>
>    switch (Binding) {
> @@ -344,22 +348,19 @@ SymbolBody *elf::ObjectFile<ELFT>::creat
>    case STB_WEAK:
>    case STB_GNU_UNIQUE:
>      if (Sec == &InputSection<ELFT>::Discarded)
> -      return new (Alloc) Undefined(Name, Binding, Sym->st_other, Sym->getType(),
> -                                   /*IsBitcode*/ false);
> -    return new (Alloc) DefinedRegular<ELFT>(Name, *Sym, Sec);
> +      return Symtab<ELFT>::X
> +          ->addUndefined(Name, Binding, Sym->st_other, Sym->getType(), this)
> +          ->body();
> +    return Symtab<ELFT>::X->addRegular(Name, *Sym, Sec)->body();
>    }
>  }
>
> -void ArchiveFile::parse() {
> +template <class ELFT> void ArchiveFile::parse() {
>    File = check(Archive::create(MB), "failed to parse archive");
>
> -  // Allocate a buffer for Lazy objects.
> -  size_t NumSyms = File->getNumberOfSymbols();
> -  LazySymbols.reserve(NumSyms);
> -
>    // Read the symbol table to construct Lazy objects.
>    for (const Archive::Symbol &Sym : File->symbols())
> -    LazySymbols.emplace_back(this, Sym);
> +    Symtab<ELFT>::X->addLazyArchive(this, Sym);
>  }
>
>  // Returns a buffer pointing to a member file containing a given symbol.
> @@ -487,8 +488,6 @@ template <class ELFT> void SharedFile<EL
>    std::vector<const Elf_Verdef *> Verdefs = parseVerdefs(Versym);
>
>    Elf_Sym_Range Syms = this->getElfSymbols(true);
> -  uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
> -  SymbolBodies.reserve(NumSymbols);
>    for (const Elf_Sym &Sym : Syms) {
>      unsigned VersymIndex = 0;
>      if (Versym) {
> @@ -507,16 +506,12 @@ template <class ELFT> void SharedFile<EL
>        if (VersymIndex == 0 || (VersymIndex & VERSYM_HIDDEN))
>          continue;
>      }
> -    SymbolBodies.emplace_back(this, Name, Sym, Verdefs[VersymIndex]);
> +    Symtab<ELFT>::X->addShared(this, Name, Sym, Verdefs[VersymIndex]);
>    }
>  }
>
>  BitcodeFile::BitcodeFile(MemoryBufferRef M) : InputFile(BitcodeKind, M) {}
>
> -bool BitcodeFile::classof(const InputFile *F) {
> -  return F->kind() == BitcodeKind;
> -}
> -
>  static uint8_t getGvVisibility(const GlobalValue *GV) {
>    switch (GV->getVisibility()) {
>    case GlobalValue::DefaultVisibility:
> @@ -529,21 +524,30 @@ static uint8_t getGvVisibility(const Glo
>    llvm_unreachable("unknown visibility");
>  }
>
> -SymbolBody *
> -BitcodeFile::createBody(const DenseSet<const Comdat *> &KeptComdats,
> -                              const IRObjectFile &Obj,
> -                              const BasicSymbolRef &Sym,
> -                              const GlobalValue *GV) {
> +template <class ELFT>
> +Symbol *BitcodeFile::createSymbol(const DenseSet<const Comdat *> &KeptComdats,
> +                                  const IRObjectFile &Obj,
> +                                  const BasicSymbolRef &Sym) {
> +  const GlobalValue *GV = Obj.getSymbolGV(Sym.getRawDataRefImpl());
> +
>    SmallString<64> Name;
>    raw_svector_ostream OS(Name);
>    Sym.printName(OS);
>    StringRef NameRef = Saver.save(StringRef(Name));
> -  SymbolBody *Body;
>
>    uint32_t Flags = Sym.getFlags();
>    bool IsWeak = Flags & BasicSymbolRef::SF_Weak;
>    uint32_t Binding = IsWeak ? STB_WEAK : STB_GLOBAL;
>
> +  uint8_t Type = STT_NOTYPE;
> +  bool CanOmitFromDynSym = false;
> +  // FIXME: Expose a thread-local flag for module asm symbols.
> +  if (GV) {
> +    if (GV->isThreadLocal())
> +      Type = STT_TLS;
> +    CanOmitFromDynSym = canBeOmittedFromSymbolTable(GV);
> +  }
> +
>    uint8_t Visibility;
>    if (GV)
>      Visibility = getGvVisibility(GV);
> @@ -554,46 +558,28 @@ BitcodeFile::createBody(const DenseSet<c
>
>    if (GV)
>      if (const Comdat *C = GV->getComdat())
> -      if (!KeptComdats.count(C)) {
> -        Body = new (Alloc) Undefined(NameRef, Binding, Visibility, /*Type*/ 0,
> -                                     /*IsBitcode*/ true);
> -        return Body;
> -      }
> +      if (!KeptComdats.count(C))
> +        return Symtab<ELFT>::X->addUndefined(NameRef, Binding, Visibility, Type,
> +                                             this);
>
>    const Module &M = Obj.getModule();
>    if (Flags & BasicSymbolRef::SF_Undefined)
> -    return new (Alloc) Undefined(NameRef, Binding, Visibility, /*Type*/ 0,
> -                                 /*IsBitcode*/ true);
> +    return Symtab<ELFT>::X->addUndefined(NameRef, Binding, Visibility, Type,
> +                                         this);
>    if (Flags & BasicSymbolRef::SF_Common) {
>      // FIXME: Set SF_Common flag correctly for module asm symbols, and expose
>      // size and alignment.
>      assert(GV);
>      const DataLayout &DL = M.getDataLayout();
>      uint64_t Size = DL.getTypeAllocSize(GV->getValueType());
> -    return new (Alloc) DefinedCommon(NameRef, Size, GV->getAlignment(), Binding,
> -                                     Visibility, /*Type*/ 0);
> +    return Symtab<ELFT>::X->addCommon(NameRef, Size, GV->getAlignment(),
> +                                      Binding, Visibility, STT_OBJECT, this);
>    }
> -  return new (Alloc) DefinedBitcode(NameRef, IsWeak, Visibility);
> +  return Symtab<ELFT>::X->addBitcode(NameRef, IsWeak, Visibility, Type,
> +                                     CanOmitFromDynSym, this);
>  }
>
> -SymbolBody *
> -BitcodeFile::createSymbolBody(const DenseSet<const Comdat *> &KeptComdats,
> -                              const IRObjectFile &Obj,
> -                              const BasicSymbolRef &Sym) {
> -  const GlobalValue *GV = Obj.getSymbolGV(Sym.getRawDataRefImpl());
> -  SymbolBody *Body = createBody(KeptComdats, Obj, Sym, GV);
> -
> -  // FIXME: Expose a thread-local flag for module asm symbols.
> -  if (GV) {
> -    if (GV->isThreadLocal())
> -      Body->Type = STT_TLS;
> -    Body->CanOmitFromDynSym = canBeOmittedFromSymbolTable(GV);
> -  }
> -  return Body;
> -}
> -
> -bool BitcodeFile::shouldSkip(const BasicSymbolRef &Sym) {
> -  uint32_t Flags = Sym.getFlags();
> +bool BitcodeFile::shouldSkip(uint32_t Flags) {
>    if (!(Flags & BasicSymbolRef::SF_Global))
>      return true;
>    if (Flags & BasicSymbolRef::SF_FormatSpecific)
> @@ -601,6 +587,7 @@ bool BitcodeFile::shouldSkip(const Basic
>    return false;
>  }
>
> +template <class ELFT>
>  void BitcodeFile::parse(DenseSet<StringRef> &ComdatGroups) {
>    Obj = check(IRObjectFile::create(MB, Driver->Context));
>    const Module &M = Obj->getModule();
> @@ -613,8 +600,8 @@ void BitcodeFile::parse(DenseSet<StringR
>    }
>
>    for (const BasicSymbolRef &Sym : Obj->symbols())
> -    if (!shouldSkip(Sym))
> -      SymbolBodies.push_back(createSymbolBody(KeptComdats, *Obj, Sym));
> +    if (!shouldSkip(Sym.getFlags()))
> +      Symbols.push_back(createSymbol<ELFT>(KeptComdats, *Obj, Sym));
>  }
>
>  template <typename T>
> @@ -675,9 +662,10 @@ std::unique_ptr<InputFile> elf::createSh
>    return createELFFile<SharedFile>(MB);
>  }
>
> +template <class ELFT>
>  void LazyObjectFile::parse() {
>    for (StringRef Sym : getSymbols())
> -    LazySymbols.emplace_back(Sym, this->MB);
> +    Symtab<ELFT>::X->addLazyObject(Sym, this->MB);
>  }
>
>  template <class ELFT> std::vector<StringRef> LazyObjectFile::getElfSymbols() {
> @@ -707,9 +695,10 @@ std::vector<StringRef> LazyObjectFile::g
>        check(IRObjectFile::create(this->MB, Context));
>    std::vector<StringRef> V;
>    for (const BasicSymbolRef &Sym : Obj->symbols()) {
> -    if (BitcodeFile::shouldSkip(Sym))
> +    uint32_t Flags = Sym.getFlags();
> +    if (BitcodeFile::shouldSkip(Flags))
>        continue;
> -    if (Sym.getFlags() & BasicSymbolRef::SF_Undefined)
> +    if (Flags & BasicSymbolRef::SF_Undefined)
>        continue;
>      SmallString<64> Name;
>      raw_svector_ostream OS(Name);
> @@ -737,6 +726,25 @@ std::vector<StringRef> LazyObjectFile::g
>    return getElfSymbols<ELF64BE>();
>  }
>
> +template void ArchiveFile::parse<ELF32LE>();
> +template void ArchiveFile::parse<ELF32BE>();
> +template void ArchiveFile::parse<ELF64LE>();
> +template void ArchiveFile::parse<ELF64BE>();
> +
> +template void
> +BitcodeFile::parse<ELF32LE>(llvm::DenseSet<StringRef> &ComdatGroups);
> +template void
> +BitcodeFile::parse<ELF32BE>(llvm::DenseSet<StringRef> &ComdatGroups);
> +template void
> +BitcodeFile::parse<ELF64LE>(llvm::DenseSet<StringRef> &ComdatGroups);
> +template void
> +BitcodeFile::parse<ELF64BE>(llvm::DenseSet<StringRef> &ComdatGroups);
> +
> +template void LazyObjectFile::parse<ELF32LE>();
> +template void LazyObjectFile::parse<ELF32BE>();
> +template void LazyObjectFile::parse<ELF64LE>();
> +template void LazyObjectFile::parse<ELF64BE>();
> +
>  template class elf::ELFFileBase<ELF32LE>;
>  template class elf::ELFFileBase<ELF32BE>;
>  template class elf::ELFFileBase<ELF64LE>;
>
> Modified: lld/trunk/ELF/InputFiles.h
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=268178&r1=268177&r2=268178&view=diff
> ==============================================================================
> --- lld/trunk/ELF/InputFiles.h (original)
> +++ lld/trunk/ELF/InputFiles.h Sat Apr 30 23:55:03 2016
> @@ -89,13 +89,14 @@ public:
>
>    uint32_t getSectionIndex(const Elf_Sym &Sym) const;
>
> +  Elf_Sym_Range getElfSymbols(bool OnlyGlobals);
> +
>  protected:
>    llvm::object::ELFFile<ELFT> ELFObj;
>    const Elf_Shdr *Symtab = nullptr;
>    ArrayRef<Elf_Word> SymtabSHNDX;
>    StringRef StringTable;
>    void initStringTable();
> -  Elf_Sym_Range getElfSymbols(bool OnlyGlobals);
>  };
>
>  // .o file.
> @@ -126,7 +127,7 @@ public:
>    InputSectionBase<ELFT> *getSection(const Elf_Sym &Sym) const;
>
>    SymbolBody &getSymbolBody(uint32_t SymbolIndex) const {
> -    return SymbolBodies[SymbolIndex]->repl();
> +    return *SymbolBodies[SymbolIndex];
>    }
>
>    template <typename RelT> SymbolBody &getRelocTargetSym(const RelT &Rel) const {
> @@ -183,9 +184,7 @@ public:
>      return F->kind() == LazyObjectKind;
>    }
>
> -  void parse();
> -
> -  llvm::MutableArrayRef<LazyObject> getLazySymbols() { return LazySymbols; }
> +  template <class ELFT> void parse();
>
>  private:
>    std::vector<StringRef> getSymbols();
> @@ -194,7 +193,6 @@ private:
>
>    llvm::BumpPtrAllocator Alloc;
>    llvm::StringSaver Saver{Alloc};
> -  std::vector<LazyObject> LazySymbols;
>  };
>
>  // An ArchiveFile object represents a .a file.
> @@ -202,43 +200,36 @@ class ArchiveFile : public InputFile {
>  public:
>    explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {}
>    static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
> -  void parse();
> +  template <class ELFT> void parse();
>
>    // Returns a memory buffer for a given symbol. An empty memory buffer
>    // is returned if we have already returned the same memory buffer.
>    // (So that we don't instantiate same members more than once.)
>    MemoryBufferRef getMember(const Archive::Symbol *Sym);
>
> -  llvm::MutableArrayRef<LazyArchive> getLazySymbols() { return LazySymbols; }
> -
>  private:
>    std::unique_ptr<Archive> File;
> -  std::vector<LazyArchive> LazySymbols;
>    llvm::DenseSet<uint64_t> Seen;
>  };
>
>  class BitcodeFile : public InputFile {
>  public:
>    explicit BitcodeFile(MemoryBufferRef M);
> -  static bool classof(const InputFile *F);
> +  static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
> +  template <class ELFT>
>    void parse(llvm::DenseSet<StringRef> &ComdatGroups);
> -  ArrayRef<SymbolBody *> getSymbols() { return SymbolBodies; }
> -  static bool shouldSkip(const llvm::object::BasicSymbolRef &Sym);
> +  ArrayRef<Symbol *> getSymbols() { return Symbols; }
> +  static bool shouldSkip(uint32_t Flags);
>    std::unique_ptr<llvm::object::IRObjectFile> Obj;
>
>  private:
> -  std::vector<SymbolBody *> SymbolBodies;
> +  std::vector<Symbol *> Symbols;
>    llvm::BumpPtrAllocator Alloc;
>    llvm::StringSaver Saver{Alloc};
> -  SymbolBody *
> -  createSymbolBody(const llvm::DenseSet<const llvm::Comdat *> &KeptComdats,
> -                   const llvm::object::IRObjectFile &Obj,
> -                   const llvm::object::BasicSymbolRef &Sym);
> -  SymbolBody *
> -  createBody(const llvm::DenseSet<const llvm::Comdat *> &KeptComdats,
> -             const llvm::object::IRObjectFile &Obj,
> -             const llvm::object::BasicSymbolRef &Sym,
> -             const llvm::GlobalValue *GV);
> +  template <class ELFT>
> +  Symbol *createSymbol(const llvm::DenseSet<const llvm::Comdat *> &KeptComdats,
> +                       const llvm::object::IRObjectFile &Obj,
> +                       const llvm::object::BasicSymbolRef &Sym);
>  };
>
>  // .so file.
> @@ -251,7 +242,6 @@ template <class ELFT> class SharedFile :
>    typedef typename ELFT::Versym Elf_Versym;
>    typedef typename ELFT::Verdef Elf_Verdef;
>
> -  std::vector<SharedSymbol<ELFT>> SymbolBodies;
>    std::vector<StringRef> Undefs;
>    StringRef SoName;
>    const Elf_Shdr *VersymSec = nullptr;
> @@ -259,9 +249,6 @@ template <class ELFT> class SharedFile :
>
>  public:
>    StringRef getSoName() const { return SoName; }
> -  llvm::MutableArrayRef<SharedSymbol<ELFT>> getSharedSymbols() {
> -    return SymbolBodies;
> -  }
>    const Elf_Shdr *getSection(const Elf_Sym &Sym) const;
>    llvm::ArrayRef<StringRef> getUndefinedSymbols() { return Undefs; }
>
>
> Modified: lld/trunk/ELF/LTO.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LTO.cpp?rev=268178&r1=268177&r2=268178&view=diff
> ==============================================================================
> --- lld/trunk/ELF/LTO.cpp (original)
> +++ lld/trunk/ELF/LTO.cpp Sat Apr 30 23:55:03 2016
> @@ -76,14 +76,14 @@ static void runLTOPasses(Module &M, Targ
>  }
>
>  static bool shouldInternalize(const SmallPtrSet<GlobalValue *, 8> &Used,
> -                              SymbolBody &B, GlobalValue *GV) {
> -  if (B.Backref->IsUsedInRegularObj)
> +                              Symbol *S, GlobalValue *GV) {
> +  if (S->IsUsedInRegularObj)
>      return false;
>
>    if (Used.count(GV))
>      return false;
>
> -  return !B.Backref->includeInDynsym();
> +  return !S->includeInDynsym();
>  }
>
>  BitcodeCompiler::BitcodeCompiler()
> @@ -94,7 +94,7 @@ void BitcodeCompiler::add(BitcodeFile &F
>    std::unique_ptr<IRObjectFile> Obj = std::move(F.Obj);
>    std::vector<GlobalValue *> Keep;
>    unsigned BodyIndex = 0;
> -  ArrayRef<SymbolBody *> Bodies = F.getSymbols();
> +  ArrayRef<Symbol *> Syms = F.getSymbols();
>
>    Module &M = Obj->getModule();
>    if (M.getDataLayoutStr().empty())
> @@ -106,19 +106,30 @@ void BitcodeCompiler::add(BitcodeFile &F
>    SmallPtrSet<GlobalValue *, 8> Used;
>    collectUsedGlobalVariables(M, Used, /* CompilerUsed */ false);
>
> +  // This function is called if we know that the combined LTO object will
> +  // provide a definition of a symbol. It undefines the symbol so that the
> +  // definition in the combined LTO object will replace it when parsed.
> +  auto Undefine = [](Symbol *S) {
> +    replaceBody<Undefined>(S, S->body()->getName(), STV_DEFAULT, 0);
> +  };
> +
>    for (const BasicSymbolRef &Sym : Obj->symbols()) {
> +    uint32_t Flags = Sym.getFlags();
>      GlobalValue *GV = Obj->getSymbolGV(Sym.getRawDataRefImpl());
> -    // Ignore module asm symbols.
> -    if (!GV)
> -      continue;
> -    if (GV->hasAppendingLinkage()) {
> +    if (GV && GV->hasAppendingLinkage())
>        Keep.push_back(GV);
> +    if (BitcodeFile::shouldSkip(Flags))
>        continue;
> -    }
> -    if (BitcodeFile::shouldSkip(Sym))
> +    Symbol *S = Syms[BodyIndex++];
> +    if (Flags & BasicSymbolRef::SF_Undefined)
>        continue;
> -    SymbolBody *B = Bodies[BodyIndex++];
> -    if (!B || &B->repl() != B || !isa<DefinedBitcode>(B))
> +    if (!GV) {
> +      // Module asm symbol.
> +      Undefine(S);
> +      continue;
> +    }
> +    auto *B = dyn_cast<DefinedBitcode>(S->body());
> +    if (!B || B->File != &F)
>        continue;
>      switch (GV->getLinkage()) {
>      default:
> @@ -136,8 +147,10 @@ void BitcodeCompiler::add(BitcodeFile &F
>      // we imported the symbols and satisfied undefined references
>      // to it. We can't just change linkage here because otherwise
>      // the IRMover will just rename the symbol.
> -    if (shouldInternalize(Used, *B, GV))
> +    if (shouldInternalize(Used, S, GV))
>        InternalizedSyms.insert(GV->getName());
> +    else
> +      Undefine(S);
>
>      Keep.push_back(GV);
>    }
>
> Modified: lld/trunk/ELF/MarkLive.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/MarkLive.cpp?rev=268178&r1=268177&r2=268178&view=diff
> ==============================================================================
> --- lld/trunk/ELF/MarkLive.cpp (original)
> +++ lld/trunk/ELF/MarkLive.cpp Sat Apr 30 23:55:03 2016
> @@ -137,15 +137,14 @@ template <class ELFT> void elf::markLive
>        Q.push_back(S);
>    };
>
> -  auto MarkSymbol = [&](SymbolBody *Sym) {
> -    if (Sym)
> -      if (auto *D = dyn_cast<DefinedRegular<ELFT>>(Sym))
> -        Enqueue({D->Section, D->Value});
> +  auto MarkSymbol = [&](const SymbolBody *Sym) {
> +    if (auto *D = dyn_cast_or_null<DefinedRegular<ELFT>>(Sym))
> +      Enqueue({D->Section, D->Value});
>    };
>
>    // Add GC root symbols.
>    if (Config->EntrySym)
> -    MarkSymbol(Config->EntrySym->Body);
> +    MarkSymbol(Config->EntrySym->body());
>    MarkSymbol(Symtab->find(Config->Init));
>    MarkSymbol(Symtab->find(Config->Fini));
>    for (StringRef S : Config->Undefined)
> @@ -155,7 +154,7 @@ template <class ELFT> void elf::markLive
>    // file can interrupt other ELF file's symbols at runtime.
>    for (const Symbol *S : Symtab->getSymbols())
>      if (S->includeInDynsym())
> -      MarkSymbol(S->Body);
> +      MarkSymbol(S->body());
>
>    // Preserve special sections and those which are specified in linker
>    // script KEEP command.
>
> Modified: lld/trunk/ELF/OutputSections.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=268178&r1=268177&r2=268178&view=diff
> ==============================================================================
> --- lld/trunk/ELF/OutputSections.cpp (original)
> +++ lld/trunk/ELF/OutputSections.cpp Sat Apr 30 23:55:03 2016
> @@ -144,9 +144,9 @@ template <class ELFT> void GotSection<EL
>  }
>
>  template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
> -  if (Sym.hasGlobalDynIndex())
> +  if (Sym.symbol()->GlobalDynIndex != -1U)
>      return false;
> -  Sym.GlobalDynIndex = Entries.size();
> +  Sym.symbol()->GlobalDynIndex = Entries.size();
>    // Global Dynamic TLS entries take two GOT slots.
>    Entries.push_back(&Sym);
>    Entries.push_back(nullptr);
> @@ -186,13 +186,13 @@ GotSection<ELFT>::getMipsLocalEntryOffse
>  template <class ELFT>
>  typename GotSection<ELFT>::uintX_t
>  GotSection<ELFT>::getGlobalDynAddr(const SymbolBody &B) const {
> -  return this->getVA() + B.GlobalDynIndex * sizeof(uintX_t);
> +  return this->getVA() + B.symbol()->GlobalDynIndex * sizeof(uintX_t);
>  }
>
>  template <class ELFT>
>  typename GotSection<ELFT>::uintX_t
>  GotSection<ELFT>::getGlobalDynOffset(const SymbolBody &B) const {
> -  return B.GlobalDynIndex * sizeof(uintX_t);
> +  return B.symbol()->GlobalDynIndex * sizeof(uintX_t);
>  }
>
>  template <class ELFT>
> @@ -1371,7 +1371,7 @@ static bool sortMipsSymbols(const std::p
>  }
>
>  static uint8_t getSymbolBinding(SymbolBody *Body) {
> -  Symbol *S = Body->Backref;
> +  Symbol *S = Body->symbol();
>    uint8_t Visibility = S->Visibility;
>    if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
>      return STB_LOCAL;
> @@ -1472,7 +1472,7 @@ void SymbolTableSection<ELFT>::writeGlob
>      ESym->setBindingAndType(getSymbolBinding(Body), Type);
>      ESym->st_size = Size;
>      ESym->st_name = StrOff;
> -    ESym->setVisibility(Body->Backref->Visibility);
> +    ESym->setVisibility(Body->symbol()->Visibility);
>      ESym->st_value = Body->getVA<ELFT>();
>
>      if (const OutputSectionBase<ELFT> *OutSec = getOutputSection(Body))
>
> Modified: lld/trunk/ELF/SymbolTable.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.cpp?rev=268178&r1=268177&r2=268178&view=diff
> ==============================================================================
> --- lld/trunk/ELF/SymbolTable.cpp (original)
> +++ lld/trunk/ELF/SymbolTable.cpp Sat Apr 30 23:55:03 2016
> @@ -64,18 +64,14 @@ void SymbolTable<ELFT>::addFile(std::uni
>    // .a file
>    if (auto *F = dyn_cast<ArchiveFile>(FileP)) {
>      ArchiveFiles.emplace_back(cast<ArchiveFile>(File.release()));
> -    F->parse();
> -    for (Lazy &Sym : F->getLazySymbols())
> -      addLazy(&Sym);
> +    F->parse<ELFT>();
>      return;
>    }
>
>    // Lazy object file
>    if (auto *F = dyn_cast<LazyObjectFile>(FileP)) {
>      LazyObjectFiles.emplace_back(cast<LazyObjectFile>(File.release()));
> -    F->parse();
> -    for (Lazy &Sym : F->getLazySymbols())
> -      addLazy(&Sym);
> +    F->parse<ELFT>();
>      return;
>    }
>
> @@ -91,18 +87,13 @@ void SymbolTable<ELFT>::addFile(std::uni
>
>      SharedFiles.emplace_back(cast<SharedFile<ELFT>>(File.release()));
>      F->parseRest();
> -    for (SharedSymbol<ELFT> &B : F->getSharedSymbols())
> -      resolve(&B);
>      return;
>    }
>
>    // LLVM bitcode file
>    if (auto *F = dyn_cast<BitcodeFile>(FileP)) {
>      BitcodeFiles.emplace_back(cast<BitcodeFile>(File.release()));
> -    F->parse(ComdatGroups);
> -    for (SymbolBody *B : F->getSymbols())
> -      if (B)
> -        resolve(B);
> +    F->parse<ELFT>(ComdatGroups);
>      return;
>    }
>
> @@ -110,8 +101,6 @@ void SymbolTable<ELFT>::addFile(std::uni
>    auto *F = cast<ObjectFile<ELFT>>(FileP);
>    ObjectFiles.emplace_back(cast<ObjectFile<ELFT>>(File.release()));
>    F->parse(ComdatGroups);
> -  for (SymbolBody *B : F->getNonLocalSymbols())
> -    resolve(B);
>  }
>
>  // This function is where all the optimizations of link-time
> @@ -137,41 +126,15 @@ template <class ELFT> void SymbolTable<E
>
>      llvm::DenseSet<StringRef> DummyGroups;
>      Obj->parse(DummyGroups);
> -    for (SymbolBody *Body : Obj->getNonLocalSymbols()) {
> -      Symbol *Sym = insert(Body);
> -      if (!Sym->Body->isUndefined() && Body->isUndefined())
> -        continue;
> -      Sym->Body = Body;
> -    }
>      ObjectFiles.emplace_back(Obj);
>    }
>  }
>
> -// Add an undefined symbol.
> -template <class ELFT>
> -SymbolBody *SymbolTable<ELFT>::addUndefined(StringRef Name) {
> -  auto *Sym = new (Alloc) Undefined(Name, STB_GLOBAL, STV_DEFAULT, /*Type*/ 0,
> -                                    /*IsBitcode*/ false);
> -  resolve(Sym);
> -  return Sym;
> -}
> -
>  template <class ELFT>
>  DefinedRegular<ELFT> *SymbolTable<ELFT>::addAbsolute(StringRef Name,
>                                                       uint8_t Visibility) {
> -  // Pass nullptr because absolute symbols have no corresponding input sections.
> -  auto *Sym = new (Alloc) DefinedRegular<ELFT>(Name, STB_GLOBAL, Visibility);
> -  resolve(Sym);
> -  return Sym;
> -}
> -
> -template <class ELFT>
> -SymbolBody *SymbolTable<ELFT>::addSynthetic(StringRef Name,
> -                                            OutputSectionBase<ELFT> &Sec,
> -                                            uintX_t Val) {
> -  auto *Sym = new (Alloc) DefinedSynthetic<ELFT>(Name, Val, Sec);
> -  resolve(Sym);
> -  return Sym;
> +  return cast<DefinedRegular<ELFT>>(
> +      addRegular(Name, STB_GLOBAL, Visibility)->body());
>  }
>
>  // Add Name as an "ignored" symbol. An ignored symbol is a regular
> @@ -191,84 +154,47 @@ template <class ELFT> void SymbolTable<E
>    if (!B)
>      return;
>    StringSaver Saver(Alloc);
> -  Symbol *Sym = B->Backref;
> -  Symbol *Real = addUndefined(Saver.save("__real_" + Name))->Backref;
> -  Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name))->Backref;
> -  Real->Body = Sym->Body;
> -  Sym->Body = Wrap->Body;
> +  Symbol *Sym = B->symbol();
> +  Symbol *Real = addUndefined(Saver.save("__real_" + Name));
> +  Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name));
> +  // We rename symbols by replacing the old symbol's SymbolBody with the new
> +  // symbol's SymbolBody. This causes all SymbolBody pointers referring to the
> +  // old symbol to instead refer to the new symbol.
> +  memcpy(Real->Body.buffer, Sym->Body.buffer, sizeof(Sym->Body));
> +  memcpy(Sym->Body.buffer, Wrap->Body.buffer, sizeof(Wrap->Body));
>  }
>
>  // Returns a file from which symbol B was created.
>  // If B does not belong to any file, returns a nullptr.
>  // This function is slow, but it's okay as it is used only for error messages.
>  template <class ELFT> InputFile *SymbolTable<ELFT>::findFile(SymbolBody *B) {
> +  // If this symbol has a definition, follow pointers in the symbol to its
> +  // defining file.
> +  if (auto *R = dyn_cast<DefinedRegular<ELFT>>(B))
> +    if (auto *S = R->Section)
> +      return S->getFile();
> +  if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(B))
> +    return SS->File;
> +  if (auto *BC = dyn_cast<DefinedBitcode>(B))
> +    return BC->File;
> +  // If not, we might be able to find it by searching symbol tables of files.
> +  // This code is generally only used for undefined symbols. Note that we can't
> +  // rely exclusively on a file search because we may find what was originally
> +  // an undefined symbol that was later replaced with a defined symbol, and we
> +  // want to return the file that defined the symbol.
>    for (const std::unique_ptr<ObjectFile<ELFT>> &F : ObjectFiles) {
>      ArrayRef<SymbolBody *> Syms = F->getSymbols();
>      if (std::find(Syms.begin(), Syms.end(), B) != Syms.end())
>        return F.get();
>    }
>    for (const std::unique_ptr<BitcodeFile> &F : BitcodeFiles) {
> -    ArrayRef<SymbolBody *> Syms = F->getSymbols();
> -    if (std::find(Syms.begin(), Syms.end(), B) != Syms.end())
> +    ArrayRef<Symbol *> Syms = F->getSymbols();
> +    if (std::find(Syms.begin(), Syms.end(), B->symbol()) != Syms.end())
>        return F.get();
>    }
>    return nullptr;
>  }
>
> -// Construct a string in the form of "Sym in File1 and File2".
> -// Used to construct an error message.
> -template <class ELFT>
> -std::string SymbolTable<ELFT>::conflictMsg(SymbolBody *Old, SymbolBody *New) {
> -  InputFile *F1 = findFile(Old);
> -  InputFile *F2 = findFile(New);
> -  StringRef Sym = Old->getName();
> -  return demangle(Sym) + " in " + getFilename(F1) + " and " + getFilename(F2);
> -}
> -
> -// This function resolves conflicts if there's an existing symbol with
> -// the same name. Decisions are made based on symbol type.
> -template <class ELFT> void SymbolTable<ELFT>::resolve(SymbolBody *New) {
> -  Symbol *Sym = insert(New);
> -  if (Sym->Body == New)
> -    return;
> -
> -  SymbolBody *Existing = Sym->Body;
> -
> -  if (auto *L = dyn_cast<Lazy>(Existing)) {
> -    Sym->Binding = New->Binding;
> -    if (New->isUndefined()) {
> -      addMemberFile(New, L);
> -      return;
> -    }
> -    // Found a definition for something also in an archive.
> -    // Ignore the archive definition.
> -    Sym->Body = New;
> -    return;
> -  }
> -
> -  if (New->isTls() != Existing->isTls()) {
> -    error("TLS attribute mismatch for symbol: " + conflictMsg(Existing, New));
> -    return;
> -  }
> -
> -  // compare() returns -1, 0, or 1 if the lhs symbol is less preferable,
> -  // equivalent (conflicting), or more preferable, respectively.
> -  int Comp = Existing->compare(New);
> -  if (Comp == 0) {
> -    std::string S = "duplicate symbol: " + conflictMsg(Existing, New);
> -    if (Config->AllowMultipleDefinition)
> -      warning(S);
> -    else
> -      error(S);
> -    return;
> -  }
> -  if (Comp < 0) {
> -    Sym->Body = New;
> -    if (!New->isShared())
> -      Sym->Binding = New->Binding;
> -  }
> -}
> -
>  static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
>    if (VA == STV_DEFAULT)
>      return VB;
> @@ -277,25 +203,15 @@ static uint8_t getMinVisibility(uint8_t
>    return std::min(VA, VB);
>  }
>
> -static bool shouldExport(SymbolBody *B) {
> -  if (Config->Shared || Config->ExportDynamic) {
> -    // Export most symbols except for those that do not need to be exported.
> -    return !B->CanOmitFromDynSym;
> -  }
> -  // Make sure we preempt DSO symbols with default visibility.
> -  return B->isShared() && B->getVisibility() == STV_DEFAULT;
> -}
> -
>  // Find an existing symbol or create and insert a new one.
> -template <class ELFT> Symbol *SymbolTable<ELFT>::insert(SymbolBody *New) {
> -  StringRef Name = New->getName();
> +template <class ELFT>
> +std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef Name) {
>    unsigned NumSyms = SymVector.size();
>    auto P = Symtab.insert(std::make_pair(Name, NumSyms));
>    Symbol *Sym;
>    if (P.second) {
>      Sym = new (Alloc) Symbol;
> -    Sym->Body = New;
> -    Sym->Binding = New->isShared() ? (uint8_t)STB_GLOBAL : New->Binding;
> +    Sym->Binding = STB_WEAK;
>      Sym->Visibility = STV_DEFAULT;
>      Sym->IsUsedInRegularObj = false;
>      Sym->ExportDynamic = false;
> @@ -304,69 +220,299 @@ template <class ELFT> Symbol *SymbolTabl
>    } else {
>      Sym = SymVector[P.first->second];
>    }
> -  New->Backref = Sym;
> +  return {Sym, P.second};
> +}
> +
> +// Find an existing symbol or create and insert a new one, then apply the given
> +// attributes.
> +template <class ELFT>
> +std::pair<Symbol *, bool>
> +SymbolTable<ELFT>::insert(StringRef Name, uint8_t Type, uint8_t Visibility,
> +                          bool CanOmitFromDynSym, bool IsUsedInRegularObj,
> +                          InputFile *File) {
> +  Symbol *S;
> +  bool WasInserted;
> +  std::tie(S, WasInserted) = insert(Name);
> +
> +  // Merge in the new symbol's visibility.
> +  S->Visibility = getMinVisibility(S->Visibility, Visibility);
> +  if (!CanOmitFromDynSym && (Config->Shared || Config->ExportDynamic))
> +    S->ExportDynamic = true;
> +  if (IsUsedInRegularObj)
> +    S->IsUsedInRegularObj = true;
> +  if (!WasInserted && ((Type == STT_TLS) != S->body()->isTls()))
> +    error("TLS attribute mismatch for symbol: " +
> +          conflictMsg(S->body(), File));
> +
> +  return {S, WasInserted};
> +}
> +
> +// Construct a string in the form of "Sym in File1 and File2".
> +// Used to construct an error message.
> +template <typename ELFT>
> +std::string SymbolTable<ELFT>::conflictMsg(SymbolBody *Existing,
> +                                           InputFile *NewFile) {
> +  StringRef Sym = Existing->getName();
> +  return demangle(Sym) + " in " + getFilename(findFile(Existing)) + " and " +
> +         getFilename(NewFile);
> +}
> +
> +template <class ELFT> Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name) {
> +  return addUndefined(Name, STB_GLOBAL, STV_DEFAULT, /*Type*/ 0,
> +                      /*File*/ nullptr);
> +}
> +
> +template <class ELFT>
> +Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, uint8_t Binding,
> +                                        uint8_t StOther, uint8_t Type,
> +                                        InputFile *File) {
> +  Symbol *S;
> +  bool WasInserted;
> +  std::tie(S, WasInserted) =
> +      insert(Name, Type, StOther & 3, /*CanOmitFromDynSym*/ false,
> +             /*IsUsedInRegularObj*/ !File || !isa<BitcodeFile>(File), File);
> +  if (WasInserted) {
> +    S->Binding = Binding;
> +    replaceBody<Undefined>(S, Name, StOther, Type);
> +    return S;
> +  }
> +  if (Binding != STB_WEAK &&
> +      (S->body()->isShared() || S->body()->isLazy()))
> +    S->Binding = Binding;
> +  if (auto *L = dyn_cast<Lazy>(S->body())) {
> +    // An undefined weak will not fetch archive members, but we have to remember
> +    // its type. See also comment in addLazyArchive.
> +    if (S->isWeak())
> +      L->Type = Type;
> +    else if (auto F = L->getFile())
> +      addFile(std::move(F));
> +  }
> +  return S;
> +}
> +
> +// We have a new defined symbol with the specified binding. Return 1 if the new
> +// symbol should win, -1 if the new symbol should lose, or 0 if both symbols are
> +// strong defined symbols.
> +static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding) {
> +  if (WasInserted)
> +    return 1;
> +  SymbolBody *Body = S->body();
> +  if (Body->isLazy() || Body->isUndefined() || Body->isShared())
> +    return 1;
> +  if (Binding == STB_WEAK)
> +    return -1;
> +  if (S->isWeak())
> +    return 1;
> +  return 0;
> +}
> +
> +// We have a new non-common defined symbol with the specified binding. Return 1
> +// if the new symbol should win, -1 if the new symbol should lose, or 0 if there
> +// is a conflict. If the new symbol wins, also update the binding.
> +static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding) {
> +  if (int Cmp = compareDefined(S, WasInserted, Binding)) {
> +    if (Cmp > 0)
> +      S->Binding = Binding;
> +    return Cmp;
> +  }
> +  if (isa<DefinedCommon>(S->body())) {
> +    // Non-common symbols take precedence over common symbols.
> +    if (Config->WarnCommon)
> +      warning("common " + S->body()->getName() + " is overridden");
> +    return 1;
> +  }
> +  return 0;
> +}
> +
> +template <class ELFT>
> +Symbol *SymbolTable<ELFT>::addCommon(StringRef N, uint64_t Size,
> +                                     uint64_t Alignment, uint8_t Binding,
> +                                     uint8_t StOther, uint8_t Type,
> +                                     InputFile *File) {
> +  Symbol *S;
> +  bool WasInserted;
> +  std::tie(S, WasInserted) =
> +      insert(N, Type, StOther & 3, /*CanOmitFromDynSym*/ false,
> +             /*IsUsedInRegularObj*/ true, File);
> +  int Cmp = compareDefined(S, WasInserted, Binding);
> +  if (Cmp > 0) {
> +    S->Binding = Binding;
> +    replaceBody<DefinedCommon>(S, N, Size, Alignment, StOther, Type);
> +  } else if (Cmp == 0) {
> +    auto *C = dyn_cast<DefinedCommon>(S->body());
> +    if (!C) {
> +      // Non-common symbols take precedence over common symbols.
> +      if (Config->WarnCommon)
> +        warning("common " + S->body()->getName() + " is overridden");
> +      return S;
> +    }
> +
> +    if (Config->WarnCommon)
> +      warning("multiple common of " + S->body()->getName());
> +
> +    C->Size = std::max(C->Size, Size);
> +    C->Alignment = std::max(C->Alignment, Alignment);
> +  }
> +  return S;
> +}
> +
> +template <class ELFT>
> +void SymbolTable<ELFT>::reportDuplicate(SymbolBody *Existing,
> +                                        InputFile *NewFile) {
> +  std::string Msg = "duplicate symbol: " + conflictMsg(Existing, NewFile);
> +  if (Config->AllowMultipleDefinition)
> +    warning(Msg);
> +  else
> +    error(Msg);
> +}
> +
> +template <typename ELFT>
> +Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, const Elf_Sym &Sym,
> +                                      InputSectionBase<ELFT> *Section) {
> +  Symbol *S;
> +  bool WasInserted;
> +  std::tie(S, WasInserted) =
> +      insert(Name, Sym.getType(), Sym.getVisibility(),
> +             /*CanOmitFromDynSym*/ false, /*IsUsedInRegularObj*/ true,
> +             Section ? Section->getFile() : nullptr);
> +  int Cmp = compareDefinedNonCommon(S, WasInserted, Sym.getBinding());
> +  if (Cmp > 0)
> +    replaceBody<DefinedRegular<ELFT>>(S, Name, Sym, Section);
> +  else if (Cmp == 0)
> +    reportDuplicate(S->body(), Section->getFile());
> +  return S;
> +}
> +
> +template <typename ELFT>
> +Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, uint8_t Binding,
> +                                      uint8_t StOther) {
> +  Symbol *S;
> +  bool WasInserted;
> +  std::tie(S, WasInserted) =
> +      insert(Name, STT_NOTYPE, StOther & 3, /*CanOmitFromDynSym*/ false,
> +             /*IsUsedInRegularObj*/ true, nullptr);
> +  int Cmp = compareDefinedNonCommon(S, WasInserted, Binding);
> +  if (Cmp > 0)
> +    replaceBody<DefinedRegular<ELFT>>(S, Name, StOther);
> +  else if (Cmp == 0)
> +    reportDuplicate(S->body(), nullptr);
> +  return S;
> +}
> +
> +template <typename ELFT>
> +Symbol *SymbolTable<ELFT>::addSynthetic(StringRef N,
> +                                        OutputSectionBase<ELFT> &Section,
> +                                        uintX_t Value) {
> +  Symbol *S;
> +  bool WasInserted;
> +  std::tie(S, WasInserted) =
> +      insert(N, STT_NOTYPE, STV_HIDDEN, /*CanOmitFromDynSym*/ false,
> +             /*IsUsedInRegularObj*/ true, nullptr);
> +  int Cmp = compareDefinedNonCommon(S, WasInserted, STB_GLOBAL);
> +  if (Cmp > 0)
> +    replaceBody<DefinedSynthetic<ELFT>>(S, N, Value, Section);
> +  else if (Cmp == 0)
> +    reportDuplicate(S->body(), nullptr);
> +  return S;
> +}
> +
> +template <typename ELFT>
> +void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *F, StringRef Name,
> +                                  const Elf_Sym &Sym,
> +                                  const typename ELFT::Verdef *Verdef) {
> +  // DSO symbols do not affect visibility in the output, so we pass STV_DEFAULT
> +  // as the visibility, which will leave the visibility in the symbol table
> +  // unchanged.
> +  Symbol *S;
> +  bool WasInserted;
> +  std::tie(S, WasInserted) =
> +      insert(Name, Sym.getType(), STV_DEFAULT, /*CanOmitFromDynSym*/ true,
> +             /*IsUsedInRegularObj*/ false, F);
> +  // Make sure we preempt DSO symbols with default visibility.
> +  if (Sym.getVisibility() == STV_DEFAULT)
> +    S->ExportDynamic = true;
> +  if (WasInserted || isa<Undefined>(S->body()))
> +    replaceBody<SharedSymbol<ELFT>>(S, F, Name, Sym, Verdef);
> +}
>
> -  // Merge in the new symbol's visibility. DSO symbols do not affect visibility
> -  // in the output.
> -  if (!New->isShared())
> -    Sym->Visibility = getMinVisibility(Sym->Visibility, New->getVisibility());
> -  Sym->ExportDynamic = Sym->ExportDynamic || shouldExport(New);
> -  SymbolBody::Kind K = New->kind();
> -  if (K == SymbolBody::DefinedRegularKind ||
> -      K == SymbolBody::DefinedCommonKind ||
> -      K == SymbolBody::DefinedSyntheticKind ||
> -      (K == SymbolBody::UndefinedKind && !New->IsUndefinedBitcode))
> -    Sym->IsUsedInRegularObj = true;
> -  return Sym;
> +template <class ELFT>
> +Symbol *SymbolTable<ELFT>::addBitcode(StringRef Name, bool IsWeak,
> +                                      uint8_t StOther, uint8_t Type,
> +                                      bool CanOmitFromDynSym, BitcodeFile *F) {
> +  Symbol *S;
> +  bool WasInserted;
> +  std::tie(S, WasInserted) = insert(Name, Type, StOther & 3, CanOmitFromDynSym,
> +                                    /*IsUsedInRegularObj*/ false, F);
> +  int Cmp =
> +      compareDefinedNonCommon(S, WasInserted, IsWeak ? STB_WEAK : STB_GLOBAL);
> +  if (Cmp > 0)
> +    replaceBody<DefinedBitcode>(S, Name, StOther, Type, F);
> +  else if (Cmp == 0)
> +    reportDuplicate(S->body(), F);
> +  return S;
>  }
>
>  template <class ELFT> SymbolBody *SymbolTable<ELFT>::find(StringRef Name) {
>    auto It = Symtab.find(Name);
>    if (It == Symtab.end())
>      return nullptr;
> -  return SymVector[It->second]->Body;
> +  return SymVector[It->second]->body();
>  }
>
> -template <class ELFT> void SymbolTable<ELFT>::addLazy(Lazy *L) {
> -  Symbol *Sym = insert(L);
> -  SymbolBody *Cur = Sym->Body;
> -  if (Cur == L)
> -    return;
> -  if (Cur->isUndefined()) {
> -    Sym->Body = L;
> -    addMemberFile(Cur, L);
> -  }
> +template <class ELFT>
> +void SymbolTable<ELFT>::addLazyArchive(
> +    ArchiveFile *F, const llvm::object::Archive::Symbol Sym) {
> +  Symbol *S;
> +  bool WasInserted;
> +  std::tie(S, WasInserted) = insert(Sym.getName());
> +  if (WasInserted) {
> +    replaceBody<LazyArchive>(S, F, Sym, STT_NOTYPE);
> +    return;
> +  }
> +  if (!S->body()->isUndefined())
> +    return;
> +
> +  // Weak undefined symbols should not fetch members from archives. If we were
> +  // to keep old symbol we would not know that an archive member was available
> +  // if a strong undefined symbol shows up afterwards in the link. If a strong
> +  // undefined symbol never shows up, this lazy symbol will get to the end of
> +  // the link and must be treated as the weak undefined one. We already marked
> +  // this symbol as used when we added it to the symbol table, but we also need
> +  // to preserve its type. FIXME: Move the Type field to Symbol.
> +  if (S->isWeak()) {
> +    replaceBody<LazyArchive>(S, F, Sym, S->body()->Type);
> +    return;
> +  }
> +  MemoryBufferRef MBRef = F->getMember(&Sym);
> +  if (!MBRef.getBuffer().empty())
> +    addFile(createObjectFile(MBRef, F->getName()));
>  }
>
>  template <class ELFT>
> -void SymbolTable<ELFT>::addMemberFile(SymbolBody *Undef, Lazy *L) {
> -  // Weak undefined symbols should not fetch members from archives.
> -  // If we were to keep old symbol we would not know that an archive member was
> -  // available if a strong undefined symbol shows up afterwards in the link.
> -  // If a strong undefined symbol never shows up, this lazy symbol will
> -  // get to the end of the link and must be treated as the weak undefined one.
> -  // We already marked this symbol as used when we added it to the symbol table,
> -  // but we also need to preserve its binding and type.
> -  if (Undef->isWeak()) {
> -    // FIXME: Consider moving these members to Symbol.
> -    L->Type = Undef->Type;
> -    return;
> -  }
> -
> -  // Fetch a member file that has the definition for L.
> -  // getMember returns nullptr if the member was already read from the library.
> -  if (std::unique_ptr<InputFile> File = L->getFile())
> -    addFile(std::move(File));
> +void SymbolTable<ELFT>::addLazyObject(StringRef Name, MemoryBufferRef MBRef) {
> +  Symbol *S;
> +  bool WasInserted;
> +  std::tie(S, WasInserted) = insert(Name);
> +  if (WasInserted) {
> +    replaceBody<LazyObject>(S, Name, MBRef, STT_NOTYPE);
> +    return;
> +  }
> +  if (!S->body()->isUndefined())
> +    return;
> +
> +  // See comment for addLazyArchive above.
> +  if (S->isWeak())
> +    replaceBody<LazyObject>(S, Name, MBRef, S->body()->Type);
> +  else
> +    addFile(createObjectFile(MBRef));
>  }
>
>  // Process undefined (-u) flags by loading lazy symbols named by those flags.
> -template <class ELFT>
> -void SymbolTable<ELFT>::scanUndefinedFlags() {
> +template <class ELFT> void SymbolTable<ELFT>::scanUndefinedFlags() {
>    for (StringRef S : Config->Undefined)
> -    if (SymbolBody *Sym = find(S))
> -      if (auto *L = dyn_cast<Lazy>(Sym))
> -        if (std::unique_ptr<InputFile> File = L->getFile())
> -          addFile(std::move(File));
> +    if (auto *L = dyn_cast_or_null<Lazy>(find(S)))
> +      if (std::unique_ptr<InputFile> File = L->getFile())
> +        addFile(std::move(File));
>  }
>
>  // This function takes care of the case in which shared libraries depend on
> @@ -381,7 +527,7 @@ template <class ELFT> void SymbolTable<E
>      for (StringRef U : File->getUndefinedSymbols())
>        if (SymbolBody *Sym = find(U))
>          if (Sym->isDefined())
> -          Sym->Backref->ExportDynamic = true;
> +          Sym->symbol()->ExportDynamic = true;
>  }
>
>  // This function process the dynamic list option by marking all the symbols
> @@ -389,7 +535,7 @@ template <class ELFT> void SymbolTable<E
>  template <class ELFT> void SymbolTable<ELFT>::scanDynamicList() {
>    for (StringRef S : Config->DynamicList)
>      if (SymbolBody *B = find(S))
> -      B->Backref->ExportDynamic = true;
> +      B->symbol()->ExportDynamic = true;
>  }
>
>  // This function processes the --version-script option by marking all global
> @@ -398,7 +544,7 @@ template <class ELFT> void SymbolTable<E
>  template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
>    for (StringRef S : Config->VersionScriptGlobals)
>      if (SymbolBody *B = find(S))
> -      B->Backref->VersionScriptGlobal = true;
> +      B->symbol()->VersionScriptGlobal = true;
>  }
>
>  template class elf::SymbolTable<ELF32LE>;
>
> Modified: lld/trunk/ELF/SymbolTable.h
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.h?rev=268178&r1=268177&r2=268178&view=diff
> ==============================================================================
> --- lld/trunk/ELF/SymbolTable.h (original)
> +++ lld/trunk/ELF/SymbolTable.h Sat Apr 30 23:55:03 2016
> @@ -31,7 +31,9 @@ typedef llvm::CachedHash<StringRef> SymN
>  // conflicts. For example, obviously, a defined symbol is better than
>  // an undefined symbol. Or, if there's a conflict between a lazy and a
>  // undefined, it'll read an archive member to read a real definition
> -// to replace the lazy symbol. The logic is implemented in resolve().
> +// to replace the lazy symbol. The logic is implemented in the
> +// add*() functions, which are called by input files as they are parsed. There
> +// is one add* function per symbol type.
>  template <class ELFT> class SymbolTable {
>    typedef typename ELFT::Sym Elf_Sym;
>    typedef typename ELFT::uint uintX_t;
> @@ -50,14 +52,32 @@ public:
>      return SharedFiles;
>    }
>
> -  SymbolBody *addUndefined(StringRef Name);
>    DefinedRegular<ELFT> *addAbsolute(StringRef Name,
>                                      uint8_t Visibility = llvm::ELF::STV_HIDDEN);
> -  SymbolBody *addSynthetic(StringRef Name, OutputSectionBase<ELFT> &Section,
> -                           uintX_t Value);
>    DefinedRegular<ELFT> *addIgnored(StringRef Name,
>                                     uint8_t Visibility = llvm::ELF::STV_HIDDEN);
>
> +  Symbol *addUndefined(StringRef Name);
> +  Symbol *addUndefined(StringRef Name, uint8_t Binding, uint8_t StOther,
> +                       uint8_t Type, InputFile *File);
> +
> +  Symbol *addRegular(StringRef Name, const Elf_Sym &Sym,
> +                     InputSectionBase<ELFT> *Section);
> +  Symbol *addRegular(StringRef Name, uint8_t Binding, uint8_t StOther);
> +  Symbol *addSynthetic(StringRef N, OutputSectionBase<ELFT> &Section,
> +                       uintX_t Value);
> +  void addShared(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym,
> +                 const typename ELFT::Verdef *Verdef);
> +
> +  void addLazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S);
> +  void addLazyObject(StringRef Name, MemoryBufferRef MBRef);
> +  Symbol *addBitcode(StringRef Name, bool IsWeak, uint8_t StOther, uint8_t Type,
> +                     bool CanOmitFromDynSym, BitcodeFile *File);
> +
> +  Symbol *addCommon(StringRef N, uint64_t Size, uint64_t Alignment,
> +                    uint8_t Binding, uint8_t StOther, uint8_t Type,
> +                    InputFile *File);
> +
>    void scanUndefinedFlags();
>    void scanShlibUndefined();
>    void scanDynamicList();
> @@ -67,11 +87,13 @@ public:
>    InputFile *findFile(SymbolBody *B);
>
>  private:
> -  Symbol *insert(SymbolBody *New);
> -  void addLazy(Lazy *New);
> -  void addMemberFile(SymbolBody *Undef, Lazy *L);
> -  void resolve(SymbolBody *Body);
> -  std::string conflictMsg(SymbolBody *Old, SymbolBody *New);
> +  std::pair<Symbol *, bool> insert(StringRef Name);
> +  std::pair<Symbol *, bool> insert(StringRef Name, uint8_t Type,
> +                                   uint8_t Visibility, bool CanOmitFromDynSym,
> +                                   bool IsUsedInRegularObj, InputFile *File);
> +
> +  std::string conflictMsg(SymbolBody *Existing, InputFile *NewFile);
> +  void reportDuplicate(SymbolBody *Existing, InputFile *NewFile);
>
>    // The order the global symbols are in is not defined. We can use an arbitrary
>    // order, but it has to be reproducible. That is true even when cross linking.
> @@ -102,6 +124,9 @@ private:
>    std::unique_ptr<BitcodeCompiler> Lto;
>  };
>
> +template <class ELFT> struct Symtab { static SymbolTable<ELFT> *X; };
> +template <class ELFT> SymbolTable<ELFT> *Symtab<ELFT>::X;
> +
>  } // namespace elf
>  } // namespace lld
>
>
> Modified: lld/trunk/ELF/Symbols.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.cpp?rev=268178&r1=268177&r2=268178&view=diff
> ==============================================================================
> --- lld/trunk/ELF/Symbols.cpp (original)
> +++ lld/trunk/ELF/Symbols.cpp Sat Apr 30 23:55:03 2016
> @@ -79,7 +79,7 @@ static typename ELFT::uint getSymVA(cons
>      return 0;
>    case SymbolBody::LazyArchiveKind:
>    case SymbolBody::LazyObjectKind:
> -    assert(Body.Backref->IsUsedInRegularObj && "lazy symbol reached writer");
> +    assert(Body.symbol()->IsUsedInRegularObj && "lazy symbol reached writer");
>      return 0;
>    case SymbolBody::DefinedBitcodeKind:
>      llvm_unreachable("should have been replaced");
> @@ -89,22 +89,19 @@ static typename ELFT::uint getSymVA(cons
>
>  SymbolBody::SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther,
>                         uint8_t Type)
> -    : SymbolKind(K), Type(Type), Binding(STB_LOCAL), StOther(StOther),
> +    : SymbolKind(K), IsLocal(true), Type(Type), StOther(StOther),
>        NameOffset(NameOffset) {
>    init();
>  }
>
> -SymbolBody::SymbolBody(Kind K, StringRef Name, uint8_t Binding, uint8_t StOther,
> -                       uint8_t Type)
> -    : SymbolKind(K), Type(Type), Binding(Binding), StOther(StOther),
> +SymbolBody::SymbolBody(Kind K, StringRef Name, uint8_t StOther, uint8_t Type)
> +    : SymbolKind(K), IsLocal(false), Type(Type), StOther(StOther),
>        Name({Name.data(), Name.size()}) {
> -  assert(!isLocal());
>    init();
>  }
>
>  void SymbolBody::init() {
>    NeedsCopyOrPltAddr = false;
> -  CanOmitFromDynSym = false;
>  }
>
>  // Returns true if a symbol can be replaced at load-time by a symbol
> @@ -122,14 +119,14 @@ bool SymbolBody::isPreemptible() const {
>      return false;
>
>    // Only symbols that appear in dynsym can be preempted.
> -  if (!Backref->includeInDynsym())
> +  if (!symbol()->includeInDynsym())
>      return false;
>
>    // Normally only default visibility symbols can be preempted, but -Bsymbolic
>    // means that not even they can be preempted.
>    if (Config->Bsymbolic || (Config->BsymbolicFunctions && isFunc()))
>      return !isDefined();
> -  return Backref->Visibility == STV_DEFAULT;
> +  return symbol()->Visibility == STV_DEFAULT;
>  }
>
>  template <class ELFT>
> @@ -177,79 +174,35 @@ template <class ELFT> typename ELFT::uin
>    return 0;
>  }
>
> -// Returns 1, 0 or -1 if this symbol should take precedence
> -// over the Other, tie or lose, respectively.
> -int SymbolBody::compare(SymbolBody *Other) {
> -  assert(!isLazy() && !Other->isLazy());
> -  std::tuple<bool, bool, bool> L(isDefined(), !isShared(), !isWeak());
> -  std::tuple<bool, bool, bool> R(Other->isDefined(), !Other->isShared(),
> -                                 !Other->isWeak());
> -
> -  // Compare the two by symbol type.
> -  if (L > R)
> -    return -Other->compare(this);
> -  if (L != R)
> -    return -1;
> -  if (!isDefined() || isShared() || isWeak())
> -    return 1;
> -
> -  // If both are equal in terms of symbol type, then at least
> -  // one of them must be a common symbol. Otherwise, they conflict.
> -  auto *A = dyn_cast<DefinedCommon>(this);
> -  auto *B = dyn_cast<DefinedCommon>(Other);
> -  if (!A && !B)
> -    return 0;
> -
> -  // If both are common, the larger one is chosen.
> -  if (A && B) {
> -    if (Config->WarnCommon)
> -      warning("multiple common of " + A->getName());
> -    A->Alignment = B->Alignment = std::max(A->Alignment, B->Alignment);
> -    return A->Size < B->Size ? -1 : 1;
> -  }
> -
> -  // Non-common symbols takes precedence over common symbols.
> -  if (Config->WarnCommon)
> -    warning("common " + this->getName() + " is overridden");
> -  return A ? -1 : 1;
> -}
> -
> -Defined::Defined(Kind K, StringRef Name, uint8_t Binding, uint8_t StOther,
> -                 uint8_t Type)
> -    : SymbolBody(K, Name, Binding, StOther, Type) {}
> +Defined::Defined(Kind K, StringRef Name, uint8_t StOther, uint8_t Type)
> +    : SymbolBody(K, Name, StOther, Type) {}
>
>  Defined::Defined(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type)
>      : SymbolBody(K, NameOffset, StOther, Type) {}
>
> -DefinedBitcode::DefinedBitcode(StringRef Name, bool IsWeak, uint8_t StOther)
> -    : Defined(DefinedBitcodeKind, Name, IsWeak ? STB_WEAK : STB_GLOBAL,
> -              StOther, 0 /* Type */) {}
> +DefinedBitcode::DefinedBitcode(StringRef Name, uint8_t StOther, uint8_t Type,
> +                               BitcodeFile *F)
> +    : Defined(DefinedBitcodeKind, Name, StOther, Type), File(F) {}
>
>  bool DefinedBitcode::classof(const SymbolBody *S) {
>    return S->kind() == DefinedBitcodeKind;
>  }
>
> -Undefined::Undefined(StringRef Name, uint8_t Binding, uint8_t StOther,
> -                     uint8_t Type, bool IsBitcode)
> -    : SymbolBody(SymbolBody::UndefinedKind, Name, Binding, StOther, Type) {
> -  this->IsUndefinedBitcode = IsBitcode;
> -}
> +Undefined::Undefined(StringRef Name, uint8_t StOther, uint8_t Type)
> +    : SymbolBody(SymbolBody::UndefinedKind, Name, StOther, Type) {}
>
>  Undefined::Undefined(uint32_t NameOffset, uint8_t StOther, uint8_t Type)
> -    : SymbolBody(SymbolBody::UndefinedKind, NameOffset, StOther, Type) {
> -  this->IsUndefinedBitcode = false;
> -}
> +    : SymbolBody(SymbolBody::UndefinedKind, NameOffset, StOther, Type) {}
>
>  template <typename ELFT>
>  DefinedSynthetic<ELFT>::DefinedSynthetic(StringRef N, uintX_t Value,
>                                           OutputSectionBase<ELFT> &Section)
> -    : Defined(SymbolBody::DefinedSyntheticKind, N, STB_GLOBAL, STV_HIDDEN,
> -              0 /* Type */),
> +    : Defined(SymbolBody::DefinedSyntheticKind, N, STV_HIDDEN, 0 /* Type */),
>        Value(Value), Section(Section) {}
>
>  DefinedCommon::DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment,
> -                             uint8_t Binding, uint8_t StOther, uint8_t Type)
> -    : Defined(SymbolBody::DefinedCommonKind, N, Binding, StOther, Type),
> +                             uint8_t StOther, uint8_t Type)
> +    : Defined(SymbolBody::DefinedCommonKind, N, StOther, Type),
>        Alignment(Alignment), Size(Size) {}
>
>  std::unique_ptr<InputFile> Lazy::getFile() {
> @@ -301,8 +254,8 @@ std::string elf::demangle(StringRef Name
>  bool Symbol::includeInDynsym() const {
>    if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
>      return false;
> -  return (ExportDynamic && VersionScriptGlobal) || Body->isShared() ||
> -         (Body->isUndefined() && Config->Shared);
> +  return (ExportDynamic && VersionScriptGlobal) || body()->isShared() ||
> +         (body()->isUndefined() && Config->Shared);
>  }
>
>  template uint32_t SymbolBody::template getVA<ELF32LE>(uint32_t) const;
>
> Modified: lld/trunk/ELF/Symbols.h
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=268178&r1=268177&r2=268178&view=diff
> ==============================================================================
> --- lld/trunk/ELF/Symbols.h (original)
> +++ lld/trunk/ELF/Symbols.h Sat Apr 30 23:55:03 2016
> @@ -20,11 +20,13 @@
>  #include "lld/Core/LLVM.h"
>  #include "llvm/Object/Archive.h"
>  #include "llvm/Object/ELF.h"
> +#include "llvm/Support/AlignOf.h"
>
>  namespace lld {
>  namespace elf {
>
>  class ArchiveFile;
> +class BitcodeFile;
>  class InputFile;
>  class SymbolBody;
>  template <class ELFT> class ObjectFile;
> @@ -37,45 +39,7 @@ template <class ELFT> class SharedFile;
>  // it returns the unmodified string.
>  std::string demangle(StringRef Name);
>
> -// A real symbol object, SymbolBody, is usually accessed indirectly
> -// through a Symbol. There's always one Symbol for each symbol name.
> -// The resolver updates SymbolBody pointers as it resolves symbols.
> -// Symbol also holds computed properties of symbol names.
> -struct Symbol {
> -  SymbolBody *Body;
> -
> -  // Symbol binding. This is on the Symbol to track changes during resolution.
> -  // In particular:
> -  // An undefined weak is still weak when it resolves to a shared library.
> -  // An undefined weak will not fetch archive members, but we have to remember
> -  // it is weak.
> -  uint8_t Binding;
> -
> -  // Symbol visibility. This is the computed minimum visibility of all
> -  // observed non-DSO symbols.
> -  unsigned Visibility : 2;
> -
> -  // True if the symbol was used for linking and thus need to be added to the
> -  // output file's symbol table. This is true for all symbols except for
> -  // unreferenced DSO symbols and bitcode symbols that are unreferenced except
> -  // by other bitcode objects.
> -  unsigned IsUsedInRegularObj : 1;
> -
> -  // If this flag is true and the symbol has protected or default visibility, it
> -  // will appear in .dynsym. This flag is set by interposable DSO symbols in
> -  // executables, by most symbols in DSOs and executables built with
> -  // --export-dynamic, and by dynamic lists.
> -  unsigned ExportDynamic : 1;
> -
> -  // This flag acts as an additional filter on the dynamic symbol list. It is
> -  // set if there is no version script, or if the symbol appears in the global
> -  // section of the version script.
> -  unsigned VersionScriptGlobal : 1;
> -
> -  bool includeInDynsym() const;
> -
> -  bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; }
> -};
> +struct Symbol;
>
>  // The base class for real symbol classes.
>  class SymbolBody {
> @@ -95,9 +59,13 @@ public:
>      LazyObjectKind,
>    };
>
> +  Symbol *symbol();
> +  const Symbol *symbol() const {
> +    return const_cast<SymbolBody *>(this)->symbol();
> +  }
> +
>    Kind kind() const { return static_cast<Kind>(SymbolKind); }
>
> -  bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; }
>    bool isUndefined() const { return SymbolKind == UndefinedKind; }
>    bool isDefined() const { return SymbolKind <= DefinedLast; }
>    bool isCommon() const { return SymbolKind == DefinedCommonKind; }
> @@ -105,7 +73,7 @@ public:
>      return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind;
>    }
>    bool isShared() const { return SymbolKind == SharedKind; }
> -  bool isLocal() const { return Binding == llvm::ELF::STB_LOCAL; }
> +  bool isLocal() const { return IsLocal; }
>    bool isPreemptible() const;
>
>    // Returns the symbol name.
> @@ -121,12 +89,10 @@ public:
>    uint8_t getVisibility() const { return StOther & 0x3; }
>
>    unsigned DynsymIndex = 0;
> -  uint32_t GlobalDynIndex = -1;
>    uint32_t GotIndex = -1;
>    uint32_t GotPltIndex = -1;
>    uint32_t PltIndex = -1;
>    uint32_t ThunkIndex = -1;
> -  bool hasGlobalDynIndex() { return GlobalDynIndex != uint32_t(-1); }
>    bool isInGot() const { return GotIndex != -1U; }
>    bool isInPlt() const { return PltIndex != -1U; }
>    bool hasThunk() const { return ThunkIndex != -1U; }
> @@ -142,46 +108,23 @@ public:
>    template <class ELFT> typename ELFT::uint getThunkVA() const;
>    template <class ELFT> typename ELFT::uint getSize() const;
>
> -  // A SymbolBody has a backreference to a Symbol. Originally they are
> -  // doubly-linked. A backreference will never change. But the pointer
> -  // in the Symbol may be mutated by the resolver. If you have a
> -  // pointer P to a SymbolBody and are not sure whether the resolver
> -  // has chosen the object among other objects having the same name,
> -  // you can access P->Backref->Body to get the resolver's result.
> -  SymbolBody &repl() { return Backref ? *Backref->Body : *this; }
> -
> -  // Decides which symbol should "win" in the symbol table, this or
> -  // the Other. Returns 1 if this wins, -1 if the Other wins, or 0 if
> -  // they are duplicate (conflicting) symbols.
> -  int compare(SymbolBody *Other);
> -
>  protected:
> -  SymbolBody(Kind K, StringRef Name, uint8_t Binding, uint8_t StOther,
> -             uint8_t Type);
> +  SymbolBody(Kind K, StringRef Name, uint8_t StOther, uint8_t Type);
>
>    SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type);
>
>    const unsigned SymbolKind : 8;
>
>  public:
> -  // True if this symbol can be omitted from the symbol table if nothing else
> -  // requires it to be there. Right now this is only used for linkonce_odr in
> -  // LTO, but we could add the feature to ELF. It would be similar to
> -  // MachO's .weak_def_can_be_hidden.
> -  unsigned CanOmitFromDynSym : 1;
> -
>    // True if the linker has to generate a copy relocation for this shared
>    // symbol or if the symbol should point to its plt entry.
>    unsigned NeedsCopyOrPltAddr : 1;
>
> -  // True if the symbol is undefined and comes from a bitcode file. We need to
> -  // keep track of this because undefined symbols only prevent internalization
> -  // of bitcode symbols if they did not come from a bitcode file.
> -  unsigned IsUndefinedBitcode : 1;
> +  // True if this is a local symbol.
> +  unsigned IsLocal : 1;
>
>    // The following fields have the same meaning as the ELF symbol attributes.
>    uint8_t Type;    // symbol type
> -  uint8_t Binding; // symbol binding
>    uint8_t StOther; // st_other field value
>
>    bool isSection() const { return Type == llvm::ELF::STT_SECTION; }
> @@ -191,8 +134,6 @@ public:
>    bool isObject() const { return Type == llvm::ELF::STT_OBJECT; }
>    bool isFile() const { return Type == llvm::ELF::STT_FILE; }
>
> -  Symbol *Backref = nullptr;
> -
>  protected:
>    struct Str {
>      const char *S;
> @@ -207,8 +148,7 @@ protected:
>  // The base class for any defined symbols.
>  class Defined : public SymbolBody {
>  public:
> -  Defined(Kind K, StringRef Name, uint8_t Binding, uint8_t StOther,
> -          uint8_t Type);
> +  Defined(Kind K, StringRef Name, uint8_t StOther, uint8_t Type);
>    Defined(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type);
>    static bool classof(const SymbolBody *S) { return S->isDefined(); }
>  };
> @@ -216,14 +156,16 @@ public:
>  // The defined symbol in LLVM bitcode files.
>  class DefinedBitcode : public Defined {
>  public:
> -  DefinedBitcode(StringRef Name, bool IsWeak, uint8_t StOther);
> +  DefinedBitcode(StringRef Name, uint8_t StOther, uint8_t Type, BitcodeFile *F);
>    static bool classof(const SymbolBody *S);
> +
> +  BitcodeFile *File;
>  };
>
>  class DefinedCommon : public Defined {
>  public:
> -  DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, uint8_t Binding,
> -                uint8_t StOther, uint8_t Type);
> +  DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, uint8_t StOther,
> +                uint8_t Type);
>
>    static bool classof(const SymbolBody *S) {
>      return S->kind() == SymbolBody::DefinedCommonKind;
> @@ -247,8 +189,8 @@ template <class ELFT> class DefinedRegul
>  public:
>    DefinedRegular(StringRef Name, const Elf_Sym &Sym,
>                   InputSectionBase<ELFT> *Section)
> -      : Defined(SymbolBody::DefinedRegularKind, Name, Sym.getBinding(),
> -                Sym.st_other, Sym.getType()),
> +      : Defined(SymbolBody::DefinedRegularKind, Name, Sym.st_other,
> +                Sym.getType()),
>          Value(Sym.st_value), Size(Sym.st_size),
>          Section(Section ? Section->Repl : NullInputSection) {}
>
> @@ -260,8 +202,8 @@ public:
>      assert(isLocal());
>    }
>
> -  DefinedRegular(StringRef Name, uint8_t Binding, uint8_t StOther)
> -      : Defined(SymbolBody::DefinedRegularKind, Name, Binding, StOther,
> +  DefinedRegular(StringRef Name, uint8_t StOther)
> +      : Defined(SymbolBody::DefinedRegularKind, Name, StOther,
>                  llvm::ELF::STT_NOTYPE),
>          Value(0), Size(0), Section(NullInputSection) {}
>
> @@ -311,8 +253,7 @@ public:
>
>  class Undefined : public SymbolBody {
>  public:
> -  Undefined(StringRef Name, uint8_t Binding, uint8_t StOther, uint8_t Type,
> -            bool IsBitcode);
> +  Undefined(StringRef Name, uint8_t StOther, uint8_t Type);
>    Undefined(uint32_t NameOffset, uint8_t StOther, uint8_t Type);
>
>    static bool classof(const SymbolBody *S) {
> @@ -332,8 +273,7 @@ public:
>
>    SharedSymbol(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym,
>                 const Elf_Verdef *Verdef)
> -      : Defined(SymbolBody::SharedKind, Name, Sym.getBinding(), Sym.st_other,
> -                Sym.getType()),
> +      : Defined(SymbolBody::SharedKind, Name, Sym.st_other, Sym.getType()),
>          File(F), Sym(Sym), Verdef(Verdef) {
>      // IFuncs defined in DSOs are treated as functions by the static linker.
>      if (isGnuIFunc())
> @@ -364,9 +304,8 @@ public:
>  // the same name, it will ask the Lazy to load a file.
>  class Lazy : public SymbolBody {
>  public:
> -  Lazy(SymbolBody::Kind K, StringRef Name)
> -      : SymbolBody(K, Name, llvm::ELF::STB_GLOBAL, llvm::ELF::STV_DEFAULT,
> -                   /* Type */ 0) {}
> +  Lazy(SymbolBody::Kind K, StringRef Name, uint8_t Type)
> +      : SymbolBody(K, Name, llvm::ELF::STV_DEFAULT, Type) {}
>
>    static bool classof(const SymbolBody *S) { return S->isLazy(); }
>
> @@ -378,8 +317,9 @@ public:
>  // LazyArchive symbols represents symbols in archive files.
>  class LazyArchive : public Lazy {
>  public:
> -  LazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S)
> -      : Lazy(LazyArchiveKind, S.getName()), File(F), Sym(S) {}
> +  LazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S,
> +              uint8_t Type)
> +      : Lazy(LazyArchiveKind, S.getName(), Type), File(F), Sym(S) {}
>
>    static bool classof(const SymbolBody *S) {
>      return S->kind() == LazyArchiveKind;
> @@ -396,8 +336,8 @@ private:
>  // --start-lib and --end-lib options.
>  class LazyObject : public Lazy {
>  public:
> -  LazyObject(StringRef Name, MemoryBufferRef M)
> -      : Lazy(LazyObjectKind, Name), MBRef(M) {}
> +  LazyObject(StringRef Name, MemoryBufferRef M, uint8_t Type)
> +      : Lazy(LazyObjectKind, Name, Type), MBRef(M) {}
>
>    static bool classof(const SymbolBody *S) {
>      return S->kind() == LazyObjectKind;
> @@ -424,16 +364,8 @@ template <class ELFT> struct ElfSym {
>    static DefinedRegular<ELFT> *End;
>    static DefinedRegular<ELFT> *End2;
>
> -  // The content for _gp symbol for MIPS target.
> -  static SymbolBody *MipsGp;
> -
> -  static SymbolBody *MipsLocalGp;
> +  // The content for _gp_disp symbol for MIPS target.
>    static SymbolBody *MipsGpDisp;
> -
> -  // __rel_iplt_start/__rel_iplt_end for signaling
> -  // where R_[*]_IRELATIVE relocations do live.
> -  static SymbolBody *RelaIpltStart;
> -  static SymbolBody *RelaIpltEnd;
>  };
>
>  template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Etext;
> @@ -442,11 +374,76 @@ template <class ELFT> DefinedRegular<ELF
>  template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Edata2;
>  template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::End;
>  template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::End2;
> -template <class ELFT> SymbolBody *ElfSym<ELFT>::MipsGp;
> -template <class ELFT> SymbolBody *ElfSym<ELFT>::MipsLocalGp;
>  template <class ELFT> SymbolBody *ElfSym<ELFT>::MipsGpDisp;
> -template <class ELFT> SymbolBody *ElfSym<ELFT>::RelaIpltStart;
> -template <class ELFT> SymbolBody *ElfSym<ELFT>::RelaIpltEnd;
> +
> +// A real symbol object, SymbolBody, is usually stored within a Symbol. There's
> +// always one Symbol for each symbol name. The resolver updates the SymbolBody
> +// stored in the Body field of this object as it resolves symbols. Symbol also
> +// holds computed properties of symbol names.
> +struct Symbol {
> +  uint32_t GlobalDynIndex = -1;
> +
> +  // Symbol binding. This is on the Symbol to track changes during resolution.
> +  // In particular:
> +  // An undefined weak is still weak when it resolves to a shared library.
> +  // An undefined weak will not fetch archive members, but we have to remember
> +  // it is weak.
> +  uint8_t Binding;
> +
> +  // Symbol visibility. This is the computed minimum visibility of all
> +  // observed non-DSO symbols.
> +  unsigned Visibility : 2;
> +
> +  // True if the symbol was used for linking and thus need to be added to the
> +  // output file's symbol table. This is true for all symbols except for
> +  // unreferenced DSO symbols and bitcode symbols that are unreferenced except
> +  // by other bitcode objects.
> +  unsigned IsUsedInRegularObj : 1;
> +
> +  // If this flag is true and the symbol has protected or default visibility, it
> +  // will appear in .dynsym. This flag is set by interposable DSO symbols in
> +  // executables, by most symbols in DSOs and executables built with
> +  // --export-dynamic, and by dynamic lists.
> +  unsigned ExportDynamic : 1;
> +
> +  // This flag acts as an additional filter on the dynamic symbol list. It is
> +  // set if there is no version script, or if the symbol appears in the global
> +  // section of the version script.
> +  unsigned VersionScriptGlobal : 1;
> +
> +  bool includeInDynsym() const;
> +  bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; }
> +
> +  // This field is used to store the Symbol's SymbolBody. This instantiation of
> +  // AlignedCharArrayUnion gives us a struct with a char array field that is
> +  // large and aligned enough to store any derived class of SymbolBody. We
> +  // assume that the size and alignment of ELF64LE symbols is sufficient for any
> +  // ELFT, and we verify this with the static_asserts in replaceBody.
> +  llvm::AlignedCharArrayUnion<
> +      DefinedBitcode, DefinedCommon, DefinedRegular<llvm::object::ELF64LE>,
> +      DefinedSynthetic<llvm::object::ELF64LE>, Undefined,
> +      SharedSymbol<llvm::object::ELF64LE>, LazyArchive, LazyObject>
> +      Body;
> +
> +  SymbolBody *body() { return reinterpret_cast<SymbolBody *>(Body.buffer); }
> +  const SymbolBody *body() const { return const_cast<Symbol *>(this)->body(); }
> +};
> +
> +template <typename T, typename... ArgT>
> +void replaceBody(Symbol *S, ArgT &&... Arg) {
> +  static_assert(sizeof(T) <= sizeof(S->Body), "Body too small");
> +  static_assert(alignof(T) <= alignof(decltype(S->Body)),
> +                "Body not aligned enough");
> +  static_assert(static_cast<SymbolBody *>(static_cast<T *>(nullptr)) == nullptr,
> +                "Not a SymbolBody");
> +  new (S->Body.buffer) T(std::forward<ArgT>(Arg)...);
> +}
> +
> +inline Symbol *SymbolBody::symbol() {
> +  assert(!isLocal());
> +  return reinterpret_cast<Symbol *>(reinterpret_cast<char *>(this) -
> +                                    offsetof(Symbol, Body));
> +}
>
>  } // namespace elf
>  } // namespace lld
>
> Modified: lld/trunk/ELF/Writer.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=268178&r1=268177&r2=268178&view=diff
> ==============================================================================
> --- lld/trunk/ELF/Writer.cpp (original)
> +++ lld/trunk/ELF/Writer.cpp Sat Apr 30 23:55:03 2016
> @@ -428,13 +428,8 @@ static int32_t findMipsPairedAddend(cons
>  // True if non-preemptable symbol always has the same value regardless of where
>  // the DSO is loaded.
>  template <class ELFT> static bool isAbsolute(const SymbolBody &Body) {
> -  Symbol *Sym = Body.Backref;
> -  if (Body.isUndefined()) {
> -    if (!Sym)
> -      return false; // undefined local. That is the dummy symbol 0.
> -    if (Sym->isWeak())
> -      return true; // always 0
> -  }
> +  if (Body.isUndefined())
> +    return !Body.isLocal() && Body.symbol()->isWeak();
>    if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(&Body))
>      return DR->Section == nullptr; // Absolute symbol.
>    return false;
> @@ -771,7 +766,7 @@ static void reportUndefined(SymbolTable<
>      if (Config->Relocatable)
>        return;
>      if (Config->Shared)
> -      if (Sym->Backref->Visibility == STV_DEFAULT)
> +      if (Sym->symbol()->Visibility == STV_DEFAULT)
>          return;
>    }
>
> @@ -1022,15 +1017,19 @@ void Writer<ELFT>::addCopyRelSymbol(Shar
>    Out<ELFT>::Bss->updateAlign(Align);
>    uintX_t Shndx = SS->Sym.st_shndx;
>    uintX_t Value = SS->Sym.st_value;
> -  // Look through the DSO's dynamic symbol for aliases and create a dynamic
> -  // symbol for each one. This causes the copy relocation to correctly interpose
> -  // any aliases.
> -  for (SharedSymbol<ELFT> &S : SS->File->getSharedSymbols()) {
> -    if (S.Sym.st_shndx != Shndx || S.Sym.st_value != Value)
> +  // Look through the DSO's dynamic symbol table for aliases and create a
> +  // dynamic symbol for each one. This causes the copy relocation to correctly
> +  // interpose any aliases.
> +  for (const Elf_Sym &S : SS->File->getElfSymbols(true)) {
> +    if (S.st_shndx != Shndx || S.st_value != Value)
> +      continue;
> +    auto *Alias = dyn_cast_or_null<SharedSymbol<ELFT>>(
> +        Symtab.find(check(S.getName(SS->File->getStringTable()))));
> +    if (!Alias)
>        continue;
> -    S.OffsetInBss = Off;
> -    S.NeedsCopyOrPltAddr = true;
> -    S.Backref->IsUsedInRegularObj = true;
> +    Alias->OffsetInBss = Off;
> +    Alias->NeedsCopyOrPltAddr = true;
> +    Alias->symbol()->IsUsedInRegularObj = true;
>    }
>    Out<ELFT>::RelaDyn->addReloc(
>        {Target->CopyRel, Out<ELFT>::Bss, SS->OffsetInBss, false, SS, 0});
> @@ -1067,9 +1066,9 @@ bool Writer<ELFT>::isDiscarded(InputSect
>  }
>
>  template <class ELFT>
> -static SymbolBody *
> -addOptionalSynthetic(SymbolTable<ELFT> &Table, StringRef Name,
> -                     OutputSectionBase<ELFT> &Sec, typename ELFT::uint Val) {
> +static Symbol *addOptionalSynthetic(SymbolTable<ELFT> &Table, StringRef Name,
> +                                    OutputSectionBase<ELFT> &Sec,
> +                                    typename ELFT::uint Val) {
>    if (!Table.find(Name))
>      return nullptr;
>    return Table.addSynthetic(Name, Sec, Val);
> @@ -1085,16 +1084,15 @@ template <class ELFT> void Writer<ELFT>:
>    if (isOutputDynamic() || !Out<ELFT>::RelaPlt)
>      return;
>    StringRef S = Config->Rela ? "__rela_iplt_start" : "__rel_iplt_start";
> -  ElfSym<ELFT>::RelaIpltStart =
> -      addOptionalSynthetic(Symtab, S, *Out<ELFT>::RelaPlt, 0);
> +  addOptionalSynthetic(Symtab, S, *Out<ELFT>::RelaPlt, 0);
>
>    S = Config->Rela ? "__rela_iplt_end" : "__rel_iplt_end";
> -  ElfSym<ELFT>::RelaIpltEnd = addOptionalSynthetic(
> -      Symtab, S, *Out<ELFT>::RelaPlt, DefinedSynthetic<ELFT>::SectionEnd);
> +  addOptionalSynthetic(Symtab, S, *Out<ELFT>::RelaPlt,
> +                       DefinedSynthetic<ELFT>::SectionEnd);
>  }
>
>  template <class ELFT> static bool includeInSymtab(const SymbolBody &B) {
> -  if (!B.Backref->IsUsedInRegularObj)
> +  if (!B.symbol()->IsUsedInRegularObj)
>      return false;
>
>    if (auto *D = dyn_cast<DefinedRegular<ELFT>>(&B)) {
> @@ -1191,19 +1189,19 @@ template <class ELFT> void Writer<ELFT>:
>      // so that it points to an absolute address which is relative to GOT.
>      // See "Global Data Symbols" in Chapter 6 in the following document:
>      // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
> -    ElfSym<ELFT>::MipsGp =
> -        Symtab.addSynthetic("_gp", *Out<ELFT>::Got, MipsGPOffset);
> +    Symtab.addSynthetic("_gp", *Out<ELFT>::Got, MipsGPOffset);
>
>      // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between
>      // start of function and 'gp' pointer into GOT.
>      ElfSym<ELFT>::MipsGpDisp =
> -        addOptionalSynthetic(Symtab, "_gp_disp", *Out<ELFT>::Got, MipsGPOffset);
> +        addOptionalSynthetic(Symtab, "_gp_disp", *Out<ELFT>::Got, MipsGPOffset)
> +            ->body();
>      // The __gnu_local_gp is a magic symbol equal to the current value of 'gp'
>      // pointer. This symbol is used in the code generated by .cpload pseudo-op
>      // in case of using -mno-shared option.
>      // https://sourceware.org/ml/binutils/2004-12/msg00094.html
> -    ElfSym<ELFT>::MipsLocalGp = addOptionalSynthetic(
> -        Symtab, "__gnu_local_gp", *Out<ELFT>::Got, MipsGPOffset);
> +    addOptionalSynthetic(Symtab, "__gnu_local_gp", *Out<ELFT>::Got,
> +                         MipsGPOffset);
>    }
>
>    // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol
> @@ -1363,7 +1361,7 @@ template <class ELFT> void Writer<ELFT>:
>    // synthesized ones. Visit all symbols to give the finishing touches.
>    std::vector<DefinedCommon *> CommonSymbols;
>    for (Symbol *S : Symtab.getSymbols()) {
> -    SymbolBody *Body = S->Body;
> +    SymbolBody *Body = S->body();
>
>      // Set "used" bit for --as-needed.
>      if (S->IsUsedInRegularObj && !S->isWeak())
> @@ -1781,7 +1779,7 @@ static uint32_t getMipsEFlags(bool Is64B
>
>  template <class ELFT> static typename ELFT::uint getEntryAddr() {
>    if (Symbol *S = Config->EntrySym)
> -    return S->Body->getVA<ELFT>();
> +    return S->body()->getVA<ELFT>();
>    if (Config->EntryAddr != uint64_t(-1))
>      return Config->EntryAddr;
>    return 0;
>
> Modified: lld/trunk/docs/NewLLD.rst
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/docs/NewLLD.rst?rev=268178&r1=268177&r2=268178&view=diff
> ==============================================================================
> --- lld/trunk/docs/NewLLD.rst (original)
> +++ lld/trunk/docs/NewLLD.rst Sat Apr 30 23:55:03 2016
> @@ -186,23 +186,24 @@ Once you understand their functions, the
>
>  * Symbol
>
> -  Symbol is a pointer to a SymbolBody. There's only one Symbol for
> -  each unique symbol name (this uniqueness is guaranteed by the symbol table).
> -  Because SymbolBodies are created for each file independently,
> -  there can be many SymbolBodies for the same name.
> -  Thus, the relationship between Symbols and SymbolBodies is 1:N.
> -  You can think of Symbols as handles for SymbolBodies.
> -
> -  The resolver keeps the Symbol's pointer to always point to the "best" SymbolBody.
> -  Pointer mutation is the resolve operation of this linker.
> -
> -  SymbolBodies have pointers to their Symbols.
> -  That means you can always find the best SymbolBody from
> -  any SymbolBody by following pointers twice.
> -  This structure makes it very easy and cheap to find replacements for symbols.
> -  For example, if you have an Undefined SymbolBody, you can find a Defined
> -  SymbolBody for that symbol just by going to its Symbol and then to SymbolBody,
> -  assuming the resolver have successfully resolved all undefined symbols.
> +  A Symbol is a container for a SymbolBody. There's only one Symbol for each
> +  unique symbol name (this uniqueness is guaranteed by the symbol table).
> +  Each global symbol has only one SymbolBody at any one time, which is
> +  the SymbolBody stored within a memory region of the Symbol large enough
> +  to store any SymbolBody.
> +
> +  As the resolver reads symbols from input files, it replaces the Symbol's
> +  SymbolBody with the "best" SymbolBody for its symbol name by constructing
> +  the new SymbolBody in place on top of the existing SymbolBody. For example,
> +  if the resolver is given a defined symbol, and the SymbolBody with its name
> +  is undefined, it will construct a Defined SymbolBody over the Undefined
> +  SymbolBody.
> +
> +  This means that each SymbolBody pointer always points to the best SymbolBody,
> +  and it is possible to get from a SymbolBody to a Symbol, or vice versa,
> +  by adding or subtracting a fixed offset. This memory layout helps reduce
> +  the cache miss rate through high locality and a small number of required
> +  pointer indirections.
>
>  * SymbolTable
>
>
> Modified: lld/trunk/test/ELF/lto/common2.ll
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/lto/common2.ll?rev=268178&r1=268177&r2=268178&view=diff
> ==============================================================================
> --- lld/trunk/test/ELF/lto/common2.ll (original)
> +++ lld/trunk/test/ELF/lto/common2.ll Sat Apr 30 23:55:03 2016
> @@ -18,7 +18,7 @@ target triple = "x86_64-unknown-linux-gn
>  ; SHARED-NEXT:   Value: 0x2000
>  ; SHARED-NEXT:   Size: 1
>  ; SHARED-NEXT:   Binding: Global
> -; SHARED-NEXT:   Type: None
> +; SHARED-NEXT:   Type: Object
>  ; SHARED-NEXT:   Other: 0
>  ; SHARED-NEXT:   Section: .bss
>  ; SHARED-NEXT: }
>
> Modified: lld/trunk/test/ELF/relocation-copy-alias.s
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/relocation-copy-alias.s?rev=268178&r1=268177&r2=268178&view=diff
> ==============================================================================
> --- lld/trunk/test/ELF/relocation-copy-alias.s (original)
> +++ lld/trunk/test/ELF/relocation-copy-alias.s Sat Apr 30 23:55:03 2016
> @@ -53,7 +53,7 @@ movl $5, b2
>  // CHECK:      Name: a2
>  // CHECK-NEXT: Value: [[A]]
>  // CHECK-NEXT: Size: 1
> -// CHECK-NEXT: Binding: Global
> +// CHECK-NEXT: Binding: Weak
>  // CHECK-NEXT: Type: Object (0x1)
>  // CHECK-NEXT: Other: 0
>  // CHECK-NEXT: Section: .bss
> @@ -61,7 +61,7 @@ movl $5, b2
>  // CHECK:      Name: b3
>  // CHECK-NEXT: Value: [[B]]
>  // CHECK-NEXT: Size: 1
> -// CHECK-NEXT: Binding: Global (0x1)
> +// CHECK-NEXT: Binding: Weak
>  // CHECK-NEXT: Type: Object (0x1)
>  // CHECK-NEXT: Other: 0
>  // CHECK-NEXT: Section: .bss
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits


More information about the llvm-commits mailing list