Don't store an Elf_Sym for most symbols.
authorRafael Espindola <rafael.espindola@gmail.com>
Mon, 4 Apr 2016 14:04:16 +0000 (14:04 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Mon, 4 Apr 2016 14:04:16 +0000 (14:04 +0000)
Our symbol representation was redundant, and some times would get out of
sync. It had an Elf_Sym, but some fields were copied to SymbolBody.

Different parts of the code were checking the bits in SymbolBody and
others were checking Elf_Sym.

There are two general approaches to fix this:
* Copy the required information and don't store and Elf_Sym.
* Don't copy the information and always use the Elf_Smy.

The second way sounds tempting, but has a big problem: we would have to
template SymbolBody. I started doing it, but it requires templeting
*everything* and creates a bit chicken and egg problem at the driver
where we have to find ELFT before we can create an ArchiveFile for
example.

As much as possible I compared the test differences with what gold and
bfd produce to make sure they are still valid. In most cases we are just
adding hidden visibility to a local symbol, which is harmless.

In most tests this is a small speedup. The only slowdown was scylla
(1.006X). The largest speedup was clang with no --build-id, -O3 or
--gc-sections (i.e.: focus on the relocations): 1.019X.

llvm-svn: 265293

21 files changed:
lld/ELF/Driver.cpp
lld/ELF/ICF.cpp
lld/ELF/InputFiles.cpp
lld/ELF/InputFiles.h
lld/ELF/InputSection.cpp
lld/ELF/InputSection.h
lld/ELF/MarkLive.cpp
lld/ELF/OutputSections.cpp
lld/ELF/SymbolTable.cpp
lld/ELF/SymbolTable.h
lld/ELF/Symbols.cpp
lld/ELF/Symbols.h
lld/ELF/Target.cpp
lld/ELF/Writer.cpp
lld/test/ELF/aarch64-gnu-ifunc.s
lld/test/ELF/basic-mips.s
lld/test/ELF/global_offset_table_shared.s
lld/test/ELF/gnu-ifunc-i386.s
lld/test/ELF/gnu-ifunc.s
lld/test/ELF/mips-gp-disp.s
lld/test/ELF/mips-hilo-gp-disp.s

index ab1098d..93103d9 100644 (file)
@@ -366,17 +366,7 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
     error("no input files.");
 }
 
-template <class ELFT> static void initSymbols() {
-  ElfSym<ELFT>::Etext.setBinding(STB_GLOBAL);
-  ElfSym<ELFT>::Edata.setBinding(STB_GLOBAL);
-  ElfSym<ELFT>::End.setBinding(STB_GLOBAL);
-  ElfSym<ELFT>::Ignored.setBinding(STB_WEAK);
-  ElfSym<ELFT>::Ignored.setVisibility(STV_HIDDEN);
-}
-
 template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
-  initSymbols<ELFT>();
-
   SymbolTable<ELFT> Symtab;
   std::unique_ptr<TargetInfo> TI(createTarget());
   Target = TI.get();
@@ -390,21 +380,6 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
       Config->EMachine != EM_AMDGPU)
     Config->Entry = Config->EMachine == EM_MIPS ? "__start" : "_start";
 
-  // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol
-  // is magical and is used to produce a R_386_GOTPC relocation.
-  // The R_386_GOTPC relocation value doesn't actually depend on the
-  // symbol value, so it could use an index of STN_UNDEF which, according
-  // to the spec, means the symbol value is 0.
-  // Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in
-  // the object file.
-  // The situation is even stranger on x86_64 where the assembly doesn't
-  // need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as
-  // an undefined symbol in the .o files.
-  // Given that the symbol is effectively unused, we just create a dummy
-  // hidden one to avoid the undefined symbol error.
-  if (!Config->Relocatable)
-    Symtab.addIgnored("_GLOBAL_OFFSET_TABLE_");
-
   if (!Config->Entry.empty()) {
     // Set either EntryAddr (if S is a number) or EntrySym (otherwise).
     StringRef S = Config->Entry;
@@ -413,20 +388,11 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
   }
 
   if (Config->EMachine == EM_MIPS) {
-    // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between
-    // start of function and 'gp' pointer into GOT.
-    Config->MipsGpDisp = Symtab.addIgnored("_gp_disp");
-    // 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
-    Config->MipsLocalGp = Symtab.addIgnored("__gnu_local_gp");
-
     // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer
     // 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
-    Symtab.addAbsolute("_gp", ElfSym<ELFT>::MipsGp);
+    ElfSym<ELFT>::MipsGp = Symtab.addAbsolute("_gp", STV_DEFAULT);
   }
 
   for (std::unique_ptr<InputFile> &F : Files)
index 7392e72..a69acdd 100644 (file)
@@ -132,7 +132,7 @@ template <class ELFT> uint64_t ICF<ELFT>::getHash(InputSection<ELFT> *S) {
 
 // Returns true if Sec is subject of ICF.
 template <class ELFT> bool ICF<ELFT>::isEligible(InputSectionBase<ELFT> *Sec) {
-  if (!Sec || Sec == InputSection<ELFT>::Discarded || !Sec->Live)
+  if (!Sec || Sec == &InputSection<ELFT>::Discarded || !Sec->Live)
     return false;
   auto *S = dyn_cast<InputSection<ELFT>>(Sec);
   if (!S)
@@ -270,7 +270,7 @@ bool ICF<ELFT>::variableEq(const InputSection<ELFT> *A,
     auto *DB = dyn_cast<DefinedRegular<ELFT>>(&SB);
     if (!DA || !DB)
       return false;
-    if (DA->Sym.st_value != DB->Sym.st_value)
+    if (DA->Value != DB->Value)
       return false;
     InputSection<ELFT> *X = dyn_cast<InputSection<ELFT>>(DA->Section);
     InputSection<ELFT> *Y = dyn_cast<InputSection<ELFT>>(DB->Section);
index 3622dc2..34236ac 100644 (file)
@@ -175,18 +175,18 @@ void elf::ObjectFile<ELFT>::initializeSections(
   const ELFFile<ELFT> &Obj = this->ELFObj;
   for (const Elf_Shdr &Sec : Obj.sections()) {
     ++I;
-    if (Sections[I] == InputSection<ELFT>::Discarded)
+    if (Sections[I] == &InputSection<ELFT>::Discarded)
       continue;
 
     switch (Sec.sh_type) {
     case SHT_GROUP:
-      Sections[I] = InputSection<ELFT>::Discarded;
+      Sections[I] = &InputSection<ELFT>::Discarded;
       if (ComdatGroups.insert(getShtGroupSignature(Sec)).second)
         continue;
       for (uint32_t SecIndex : getShtGroupEntries(Sec)) {
         if (SecIndex >= Size)
           fatal("invalid section index in group");
-        Sections[SecIndex] = InputSection<ELFT>::Discarded;
+        Sections[SecIndex] = &InputSection<ELFT>::Discarded;
       }
       break;
     case SHT_SYMTAB:
@@ -242,7 +242,7 @@ elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
   // Strictly speaking, a relocation section must be included in the
   // group of the section it relocates. However, LLVM 3.3 and earlier
   // would fail to do so, so we gracefully handle that case.
-  if (Target == InputSection<ELFT>::Discarded)
+  if (Target == &InputSection<ELFT>::Discarded)
     return nullptr;
 
   if (!Target)
@@ -260,7 +260,7 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
   // is controlled only by the command line option (-z execstack) in LLD,
   // .note.GNU-stack is ignored.
   if (Name == ".note.GNU-stack")
-    return InputSection<ELFT>::Discarded;
+    return &InputSection<ELFT>::Discarded;
 
   if (Name == ".note.GNU-split-stack")
     error("objects using splitstacks are not supported");
@@ -299,19 +299,20 @@ elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
   if (Index >= Sections.size() || !Sections[Index])
     fatal("invalid section index");
   InputSectionBase<ELFT> *S = Sections[Index];
-  if (S == InputSectionBase<ELFT>::Discarded)
+  if (S == &InputSectionBase<ELFT>::Discarded)
     return S;
   return S->Repl;
 }
 
 template <class ELFT>
 SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
+  uint32_t NameOffset = Sym->st_name;
   unsigned char Binding = Sym->getBinding();
   InputSectionBase<ELFT> *Sec = getSection(*Sym);
   if (Binding == STB_LOCAL) {
-    if (Sec == InputSection<ELFT>::Discarded)
-      Sec = nullptr;
-    return new (Alloc) DefinedRegular<ELFT>("", *Sym, Sec);
+    if (Sym->st_shndx == SHN_UNDEF)
+      return new (Alloc) UndefinedElf<ELFT>(NameOffset, *Sym);
+    return new (Alloc) DefinedRegular<ELFT>(NameOffset, *Sym, Sec);
   }
 
   StringRef Name = check(Sym->getName(this->StringTable));
@@ -320,9 +321,8 @@ SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
   case SHN_UNDEF:
     return new (Alloc) UndefinedElf<ELFT>(Name, *Sym);
   case SHN_COMMON:
-    return new (Alloc) DefinedCommon(Name, Sym->st_size, Sym->st_value,
-                                     Sym->getBinding() == llvm::ELF::STB_WEAK,
-                                     Sym->getVisibility());
+    return new (Alloc) DefinedCommon(Name, Sym->st_size, Sym->st_value, Binding,
+                                     Sym->st_other, Sym->getType());
   }
 
   switch (Binding) {
@@ -331,7 +331,7 @@ SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
   case STB_GLOBAL:
   case STB_WEAK:
   case STB_GNU_UNIQUE:
-    if (Sec == InputSection<ELFT>::Discarded)
+    if (Sec == &InputSection<ELFT>::Discarded)
       return new (Alloc) UndefinedElf<ELFT>(Name, *Sym);
     return new (Alloc) DefinedRegular<ELFT>(Name, *Sym, Sec);
   }
@@ -426,6 +426,9 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() {
   uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
   SymbolBodies.reserve(NumSymbols);
   for (const Elf_Sym &Sym : Syms) {
+    // FIXME: We should probably just err if we get a local symbol in here.
+    if (Sym.getBinding() == STB_LOCAL)
+      continue;
     StringRef Name = check(Sym.getName(this->StringTable));
     if (Sym.isUndefined())
       Undefs.push_back(Name);
@@ -479,11 +482,13 @@ BitcodeFile::createSymbolBody(const DenseSet<const Comdat *> &KeptComdats,
     const DataLayout &DL = M.getDataLayout();
     uint64_t Size = DL.getTypeAllocSize(GV->getValueType());
     Body = new (Alloc)
-        DefinedCommon(NameRef, Size, GV->getAlignment(), IsWeak, Visibility);
+        DefinedCommon(NameRef, Size, GV->getAlignment(),
+                      IsWeak ? STB_WEAK : STB_GLOBAL, Visibility, /*Type*/ 0);
   } else {
     Body = new (Alloc) DefinedBitcode(NameRef, IsWeak, Visibility);
   }
-  Body->IsTls = GV->isThreadLocal();
+  if (GV->isThreadLocal())
+    Body->Type = STT_TLS;
   return Body;
 }
 
index 5f7356b..b4f2e15 100644 (file)
@@ -129,7 +129,7 @@ public:
 
   // The number is the offset in the string table. It will be used as the
   // st_name of the symbol.
-  std::vector<std::pair<const Elf_Sym *, unsigned>> KeptLocalSyms;
+  std::vector<std::pair<const DefinedRegular<ELFT> *, unsigned>> KeptLocalSyms;
 
 private:
   void initializeSections(llvm::DenseSet<StringRef> &ComdatGroups);
index 21cd720..d007739 100644 (file)
@@ -72,8 +72,9 @@ typename ELFT::uint InputSectionBase<ELFT>::getOffset(uintX_t Offset) {
 }
 
 template <class ELFT>
-typename ELFT::uint InputSectionBase<ELFT>::getOffset(const Elf_Sym &Sym) {
-  return getOffset(Sym.st_value);
+typename ELFT::uint
+InputSectionBase<ELFT>::getOffset(const DefinedRegular<ELFT> &Sym) {
+  return getOffset(Sym.Value);
 }
 
 // Returns a section that Rel relocation is pointing to.
@@ -305,7 +306,7 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
         SymVA = getMipsGotVA<ELFT>(Body, SymVA, BufLoc);
       else
         SymVA = Body.getGotVA<ELFT>() + A;
-      if (Body.IsTls)
+      if (Body.isTls())
         Type = Target->getTlsGotRel(Type);
     } else if (Target->isSizeRel(Type) && Body.isPreemptible()) {
       // A SIZE relocation is supposed to set a symbol size, but if a symbol
index 650e705..9064abb 100644 (file)
@@ -19,6 +19,7 @@ namespace lld {
 namespace elf {
 
 template <class ELFT> class ICF;
+template <class ELFT> class DefinedRegular;
 template <class ELFT> class ObjectFile;
 template <class ELFT> class OutputSection;
 template <class ELFT> class OutputSectionBase;
@@ -40,6 +41,8 @@ public:
   enum Kind { Regular, EHFrame, Merge, MipsReginfo };
   Kind SectionKind;
 
+  InputSectionBase() : Repl(this) {}
+
   InputSectionBase(ObjectFile<ELFT> *File, const Elf_Shdr *Header,
                    Kind SectionKind);
   OutputSectionBase<ELFT> *OutSec = nullptr;
@@ -58,12 +61,12 @@ public:
   // Returns the size of this section (even if this is a common or BSS.)
   size_t getSize() const;
 
-  static InputSectionBase<ELFT> *Discarded;
+  static InputSectionBase<ELFT> Discarded;
 
   StringRef getSectionName() const;
   const Elf_Shdr *getSectionHdr() const { return Header; }
   ObjectFile<ELFT> *getFile() const { return File; }
-  uintX_t getOffset(const Elf_Sym &Sym);
+  uintX_t getOffset(const DefinedRegular<ELFT> &Sym);
 
   // Translate an offset in the input section to an offset in the output
   // section.
@@ -85,9 +88,7 @@ private:
                                const RelTy *Rel, const RelTy *End);
 };
 
-template <class ELFT>
-InputSectionBase<ELFT> *
-    InputSectionBase<ELFT>::Discarded = (InputSectionBase<ELFT> *)-1ULL;
+template <class ELFT> InputSectionBase<ELFT> InputSectionBase<ELFT>::Discarded;
 
 // Usually sections are copied to the output as atomic chunks of data,
 // but some special types of sections are split into small pieces of data
index ecb6ac9..56c89f6 100644 (file)
@@ -124,7 +124,7 @@ template <class ELFT> void elf::markLive(SymbolTable<ELFT> *Symtab) {
   // script KEEP command.
   for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab->getObjectFiles())
     for (InputSectionBase<ELFT> *Sec : F->getSections())
-      if (Sec && Sec != InputSection<ELFT>::Discarded)
+      if (Sec && Sec != &InputSection<ELFT>::Discarded)
         if (isReserved(Sec) || Script->shouldKeep<ELFT>(Sec))
           Enqueue(Sec);
 
index b5aed1c..c019fa0 100644 (file)
@@ -1426,22 +1426,23 @@ void SymbolTableSection<ELFT>::writeLocalSymbols(uint8_t *&Buf) {
   // Iterate over all input object files to copy their local symbols
   // to the output symbol table pointed by Buf.
   for (const std::unique_ptr<ObjectFile<ELFT>> &File : Table.getObjectFiles()) {
-    for (const std::pair<const Elf_Sym *, size_t> &P : File->KeptLocalSyms) {
-      const Elf_Sym *Sym = P.first;
-
+    for (const std::pair<const DefinedRegular<ELFT> *, size_t> &P :
+         File->KeptLocalSyms) {
+      const DefinedRegular<ELFT> &Body = *P.first;
+      InputSectionBase<ELFT> *Section = Body.Section;
       auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
-      if (Sym->st_shndx == SHN_ABS) {
+
+      if (!Section) {
         ESym->st_shndx = SHN_ABS;
-        ESym->st_value = Sym->st_value;
+        ESym->st_value = Body.Value;
       } else {
-        InputSectionBase<ELFT> *Section = File->getSection(*Sym);
         const OutputSectionBase<ELFT> *OutSec = Section->OutSec;
         ESym->st_shndx = OutSec->SectionIndex;
-        ESym->st_value = OutSec->getVA() + Section->getOffset(*Sym);
+        ESym->st_value = OutSec->getVA() + Section->getOffset(Body);
       }
       ESym->st_name = P.second;
-      ESym->st_size = Sym->st_size;
-      ESym->setBindingAndType(Sym->getBinding(), Sym->getType());
+      ESym->st_size = Body.template getSize<ELFT>();
+      ESym->setBindingAndType(Body.Binding, Body.Type);
       Buf += sizeof(*ESym);
     }
   }
@@ -1456,15 +1457,8 @@ void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *Buf) {
     SymbolBody *Body = P.first;
     size_t StrOff = P.second;
 
-    uint8_t Type = STT_NOTYPE;
-    uintX_t Size = 0;
-    if (const Elf_Sym *InputSym = Body->getElfSym<ELFT>()) {
-      Type = InputSym->getType();
-      Size = InputSym->st_size;
-    } else if (auto *C = dyn_cast<DefinedCommon>(Body)) {
-      Type = STT_OBJECT;
-      Size = C->Size;
-    }
+    uint8_t Type = Body->Type;
+    uintX_t Size = Body->getSize<ELFT>();
 
     ESym->setBindingAndType(getSymbolBinding(Body), Type);
     ESym->st_size = Size;
@@ -1521,11 +1515,9 @@ uint8_t SymbolTableSection<ELFT>::getSymbolBinding(SymbolBody *Body) {
   uint8_t Visibility = Body->getVisibility();
   if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
     return STB_LOCAL;
-  if (const Elf_Sym *ESym = Body->getElfSym<ELFT>())
-    return ESym->getBinding();
   if (isa<DefinedSynthetic<ELFT>>(Body))
     return STB_LOCAL;
-  return Body->isWeak() ? STB_WEAK : STB_GLOBAL;
+  return Body->Binding;
 }
 
 template <class ELFT>
index 6adc40b..06160db 100644 (file)
@@ -135,9 +135,10 @@ SymbolBody *SymbolTable<ELFT>::addUndefinedOpt(StringRef Name) {
 }
 
 template <class ELFT>
-SymbolBody *SymbolTable<ELFT>::addAbsolute(StringRef Name, Elf_Sym &ESym) {
+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, ESym, nullptr);
+  auto *Sym = new (Alloc) DefinedRegular<ELFT>(Name, STB_GLOBAL, Visibility);
   resolve(Sym);
   return Sym;
 }
@@ -152,11 +153,13 @@ SymbolBody *SymbolTable<ELFT>::addSynthetic(StringRef Name,
 }
 
 // Add Name as an "ignored" symbol. An ignored symbol is a regular
-// linker-synthesized defined symbol, but it is not recorded to the output
-// file's symbol table. Such symbols are useful for some linker-defined symbols.
+// linker-synthesized defined symbol, but is only defined if needed.
 template <class ELFT>
-SymbolBody *SymbolTable<ELFT>::addIgnored(StringRef Name) {
-  return addAbsolute(Name, ElfSym<ELFT>::Ignored);
+DefinedRegular<ELFT> *SymbolTable<ELFT>::addIgnored(StringRef Name,
+                                                    uint8_t Visibility) {
+  if (!find(Name))
+    return nullptr;
+  return addAbsolute(Name, Visibility);
 }
 
 // Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM.
@@ -228,7 +231,7 @@ template <class ELFT> void SymbolTable<ELFT>::resolve(SymbolBody *New) {
     return;
   }
 
-  if (New->IsTls != Existing->IsTls) {
+  if (New->isTls() != Existing->isTls()) {
     error("TLS attribute mismatch for symbol: " + conflictMsg(Existing, New));
     return;
   }
@@ -286,10 +289,10 @@ void SymbolTable<ELFT>::addMemberFile(Undefined *Undef, Lazy *L) {
   // symbols and copy information to reduce how many special cases are needed.
   if (Undef->isWeak()) {
     L->setUsedInRegularObj();
-    L->setWeak();
+    L->Binding = Undef->Binding;
+    L->Type = Undef->Type;
 
     // FIXME: Do we need to copy more?
-    L->IsTls |= Undef->IsTls;
     return;
   }
 
index 4fb2329..4c483b6 100644 (file)
@@ -53,21 +53,23 @@ public:
 
   SymbolBody *addUndefined(StringRef Name);
   SymbolBody *addUndefinedOpt(StringRef Name);
-  SymbolBody *addAbsolute(StringRef Name, Elf_Sym &ESym);
+  DefinedRegular<ELFT> *addAbsolute(StringRef Name,
+                                    uint8_t Visibility = llvm::ELF::STV_HIDDEN);
   SymbolBody *addSynthetic(StringRef Name, OutputSectionBase<ELFT> &Section,
                            uintX_t Value, uint8_t Visibility);
-  SymbolBody *addIgnored(StringRef Name);
+  DefinedRegular<ELFT> *addIgnored(StringRef Name,
+                                   uint8_t Visibility = llvm::ELF::STV_HIDDEN);
 
   void scanShlibUndefined();
   SymbolBody *find(StringRef Name);
   void wrap(StringRef Name);
   InputFile *findFile(SymbolBody *B);
+  void resolve(SymbolBody *Body);
 
 private:
   Symbol *insert(SymbolBody *New);
   void addLazy(Lazy *New);
   void addMemberFile(Undefined *Undef, Lazy *L);
-  void resolve(SymbolBody *Body);
   std::string conflictMsg(SymbolBody *Old, SymbolBody *New);
 
   // The order the global symbols are in is not defined. We can use an arbitrary
index d4f6120..ae4fab1 100644 (file)
@@ -31,7 +31,6 @@ using namespace lld::elf;
 template <class ELFT>
 static typename ELFT::uint getSymVA(const SymbolBody &Body,
                                     typename ELFT::uint &Addend) {
-  typedef typename ELFT::Sym Elf_Sym;
   typedef typename ELFT::uint uintX_t;
 
   switch (Body.kind()) {
@@ -45,18 +44,24 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body,
     auto &D = cast<DefinedRegular<ELFT>>(Body);
     InputSectionBase<ELFT> *SC = D.Section;
 
+    // According to the ELF spec reference to a local symbol from outside
+    // the group are not allowed. Unfortunately .eh_frame breaks that rule
+    // and must be treated specially. For now we just replace the symbol with
+    // 0.
+    if (SC == &InputSection<ELFT>::Discarded)
+      return 0;
+
     // This is an absolute symbol.
     if (!SC)
-      return D.Sym.st_value;
+      return D.Value;
 
-    const Elf_Sym &Sym = D.Sym;
-    uintX_t Offset = Sym.st_value;
-    if (Sym.getType() == STT_SECTION) {
+    uintX_t Offset = D.Value;
+    if (D.isSection()) {
       Offset += Addend;
       Addend = 0;
     }
     uintX_t VA = SC->OutSec->getVA() + SC->getOffset(Offset);
-    if (Sym.getType() == STT_TLS)
+    if (D.isTls())
       return VA - Out<ELFT>::TlsPhdr->p_vaddr;
     return VA;
   }
@@ -66,7 +71,7 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body,
     auto &SS = cast<SharedSymbol<ELFT>>(Body);
     if (!SS.NeedsCopyOrPltAddr)
       return 0;
-    if (SS.IsFunc)
+    if (SS.isFunc())
       return Body.getPltVA<ELFT>();
     return Out<ELFT>::Bss->getVA() + SS.OffsetInBss;
   }
@@ -82,6 +87,13 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body,
   llvm_unreachable("invalid symbol kind");
 }
 
+SymbolBody::SymbolBody(Kind K, uint32_t NameOffset, uint8_t Other, uint8_t Type)
+    : SymbolKind(K), MustBeInDynSym(false), NeedsCopyOrPltAddr(false),
+      Type(Type), Binding(STB_LOCAL), Other(Other), NameOffset(NameOffset) {
+  IsUsedInRegularObj =
+      K != SharedKind && K != LazyKind && K != DefinedBitcodeKind;
+}
+
 // Returns true if a symbol can be replaced at load-time by a symbol
 // with the same name defined in other ELF executable or DSO.
 bool SymbolBody::isPreemptible() const {
@@ -109,7 +121,7 @@ bool SymbolBody::isPreemptible() const {
     return false;
   if (getVisibility() != STV_DEFAULT)
     return false;
-  if (Config->Bsymbolic || (Config->BsymbolicFunctions && IsFunc))
+  if (Config->Bsymbolic || (Config->BsymbolicFunctions && isFunc()))
     return false;
   return true;
 }
@@ -143,21 +155,17 @@ template <class ELFT> typename ELFT::uint SymbolBody::getThunkVA() const {
 }
 
 template <class ELFT> typename ELFT::uint SymbolBody::getSize() const {
-  if (const typename ELFT::Sym *Sym = getElfSym<ELFT>())
-    return Sym->st_size;
+  if (const auto *C = dyn_cast<DefinedCommon>(this))
+    return C->Size;
+  if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(this))
+    return DR->Size;
+  if (const auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
+    return S->Sym.st_size;
+  if (const auto *U = dyn_cast<UndefinedElf<ELFT>>(this))
+    return U->Size;
   return 0;
 }
 
-template <class ELFT> const typename ELFT::Sym *SymbolBody::getElfSym() const {
-  if (auto *S = dyn_cast<DefinedRegular<ELFT>>(this))
-    return &S->Sym;
-  if (auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
-    return &S->Sym;
-  if (auto *S = dyn_cast<UndefinedElf<ELFT>>(this))
-    return &S->Sym;
-  return nullptr;
-}
-
 static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
   if (VA == STV_DEFAULT)
     return VB;
@@ -185,8 +193,9 @@ template <class ELFT> int SymbolBody::compare(SymbolBody *Other) {
   if (L > R)
     return -Other->compare<ELFT>(this);
 
-  Visibility = Other->Visibility =
-      getMinVisibility(Visibility, Other->Visibility);
+  uint8_t V = getMinVisibility(getVisibility(), Other->getVisibility());
+  setVisibility(V);
+  Other->setVisibility(V);
 
   if (IsUsedInRegularObj || Other->IsUsedInRegularObj)
     IsUsedInRegularObj = Other->IsUsedInRegularObj = true;
@@ -212,48 +221,61 @@ template <class ELFT> int SymbolBody::compare(SymbolBody *Other) {
   return isCommon() ? -1 : 1;
 }
 
-Defined::Defined(Kind K, StringRef Name, bool IsWeak, bool IsLocal,
-                 uint8_t Visibility, uint8_t Type)
-    : SymbolBody(K, Name, IsWeak, IsLocal, Visibility, Type) {}
+Defined::Defined(Kind K, StringRef Name, uint8_t Binding, uint8_t Visibility,
+                 uint8_t Type)
+    : SymbolBody(K, Name, Binding, Visibility, Type) {}
+
+Defined::Defined(Kind K, uint32_t NameOffset, uint8_t Visibility, uint8_t Type)
+    : SymbolBody(K, NameOffset, Visibility, Type) {}
 
 DefinedBitcode::DefinedBitcode(StringRef Name, bool IsWeak, uint8_t Visibility)
-    : Defined(DefinedBitcodeKind, Name, IsWeak, false, Visibility,
-              0 /* Type */) {}
+    : Defined(DefinedBitcodeKind, Name, IsWeak ? STB_WEAK : STB_GLOBAL,
+              Visibility, 0 /* Type */) {}
 
 bool DefinedBitcode::classof(const SymbolBody *S) {
   return S->kind() == DefinedBitcodeKind;
 }
 
-Undefined::Undefined(SymbolBody::Kind K, StringRef N, bool IsWeak,
+Undefined::Undefined(SymbolBody::Kind K, StringRef N, uint8_t Binding,
+                     uint8_t Other, uint8_t Type)
+    : SymbolBody(K, N, Binding, Other, Type), CanKeepUndefined(false) {}
+
+Undefined::Undefined(SymbolBody::Kind K, uint32_t NameOffset,
                      uint8_t Visibility, uint8_t Type)
-    : SymbolBody(K, N, IsWeak, false, Visibility, Type),
-      CanKeepUndefined(false) {}
+    : SymbolBody(K, NameOffset, Visibility, Type), CanKeepUndefined(false) {}
 
 Undefined::Undefined(StringRef N, bool IsWeak, uint8_t Visibility,
                      bool CanKeepUndefined)
-    : Undefined(SymbolBody::UndefinedKind, N, IsWeak, Visibility, 0 /* Type */) {
+    : Undefined(SymbolBody::UndefinedKind, N, IsWeak ? STB_WEAK : STB_GLOBAL,
+                Visibility, 0 /* Type */) {
   this->CanKeepUndefined = CanKeepUndefined;
 }
 
 template <typename ELFT>
 UndefinedElf<ELFT>::UndefinedElf(StringRef N, const Elf_Sym &Sym)
-    : Undefined(SymbolBody::UndefinedElfKind, N,
-                Sym.getBinding() == llvm::ELF::STB_WEAK, Sym.getVisibility(),
+    : Undefined(SymbolBody::UndefinedElfKind, N, Sym.getBinding(), Sym.st_other,
                 Sym.getType()),
-      Sym(Sym) {}
+      Size(Sym.st_size) {}
+
+template <typename ELFT>
+UndefinedElf<ELFT>::UndefinedElf(uint32_t NameOffset, const Elf_Sym &Sym)
+    : Undefined(SymbolBody::UndefinedElfKind, NameOffset, Sym.st_other,
+                Sym.getType()),
+      Size(Sym.st_size) {
+  assert(Sym.getBinding() == STB_LOCAL);
+}
 
 template <typename ELFT>
 DefinedSynthetic<ELFT>::DefinedSynthetic(StringRef N, uintX_t Value,
                                          OutputSectionBase<ELFT> &Section,
                                          uint8_t Visibility)
-    : Defined(SymbolBody::DefinedSyntheticKind, N, false, false, Visibility,
+    : Defined(SymbolBody::DefinedSyntheticKind, N, STB_GLOBAL, Visibility,
               0 /* Type */),
       Value(Value), Section(Section) {}
 
 DefinedCommon::DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment,
-                             bool IsWeak, uint8_t Visibility)
-    : Defined(SymbolBody::DefinedCommonKind, N, IsWeak, false, Visibility,
-              0 /* Type */),
+                             uint8_t Binding, uint8_t Visibility, uint8_t Type)
+    : Defined(SymbolBody::DefinedCommonKind, N, Binding, Visibility, Type),
       Alignment(Alignment), Size(Size) {}
 
 std::unique_ptr<InputFile> Lazy::getMember() {
@@ -317,11 +339,6 @@ template uint32_t SymbolBody::template getSize<ELF32BE>() const;
 template uint64_t SymbolBody::template getSize<ELF64LE>() const;
 template uint64_t SymbolBody::template getSize<ELF64BE>() const;
 
-template const ELF32LE::Sym *SymbolBody::template getElfSym<ELF32LE>() const;
-template const ELF32BE::Sym *SymbolBody::template getElfSym<ELF32BE>() const;
-template const ELF64LE::Sym *SymbolBody::template getElfSym<ELF64LE>() const;
-template const ELF64BE::Sym *SymbolBody::template getElfSym<ELF64BE>() const;
-
 template uint32_t SymbolBody::template getThunkVA<ELF32LE>() const;
 template uint32_t SymbolBody::template getThunkVA<ELF32BE>() const;
 template uint64_t SymbolBody::template getThunkVA<ELF64LE>() const;
index 9e81995..d3e6e5a 100644 (file)
@@ -62,7 +62,7 @@ public:
 
   Kind kind() const { return static_cast<Kind>(SymbolKind); }
 
-  bool isWeak() const { return IsWeak; }
+  bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; }
   bool isUndefined() const {
     return SymbolKind == UndefinedKind || SymbolKind == UndefinedElfKind;
   }
@@ -70,14 +70,21 @@ public:
   bool isCommon() const { return SymbolKind == DefinedCommonKind; }
   bool isLazy() const { return SymbolKind == LazyKind; }
   bool isShared() const { return SymbolKind == SharedKind; }
-  bool isLocal() const { return IsLocal; }
+  bool isLocal() const { return Binding == llvm::ELF::STB_LOCAL; }
   bool isUsedInRegularObj() const { return IsUsedInRegularObj; }
   bool isPreemptible() const;
 
   // Returns the symbol name.
-  StringRef getName() const { return Name; }
+  StringRef getName() const {
+    assert(!isLocal());
+    return Name;
+  }
+  uint32_t getNameOffset() const {
+    assert(isLocal());
+    return NameOffset;
+  }
 
-  uint8_t getVisibility() const { return Visibility; }
+  uint8_t getVisibility() const { return Other & 0x3; }
 
   unsigned DynsymIndex = 0;
   uint32_t GlobalDynIndex = -1;
@@ -100,7 +107,6 @@ public:
   template <class ELFT> typename ELFT::uint getPltVA() const;
   template <class ELFT> typename ELFT::uint getThunkVA() const;
   template <class ELFT> typename ELFT::uint getSize() const;
-  template <class ELFT> const typename ELFT::Sym *getElfSym() const;
 
   // A SymbolBody has a backreference to a Symbol. Originally they are
   // doubly-linked. A backreference will never change. But the pointer
@@ -118,21 +124,18 @@ public:
   template <class ELFT> int compare(SymbolBody *Other);
 
 protected:
-  SymbolBody(Kind K, StringRef Name, bool IsWeak, bool IsLocal,
-             uint8_t Visibility, uint8_t Type)
-      : SymbolKind(K), IsWeak(IsWeak), IsLocal(IsLocal), Visibility(Visibility),
-        MustBeInDynSym(false), NeedsCopyOrPltAddr(false), Name(Name) {
-    IsFunc = Type == llvm::ELF::STT_FUNC;
-    IsTls = Type == llvm::ELF::STT_TLS;
-    IsGnuIFunc = Type == llvm::ELF::STT_GNU_IFUNC;
+  SymbolBody(Kind K, StringRef Name, uint8_t Binding, uint8_t Other,
+             uint8_t Type)
+      : SymbolKind(K), MustBeInDynSym(false), NeedsCopyOrPltAddr(false),
+        Type(Type), Binding(Binding), Other(Other), Name(Name) {
+    assert(!isLocal());
     IsUsedInRegularObj =
         K != SharedKind && K != LazyKind && K != DefinedBitcodeKind;
   }
 
+  SymbolBody(Kind K, uint32_t NameOffset, uint8_t Other, uint8_t Type);
+
   const unsigned SymbolKind : 8;
-  unsigned IsWeak : 1;
-  unsigned IsLocal : 1;
-  unsigned Visibility : 2;
 
   // True if the symbol was used for linking and thus need to be
   // added to the output file's symbol table. It is usually true,
@@ -148,34 +151,44 @@ public:
   // symbol or if the symbol should point to its plt entry.
   unsigned NeedsCopyOrPltAddr : 1;
 
-  unsigned IsTls : 1;
-  unsigned IsFunc : 1;
-  unsigned IsGnuIFunc : 1;
+  uint8_t Type;
+  uint8_t Binding;
+  uint8_t Other;
+  bool isSection() const { return Type == llvm::ELF::STT_SECTION; }
+  bool isTls() const { return Type == llvm::ELF::STT_TLS; }
+  bool isFunc() const { return Type == llvm::ELF::STT_FUNC; }
+  bool isGnuIFunc() const { return Type == llvm::ELF::STT_GNU_IFUNC; }
+  bool isObject() const { return Type == llvm::ELF::STT_OBJECT; }
+  bool isFile() const { return Type == llvm::ELF::STT_FILE; }
+  void setVisibility(uint8_t V) { Other = (Other & ~0x3) | V; }
 
 protected:
-  StringRef Name;
+  union {
+    StringRef Name;
+    uint32_t NameOffset;
+  };
   Symbol *Backref = nullptr;
 };
 
 // The base class for any defined symbols.
 class Defined : public SymbolBody {
 public:
-  Defined(Kind K, StringRef Name, bool IsWeak, bool IsLocal, uint8_t Visibility,
-          uint8_t Type);
+  Defined(Kind K, StringRef Name, uint8_t Binding, uint8_t Other, uint8_t Type);
+  Defined(Kind K, uint32_t NameOffset, uint8_t Other, uint8_t Type);
   static bool classof(const SymbolBody *S) { return S->isDefined(); }
 };
 
 // The defined symbol in LLVM bitcode files.
 class DefinedBitcode : public Defined {
 public:
-  DefinedBitcode(StringRef Name, bool IsWeak, uint8_t Visibility);
+  DefinedBitcode(StringRef Name, bool IsWeak, uint8_t Other);
   static bool classof(const SymbolBody *S);
 };
 
 class DefinedCommon : public Defined {
 public:
-  DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, bool IsWeak,
-                uint8_t Visibility);
+  DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, uint8_t Binding,
+                uint8_t Other, uint8_t Type);
 
   static bool classof(const SymbolBody *S) {
     return S->kind() == SymbolBody::DefinedCommonKind;
@@ -194,21 +207,36 @@ public:
 // Regular defined symbols read from object file symbol tables.
 template <class ELFT> class DefinedRegular : public Defined {
   typedef typename ELFT::Sym Elf_Sym;
+  typedef typename ELFT::uint uintX_t;
 
 public:
   DefinedRegular(StringRef Name, const Elf_Sym &Sym,
                  InputSectionBase<ELFT> *Section)
-      : Defined(SymbolBody::DefinedRegularKind, Name,
-                Sym.getBinding() == llvm::ELF::STB_WEAK,
-                Sym.getBinding() == llvm::ELF::STB_LOCAL,
-                Sym.getVisibility(), Sym.getType()),
-        Sym(Sym), Section(Section ? Section->Repl : NullInputSection) {}
+      : Defined(SymbolBody::DefinedRegularKind, Name, Sym.getBinding(),
+                Sym.st_other, Sym.getType()),
+        Value(Sym.st_value), Size(Sym.st_size),
+        Section(Section ? Section->Repl : NullInputSection) {}
+
+  DefinedRegular(uint32_t NameOffset, const Elf_Sym &Sym,
+                 InputSectionBase<ELFT> *Section)
+      : Defined(SymbolBody::DefinedRegularKind, NameOffset, Sym.st_other,
+                Sym.getType()),
+        Value(Sym.st_value), Size(Sym.st_size),
+        Section(Section ? Section->Repl : NullInputSection) {
+    assert(isLocal());
+  }
+
+  DefinedRegular(StringRef Name, uint8_t Binding, uint8_t Other)
+      : Defined(SymbolBody::DefinedRegularKind, Name, Binding, Other,
+                llvm::ELF::STT_NOTYPE),
+        Value(0), Size(0), Section(NullInputSection) {}
 
   static bool classof(const SymbolBody *S) {
     return S->kind() == SymbolBody::DefinedRegularKind;
   }
 
-  const Elf_Sym &Sym;
+  uintX_t Value;
+  uintX_t Size;
 
   // The input section this symbol belongs to. Notice that this is
   // a reference to a pointer. We are using two levels of indirections
@@ -231,10 +259,9 @@ InputSectionBase<ELFT> *DefinedRegular<ELFT>::NullInputSection;
 // takes an output section to calculate output VA, etc.
 template <class ELFT> class DefinedSynthetic : public Defined {
 public:
-  typedef typename ELFT::Sym Elf_Sym;
   typedef typename ELFT::uint uintX_t;
   DefinedSynthetic(StringRef N, uintX_t Value, OutputSectionBase<ELFT> &Section,
-                   uint8_t Visibility);
+                   uint8_t Other);
 
   static bool classof(const SymbolBody *S) {
     return S->kind() == SymbolBody::DefinedSyntheticKind;
@@ -254,11 +281,11 @@ class Undefined : public SymbolBody {
   bool CanKeepUndefined;
 
 protected:
-  Undefined(Kind K, StringRef N, bool IsWeak, uint8_t Visibility, uint8_t Type);
+  Undefined(Kind K, StringRef N, uint8_t Binding, uint8_t Other, uint8_t Type);
+  Undefined(Kind K, uint32_t NameOffset, uint8_t Other, uint8_t Type);
 
 public:
-  Undefined(StringRef N, bool IsWeak, uint8_t Visibility,
-            bool CanKeepUndefined);
+  Undefined(StringRef N, bool IsWeak, uint8_t Other, bool CanKeepUndefined);
 
   static bool classof(const SymbolBody *S) { return S->isUndefined(); }
 
@@ -266,11 +293,14 @@ public:
 };
 
 template <class ELFT> class UndefinedElf : public Undefined {
+  typedef typename ELFT::uint uintX_t;
   typedef typename ELFT::Sym Elf_Sym;
 
 public:
   UndefinedElf(StringRef N, const Elf_Sym &Sym);
-  const Elf_Sym &Sym;
+  UndefinedElf(uint32_t NameOffset, const Elf_Sym &Sym);
+
+  uintX_t Size;
 
   static bool classof(const SymbolBody *S) {
     return S->kind() == SymbolBody::UndefinedElfKind;
@@ -287,10 +317,8 @@ public:
   }
 
   SharedSymbol(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym)
-      : Defined(SymbolBody::SharedKind, Name,
-                Sym.getBinding() == llvm::ELF::STB_WEAK,
-                Sym.getBinding() == llvm::ELF::STB_LOCAL,
-                Sym.getVisibility(), Sym.getType()),
+      : Defined(SymbolBody::SharedKind, Name, Sym.getBinding(), Sym.st_other,
+                Sym.getType()),
         File(F), Sym(Sym) {}
 
   SharedFile<ELFT> *File;
@@ -299,7 +327,7 @@ public:
   // OffsetInBss is significant only when needsCopy() is true.
   uintX_t OffsetInBss = 0;
 
-  bool needsCopy() const { return this->NeedsCopyOrPltAddr && !this->IsFunc; }
+  bool needsCopy() const { return this->NeedsCopyOrPltAddr && !this->isFunc(); }
 };
 
 // This class represents a symbol defined in an archive file. It is
@@ -310,8 +338,8 @@ public:
 class Lazy : public SymbolBody {
 public:
   Lazy(ArchiveFile *F, const llvm::object::Archive::Symbol S)
-      : SymbolBody(LazyKind, S.getName(), false, false, llvm::ELF::STV_DEFAULT,
-                   /* Type */ 0),
+      : SymbolBody(LazyKind, S.getName(), llvm::ELF::STB_GLOBAL,
+                   llvm::ELF::STV_DEFAULT, /* Type */ 0),
         File(F), Sym(S) {}
 
   static bool classof(const SymbolBody *S) { return S->kind() == LazyKind; }
@@ -320,48 +348,44 @@ public:
   // was already returned.
   std::unique_ptr<InputFile> getMember();
 
-  void setWeak() { IsWeak = true; }
-
 private:
   ArchiveFile *File;
   const llvm::object::Archive::Symbol Sym;
 };
 
 // Some linker-generated symbols need to be created as
-// DefinedRegular symbols, so they need Elf_Sym symbols.
-// Here we allocate such Elf_Sym symbols statically.
+// DefinedRegular symbols.
 template <class ELFT> struct ElfSym {
-  typedef typename ELFT::Sym Elf_Sym;
-
-  // Used to represent an undefined symbol which we don't want to add to the
-  // output file's symbol table. It has weak binding and can be substituted.
-  static Elf_Sym Ignored;
-
   // The content for _etext and etext symbols.
-  static Elf_Sym Etext;
+  static DefinedRegular<ELFT> *Etext;
+  static DefinedRegular<ELFT> *Etext2;
 
   // The content for _edata and edata symbols.
-  static Elf_Sym Edata;
+  static DefinedRegular<ELFT> *Edata;
+  static DefinedRegular<ELFT> *Edata2;
 
   // The content for _end and end symbols.
-  static Elf_Sym End;
+  static DefinedRegular<ELFT> *End;
+  static DefinedRegular<ELFT> *End2;
 
   // The content for _gp symbol for MIPS target.
-  static Elf_Sym MipsGp;
+  static DefinedRegular<ELFT> *MipsGp;
 
   // __rel_iplt_start/__rel_iplt_end for signaling
   // where R_[*]_IRELATIVE relocations do live.
-  static Elf_Sym RelaIpltStart;
-  static Elf_Sym RelaIpltEnd;
+  static DefinedRegular<ELFT> *RelaIpltStart;
+  static DefinedRegular<ELFT> *RelaIpltEnd;
 };
 
-template <class ELFT> typename ELFT::Sym ElfSym<ELFT>::Ignored;
-template <class ELFT> typename ELFT::Sym ElfSym<ELFT>::Etext;
-template <class ELFT> typename ELFT::Sym ElfSym<ELFT>::Edata;
-template <class ELFT> typename ELFT::Sym ElfSym<ELFT>::End;
-template <class ELFT> typename ELFT::Sym ElfSym<ELFT>::MipsGp;
-template <class ELFT> typename ELFT::Sym ElfSym<ELFT>::RelaIpltStart;
-template <class ELFT> typename ELFT::Sym ElfSym<ELFT>::RelaIpltEnd;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Etext;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Etext2;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Edata;
+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> DefinedRegular<ELFT> *ElfSym<ELFT>::MipsGp;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::RelaIpltStart;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::RelaIpltEnd;
 
 } // namespace elf
 } // namespace lld
index 2fe4579..671d9b7 100644 (file)
@@ -248,7 +248,7 @@ uint64_t TargetInfo::getImplicitAddend(const uint8_t *Buf,
 }
 
 bool TargetInfo::canRelaxTls(uint32_t Type, const SymbolBody *S) const {
-  if (Config->Shared || (S && !S->IsTls))
+  if (Config->Shared || (S && !S->isTls()))
     return false;
 
   // We know we are producing an executable.
@@ -280,7 +280,7 @@ template <typename ELFT> static bool mayNeedCopy(const SymbolBody &S) {
   auto *SS = dyn_cast<SharedSymbol<ELFT>>(&S);
   if (!SS)
     return false;
-  return SS->Sym.getType() == STT_OBJECT;
+  return SS->isObject();
 }
 
 template <class ELFT>
@@ -303,7 +303,7 @@ bool TargetInfo::refersToGotEntry(uint32_t Type) const { return false; }
 
 TargetInfo::PltNeed TargetInfo::needsPlt(uint32_t Type,
                                          const SymbolBody &S) const {
-  if (S.IsGnuIFunc)
+  if (S.isGnuIFunc())
     return Plt_Explicit;
   if (S.isPreemptible() && needsPltImpl(Type))
     return Plt_Explicit;
@@ -330,7 +330,7 @@ TargetInfo::PltNeed TargetInfo::needsPlt(uint32_t Type,
   // plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT,
   // R_386_JMP_SLOT, etc).
   if (S.isShared())
-    if (!Config->Pic && S.IsFunc && !refersToGotEntry(Type))
+    if (!Config->Pic && S.isFunc() && !refersToGotEntry(Type))
       return Plt_Implicit;
 
   return Plt_No;
@@ -500,7 +500,7 @@ bool X86TargetInfo::needsCopyRelImpl(uint32_t Type) const {
 }
 
 bool X86TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const {
-  if (S.IsTls && Type == R_386_TLS_GD)
+  if (S.isTls() && Type == R_386_TLS_GD)
     return Target->canRelaxTls(Type, &S) && S.isPreemptible();
   if (Type == R_386_TLS_GOTIE || Type == R_386_TLS_IE)
     return !canRelaxTls(Type, &S);
@@ -1762,7 +1762,7 @@ bool MipsTargetInfo<ELFT>::needsThunk(uint32_t Type, const InputFile &File,
   // LA25 is required if target file has PIC code
   // or target symbol is a PIC symbol.
   return (D->Section->getFile()->getObj().getHeader()->e_flags & EF_MIPS_PIC) ||
-         (D->Sym.st_other & STO_MIPS_MIPS16) == STO_MIPS_PIC;
+         (D->Other & STO_MIPS_MIPS16) == STO_MIPS_PIC;
 }
 
 template <class ELFT>
index 47e7a1b..1d8fdcf 100644 (file)
@@ -287,7 +287,7 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
     return 1;
   }
 
-  if (!Body.IsTls)
+  if (!Body.isTls())
     return 0;
 
   if (Target->isTlsGlobalDynamicRel(Type)) {
@@ -403,7 +403,7 @@ void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &C,
       Out<ELFT>::Plt->addEntry(Body);
 
       uint32_t Rel;
-      if (Body.IsGnuIFunc)
+      if (Body.isGnuIFunc())
         Rel = Preemptible ? Target->PltRel : Target->IRelativeRel;
       else
         Rel = Target->UseLazyBinding ? Target->PltRel : Target->GotRel;
@@ -440,7 +440,7 @@ void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &C,
                     !Target->isSizeRel(Type);
       if (Preemptible || Dynrel) {
         uint32_t DynType;
-        if (Body.IsTls)
+        if (Body.isTls())
           DynType = Target->TlsGotRel;
         else if (Preemptible)
           DynType = Target->GotRel;
@@ -525,23 +525,17 @@ static void reportUndefined(SymbolTable<ELFT> &Symtab, SymbolBody *Sym) {
 }
 
 template <class ELFT>
-static bool shouldKeepInSymtab(const elf::ObjectFile<ELFT> &File,
-                               StringRef SymName,
-                               const typename ELFT::Sym &Sym) {
-  if (Sym.getType() == STT_FILE)
+static bool shouldKeepInSymtab(InputSectionBase<ELFT> *Sec, StringRef SymName,
+                               const SymbolBody &B) {
+  if (B.isFile())
     return false;
 
   // We keep sections in symtab for relocatable output.
-  if (Sym.getType() == STT_SECTION)
+  if (B.isSection())
     return Config->Relocatable;
 
-  // No reason to keep local undefined symbol in symtab.
-  if (Sym.st_shndx == SHN_UNDEF)
-    return false;
-
-  InputSectionBase<ELFT> *Sec = File.getSection(Sym);
   // If sym references a section in a discarded group, don't keep it.
-  if (Sec == InputSection<ELFT>::Discarded)
+  if (Sec == &InputSection<ELFT>::Discarded)
     return false;
 
   if (Config->DiscardNone)
@@ -568,18 +562,23 @@ template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
     return;
   for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F :
        Symtab.getObjectFiles()) {
+    const char *StrTab = F->getStringTable().data();
     for (SymbolBody *B : F->getLocalSymbols()) {
-      const Elf_Sym &Sym = cast<DefinedRegular<ELFT>>(B)->Sym;
-      StringRef SymName = check(Sym.getName(F->getStringTable()));
-      if (!shouldKeepInSymtab<ELFT>(*F, SymName, Sym))
+      auto *DR = dyn_cast<DefinedRegular<ELFT>>(B);
+      // No reason to keep local undefined symbol in symtab.
+      if (!DR)
+        continue;
+      StringRef SymName(StrTab + B->getNameOffset());
+      InputSectionBase<ELFT> *Sec = DR->Section;
+      if (!shouldKeepInSymtab<ELFT>(Sec, SymName, *B))
         continue;
-      if (Sym.st_shndx != SHN_ABS && !F->getSection(Sym)->Live)
+      if (Sec && !Sec->Live)
         continue;
       ++Out<ELFT>::SymTab->NumLocals;
       if (Config->Relocatable)
         B->DynsymIndex = Out<ELFT>::SymTab->NumLocals;
-      F->KeptLocalSyms.push_back(std::make_pair(
-          &Sym, Out<ELFT>::SymTab->StrTabSec.addString(SymName)));
+      F->KeptLocalSyms.push_back(
+          std::make_pair(DR, Out<ELFT>::SymTab->StrTabSec.addString(SymName)));
     }
   }
 }
@@ -754,7 +753,7 @@ void Writer<ELFT>::addCopyRelSymbols(std::vector<SharedSymbol<ELFT> *> &Syms) {
     uintX_t Align = getAlignment(SS);
     Off = alignTo(Off, Align);
     SS->OffsetInBss = Off;
-    Off += SS->Sym.st_size;
+    Off += SS->template getSize<ELFT>();
     MaxAlign = std::max(MaxAlign, Align);
   }
   Out<ELFT>::Bss->setSize(Off);
@@ -787,7 +786,7 @@ void reportDiscarded(InputSectionBase<ELFT> *IS,
 
 template <class ELFT>
 bool Writer<ELFT>::isDiscarded(InputSectionBase<ELFT> *S) const {
-  return !S || S == InputSection<ELFT>::Discarded || !S->Live ||
+  return !S || S == &InputSection<ELFT>::Discarded || !S->Live ||
          Script->isDiscarded(S);
 }
 
@@ -802,12 +801,10 @@ void Writer<ELFT>::addRelIpltSymbols() {
   if (isOutputDynamic() || !Out<ELFT>::RelaPlt)
     return;
   StringRef S = Config->Rela ? "__rela_iplt_start" : "__rel_iplt_start";
-  if (Symtab.find(S))
-    Symtab.addAbsolute(S, ElfSym<ELFT>::RelaIpltStart);
+  ElfSym<ELFT>::RelaIpltStart = Symtab.addIgnored(S);
 
   S = Config->Rela ? "__rela_iplt_end" : "__rel_iplt_end";
-  if (Symtab.find(S))
-    Symtab.addAbsolute(S, ElfSym<ELFT>::RelaIpltEnd);
+  ElfSym<ELFT>::RelaIpltEnd = Symtab.addIgnored(S);
 }
 
 template <class ELFT> static bool includeInSymtab(const SymbolBody &B) {
@@ -815,9 +812,6 @@ template <class ELFT> static bool includeInSymtab(const SymbolBody &B) {
     return false;
 
   if (auto *D = dyn_cast<DefinedRegular<ELFT>>(&B)) {
-    // Don't include synthetic symbols like __init_array_start in every output.
-    if (&D->Sym == &ElfSym<ELFT>::Ignored)
-      return false;
     // Exclude symbols pointing to garbage-collected sections.
     if (D->Section && !D->Section->Live)
       return false;
@@ -922,6 +916,32 @@ OutputSectionFactory<ELFT>::createKey(InputSectionBase<ELFT> *C,
 // The linker is expected to define some symbols depending on
 // the linking result. This function defines such symbols.
 template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
+  if (Config->EMachine == EM_MIPS) {
+    // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between
+    // start of function and 'gp' pointer into GOT.
+    Config->MipsGpDisp = Symtab.addIgnored("_gp_disp");
+    // 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
+    Config->MipsLocalGp = Symtab.addIgnored("__gnu_local_gp");
+  }
+
+  // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol
+  // is magical and is used to produce a R_386_GOTPC relocation.
+  // The R_386_GOTPC relocation value doesn't actually depend on the
+  // symbol value, so it could use an index of STN_UNDEF which, according
+  // to the spec, means the symbol value is 0.
+  // Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in
+  // the object file.
+  // The situation is even stranger on x86_64 where the assembly doesn't
+  // need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as
+  // an undefined symbol in the .o files.
+  // Given that the symbol is effectively unused, we just create a dummy
+  // hidden one to avoid the undefined symbol error.
+  if (!Config->Relocatable)
+    Symtab.addIgnored("_GLOBAL_OFFSET_TABLE_");
+
   // __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For
   // static linking the linker is required to optimize away any references to
   // __tls_get_addr, so it's not defined anywhere. Create a hidden definition
@@ -929,9 +949,9 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
   if (!isOutputDynamic())
     Symtab.addIgnored("__tls_get_addr");
 
-  auto Define = [this](StringRef S, Elf_Sym &Sym) {
-    if (Symtab.find(S))
-      Symtab.addAbsolute(S, Sym);
+  auto Define = [this](StringRef S, DefinedRegular<ELFT> *&Sym,
+                       DefinedRegular<ELFT> *&Sym2) {
+    Sym = Symtab.addIgnored(S, STV_DEFAULT);
 
     // The name without the underscore is not a reserved name,
     // so it is defined only when there is a reference against it.
@@ -939,12 +959,12 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
     S = S.substr(1);
     if (SymbolBody *B = Symtab.find(S))
       if (B->isUndefined())
-        Symtab.addAbsolute(S, Sym);
+        Sym2 = Symtab.addAbsolute(S, STV_DEFAULT);
   };
 
-  Define("_end", ElfSym<ELFT>::End);
-  Define("_etext", ElfSym<ELFT>::Etext);
-  Define("_edata", ElfSym<ELFT>::Edata);
+  Define("_end", ElfSym<ELFT>::End, ElfSym<ELFT>::End2);
+  Define("_etext", ElfSym<ELFT>::Etext, ElfSym<ELFT>::Etext2);
+  Define("_edata", ElfSym<ELFT>::Edata, ElfSym<ELFT>::Edata2);
 }
 
 // Sort input sections by section name suffixes for
@@ -1467,13 +1487,15 @@ template <class ELFT> void Writer<ELFT>::fixAbsoluteSymbols() {
   // to beginning or ending of .rela.plt section, respectively.
   if (Out<ELFT>::RelaPlt) {
     uintX_t Start = Out<ELFT>::RelaPlt->getVA();
-    ElfSym<ELFT>::RelaIpltStart.st_value = Start;
-    ElfSym<ELFT>::RelaIpltEnd.st_value = Start + Out<ELFT>::RelaPlt->getSize();
+    if (ElfSym<ELFT>::RelaIpltStart)
+      ElfSym<ELFT>::RelaIpltStart->Value = Start;
+    if (ElfSym<ELFT>::RelaIpltEnd)
+      ElfSym<ELFT>::RelaIpltEnd->Value = Start + Out<ELFT>::RelaPlt->getSize();
   }
 
   // Update MIPS _gp absolute symbol so that it points to the static data.
   if (Config->EMachine == EM_MIPS)
-    ElfSym<ELFT>::MipsGp.st_value = getMipsGpAddr<ELFT>();
+    ElfSym<ELFT>::MipsGp->Value = getMipsGpAddr<ELFT>();
 
   // _etext is the first location after the last read-only loadable segment.
   // _edata is the first location after the last read-write loadable segment.
@@ -1482,12 +1504,24 @@ template <class ELFT> void Writer<ELFT>::fixAbsoluteSymbols() {
     Elf_Phdr &H = P.H;
     if (H.p_type != PT_LOAD)
       continue;
-    ElfSym<ELFT>::End.st_value = H.p_vaddr + H.p_memsz;
-    uintX_t Val = H.p_vaddr + H.p_filesz;
-    if (H.p_flags & PF_W)
-      ElfSym<ELFT>::Edata.st_value = Val;
-    else
-      ElfSym<ELFT>::Etext.st_value = Val;
+    uintX_t Val = H.p_vaddr + H.p_memsz;
+    if (ElfSym<ELFT>::End)
+      ElfSym<ELFT>::End->Value = Val;
+    if (ElfSym<ELFT>::End2)
+      ElfSym<ELFT>::End2->Value = Val;
+
+    Val = H.p_vaddr + H.p_filesz;
+    if (H.p_flags & PF_W) {
+      if (ElfSym<ELFT>::Edata)
+        ElfSym<ELFT>::Edata->Value = Val;
+      if (ElfSym<ELFT>::Edata2)
+        ElfSym<ELFT>::Edata2->Value = Val;
+    } else {
+      if (ElfSym<ELFT>::Etext)
+        ElfSym<ELFT>::Etext->Value = Val;
+      if (ElfSym<ELFT>::Etext2)
+        ElfSym<ELFT>::Etext2->Value = Val;
+    }
   }
 }
 
index 4cc9420..32e9636 100644 (file)
@@ -51,7 +51,9 @@
 // CHECK-NEXT:    Size: 0
 // CHECK-NEXT:    Binding: Local
 // CHECK-NEXT:    Type: None
-// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Other [
+// CHECK-NEXT:      STV_HIDDEN
+// CHECK-NEXT:    ]
 // CHECK-NEXT:    Section: Absolute
 // CHECK-NEXT:  }
 // CHECK-NEXT:  Symbol {
@@ -60,7 +62,9 @@
 // CHECK-NEXT:    Size: 0
 // CHECK-NEXT:    Binding: Local
 // CHECK-NEXT:    Type: None
-// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Other [
+// CHECK-NEXT:      STV_HIDDEN
+// CHECK-NEXT:    ]
 // CHECK-NEXT:    Section: Absolute
 // CHECK-NEXT:  }
 // CHECK-NEXT:  Symbol {
index 75c44ef..aaa0318 100644 (file)
@@ -187,22 +187,22 @@ __start:
 # CHECK-NEXT:     Section: Undefined (0x0)
 # CHECK-NEXT:   }
 # CHECK-NEXT:   Symbol {
-# CHECK-NEXT:     Name: _gp
-# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Name: __start
+# CHECK-NEXT:     Value: 0x20000
 # CHECK-NEXT:     Size: 0
-# CHECK-NEXT:     Binding: Local (0x0)
+# CHECK-NEXT:     Binding: Global (0x1)
 # CHECK-NEXT:     Type: None (0x0)
 # CHECK-NEXT:     Other: 0
-# CHECK-NEXT:     Section: Absolute (0xFFF1)
+# CHECK-NEXT:     Section: .text
 # CHECK-NEXT:   }
 # CHECK-NEXT:   Symbol {
-# CHECK-NEXT:     Name: __start
-# CHECK-NEXT:     Value: 0x20000
+# CHECK-NEXT:     Name: _gp
+# CHECK-NEXT:     Value: 0x0
 # CHECK-NEXT:     Size: 0
-# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Binding: Global
 # CHECK-NEXT:     Type: None (0x0)
 # CHECK-NEXT:     Other: 0
-# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:     Section: Absolute (0xFFF1)
 # CHECK-NEXT:   }
 # CHECK-NEXT: ]
 # CHECK-NEXT: ProgramHeaders [
index b70f98c..7935925 100644 (file)
@@ -3,4 +3,7 @@
 // RUN: llvm-readobj -t %t2 | FileCheck %s
 .long _GLOBAL_OFFSET_TABLE_
 
-// CHECK-NOT: Name: _GLOBAL_OFFSET_TABLE_
+// CHECK:      Name: _GLOBAL_OFFSET_TABLE_
+// CHECK-NEXT: Value:
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Local
index 6dcdf25..925ed22 100644 (file)
@@ -43,7 +43,9 @@
 // CHECK-NEXT:   Size: 0
 // CHECK-NEXT:   Binding: Local
 // CHECK-NEXT:   Type: None
-// CHECK-NEXT:   Other: 0
+// CHECK-NEXT:   Other [
+// CHECK-NEXT:     STV_HIDDEN
+// CHECK-NEXT:   ]
 // CHECK-NEXT:   Section: Absolute
 // CHECK-NEXT: }
 // CHECK-NEXT: Symbol {
@@ -52,7 +54,9 @@
 // CHECK-NEXT:   Size: 0
 // CHECK-NEXT:   Binding: Local
 // CHECK-NEXT:   Type: None
-// CHECK-NEXT:   Other: 0
+// CHECK-NEXT:   Other [
+// CHECK-NEXT:     STV_HIDDEN
+// CHECK-NEXT:   ]
 // CHECK-NEXT:   Section: Absolute
 // CHECK-NEXT: }
 // CHECK-NEXT: Symbol {
index b04f275..38e3727 100644 (file)
@@ -42,7 +42,9 @@
 // CHECK-NEXT:    Size: 0
 // CHECK-NEXT:    Binding: Local
 // CHECK-NEXT:    Type: None
-// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Other [
+// CHECK-NEXT:      STV_HIDDEN
+// CHECK-NEXT:    ]
 // CHECK-NEXT:    Section: Absolute
 // CHECK-NEXT:  }
 // CHECK-NEXT:  Symbol {
@@ -51,7 +53,9 @@
 // CHECK-NEXT:    Size: 0
 // CHECK-NEXT:    Binding: Local
 // CHECK-NEXT:    Type: None
-// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Other [
+// CHECK-NEXT:      STV_HIDDEN
+// CHECK-NEXT:    ]
 // CHECK-NEXT:    Section: Absolute
 // CHECK-NEXT:  }
 // CHECK-NEXT:  Symbol {
index a08829c..adc84c1 100644 (file)
 
 # REQUIRES: mips
 
-# INT-SO-NOT:  Name: _gp_disp
+# INT-SO:      Name: _gp_disp
+# INT-SO-NEXT: Value:
+# INT-SO-NEXT: Size:
+# INT-SO-NEXT: Binding: Local
 
 # EXT-SO:      Name: _gp_disp
 # EXT-SO-NEXT: Value: 0x20010
index e2e9ae7..ba05a5d 100644 (file)
@@ -25,8 +25,8 @@ __start:
 #                                                  ^-- %lo(0x37ff0-0x20004+4)
 
 # EXE: SYMBOL TABLE:
-# EXE: 00037ff0     *ABS*   00000000 _gp
 # EXE: 00020000     .text   00000000 __start
+# EXE: 00037ff0     *ABS*   00000000 _gp
 # EXE: 00020010     .text   00000000 _foo
 
 # SO:      Disassembly of section .text: