[lld] r249881 - Add support for comdats.

Rafael Espindola via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 9 12:25:07 PDT 2015


Author: rafael
Date: Fri Oct  9 14:25:07 2015
New Revision: 249881

URL: http://llvm.org/viewvc/llvm-project?rev=249881&view=rev
Log:
Add support for comdats.

The implementation is a direct translation to c++ of the rules in the ELF spec.

Added:
    lld/trunk/test/elf2/Inputs/comdat.s
    lld/trunk/test/elf2/comdat.s
Modified:
    lld/trunk/ELF/InputFiles.cpp
    lld/trunk/ELF/InputFiles.h
    lld/trunk/ELF/InputSection.h
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/OutputSections.h
    lld/trunk/ELF/SymbolTable.cpp
    lld/trunk/ELF/SymbolTable.h
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.cpp?rev=249881&r1=249880&r2=249881&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.cpp (original)
+++ lld/trunk/ELF/InputFiles.cpp Fri Oct  9 14:25:07 2015
@@ -95,19 +95,65 @@ typename ObjectFile<ELFT>::Elf_Sym_Range
   return this->getSymbolsHelper(true);
 }
 
-template <class ELFT> void elf2::ObjectFile<ELFT>::parse() {
+template <class ELFT>
+void elf2::ObjectFile<ELFT>::parse(DenseSet<StringRef> &Comdats) {
   // Read section and symbol tables.
-  initializeSections();
+  initializeSections(Comdats);
   initializeSymbols();
 }
 
-template <class ELFT> void elf2::ObjectFile<ELFT>::initializeSections() {
+template <class ELFT>
+StringRef ObjectFile<ELFT>::getShtGroupSignature(const Elf_Shdr &Sec) {
+  const ELFFile<ELFT> &Obj = this->ELFObj;
+  uint32_t SymtabdSectionIndex = Sec.sh_link;
+  ErrorOr<const Elf_Shdr *> SecOrErr = Obj.getSection(SymtabdSectionIndex);
+  error(SecOrErr);
+  const Elf_Shdr *SymtabSec = *SecOrErr;
+  uint32_t SymIndex = Sec.sh_info;
+  const Elf_Sym *Sym = Obj.getSymbol(SymtabSec, SymIndex);
+  ErrorOr<StringRef> StringTableOrErr = Obj.getStringTableForSymtab(*SymtabSec);
+  error(StringTableOrErr);
+  ErrorOr<StringRef> SignatureOrErr = Sym->getName(*StringTableOrErr);
+  error(SignatureOrErr);
+  return *SignatureOrErr;
+}
+
+template <class ELFT>
+ArrayRef<typename ObjectFile<ELFT>::GroupEntryType>
+ObjectFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) {
+  const ELFFile<ELFT> &Obj = this->ELFObj;
+  ErrorOr<ArrayRef<GroupEntryType>> EntriesOrErr =
+      Obj.template getSectionContentsAsArray<GroupEntryType>(&Sec);
+  error(EntriesOrErr.getError());
+  ArrayRef<GroupEntryType> Entries = *EntriesOrErr;
+  if (Entries.empty() || Entries[0] != GRP_COMDAT)
+    error("Unsupported SHT_GROUP format");
+  return Entries.slice(1);
+}
+
+template <class ELFT>
+void elf2::ObjectFile<ELFT>::initializeSections(DenseSet<StringRef> &Comdats) {
   uint64_t Size = this->ELFObj.getNumSections();
   Sections.resize(Size);
-  unsigned I = 0;
+  unsigned I = -1;
   const ELFFile<ELFT> &Obj = this->ELFObj;
   for (const Elf_Shdr &Sec : Obj.sections()) {
+    ++I;
+    if (Sections[I] == &InputSection<ELFT>::Discarded)
+      continue;
+
     switch (Sec.sh_type) {
+    case SHT_GROUP:
+      Sections[I] = &InputSection<ELFT>::Discarded;
+      if (Comdats.insert(getShtGroupSignature(Sec)).second)
+        continue;
+      for (GroupEntryType E : getShtGroupEntries(Sec)) {
+        uint32_t SecIndex = E;
+        if (SecIndex >= Size)
+          error("Invalid section index in group");
+        Sections[SecIndex] = &InputSection<ELFT>::Discarded;
+      }
+      break;
     case SHT_SYMTAB:
       this->Symtab = &Sec;
       break;
@@ -135,7 +181,6 @@ template <class ELFT> void elf2::ObjectF
       Sections[I] = new (Alloc) InputSection<ELFT>(this, &Sec);
       break;
     }
-    ++I;
   }
 }
 
@@ -177,8 +222,12 @@ SymbolBody *elf2::ObjectFile<ELFT>::crea
     error("unexpected binding");
   case STB_GLOBAL:
   case STB_WEAK:
-  case STB_GNU_UNIQUE:
-    return new (Alloc) DefinedRegular<ELFT>(Name, *Sym, *Sections[SecIndex]);
+  case STB_GNU_UNIQUE: {
+    InputSection<ELFT> *Sec = Sections[SecIndex];
+    if (Sec == &InputSection<ELFT>::Discarded)
+      return new (Alloc) Undefined<ELFT>(Name, *Sym);
+    return new (Alloc) DefinedRegular<ELFT>(Name, *Sym, *Sec);
+  }
   }
 }
 

Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=249881&r1=249880&r2=249881&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Fri Oct  9 14:25:07 2015
@@ -37,9 +37,6 @@ public:
   Kind kind() const { return FileKind; }
   virtual ~InputFile() {}
 
-  // Reads a file (constructors don't do that).
-  virtual void parse() = 0;
-
   StringRef getName() const { return MB.getBufferIdentifier(); }
 
 protected:
@@ -75,6 +72,7 @@ public:
   static bool classof(const InputFile *F) { return F->kind() == ObjectKind; }
 
   ArrayRef<SymbolBody *> getSymbols() { return SymbolBodies; }
+  virtual void parse(llvm::DenseSet<StringRef> &Comdats) = 0;
 
 protected:
   // List of all symbols referenced or defined by this file.
@@ -126,6 +124,11 @@ class ObjectFile : public ObjectFileBase
   typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
   typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word;
 
+  typedef llvm::support::detail::packed_endian_specific_integral<
+      uint32_t, ELFT::TargetEndianness, 2> GroupEntryType;
+  StringRef getShtGroupSignature(const Elf_Shdr &Sec);
+  ArrayRef<GroupEntryType> getShtGroupEntries(const Elf_Shdr &Sec);
+
 public:
   using ELFData<ELFT>::getEMachine;
 
@@ -135,7 +138,7 @@ public:
   }
 
   explicit ObjectFile(MemoryBufferRef M);
-  void parse() override;
+  void parse(llvm::DenseSet<StringRef> &Comdats) override;
 
   ArrayRef<InputSection<ELFT> *> getSections() const { return Sections; }
 
@@ -152,7 +155,7 @@ public:
   ArrayRef<Elf_Word> getSymbolTableShndx() const { return SymtabSHNDX; };
 
 private:
-  void initializeSections();
+  void initializeSections(llvm::DenseSet<StringRef> &Comdats);
   void initializeSymbols();
 
   SymbolBody *createSymbolBody(StringRef StringTable, const Elf_Sym *Sym);
@@ -167,7 +170,7 @@ class ArchiveFile : public InputFile {
 public:
   explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {}
   static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
-  void parse() override;
+  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.
@@ -194,6 +197,7 @@ public:
   static bool classof(const InputFile *F) { return F->kind() == SharedKind; }
   StringRef getSoName() const { return SoName; }
   virtual void parseSoName() = 0;
+  virtual void parse() = 0;
 };
 
 template <class ELFT>

Modified: lld/trunk/ELF/InputSection.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.h?rev=249881&r1=249880&r2=249881&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.h (original)
+++ lld/trunk/ELF/InputSection.h Fri Oct  9 14:25:07 2015
@@ -56,6 +56,8 @@ public:
   // Relocation sections that refer to this one.
   SmallVector<const Elf_Shdr *, 1> RelocSections;
 
+  static InputSection<ELFT> Discarded;
+
 private:
   template <bool isRela>
   void relocate(uint8_t *Buf,
@@ -75,6 +77,9 @@ private:
   const Elf_Shdr *Header;
 };
 
+template <class ELFT>
+InputSection<ELFT> InputSection<ELFT>::Discarded(nullptr, nullptr);
+
 } // namespace elf2
 } // namespace lld
 

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=249881&r1=249880&r2=249881&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Fri Oct  9 14:25:07 2015
@@ -475,6 +475,14 @@ lld::elf2::getLocalSymVA(const typename
         Sym, File.getSymbolTable(), File.getSymbolTableShndx());
   ArrayRef<InputSection<ELFT> *> Sections = File.getSections();
   InputSection<ELFT> *Section = Sections[SecIndex];
+
+  // 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 (Section == &InputSection<ELFT>::Discarded)
+    return 0;
+
   OutputSection<ELFT> *OutSec = Section->getOutputSection();
   return OutSec->getVA() + Section->getOutputSectionOff() + Sym->st_value;
 }
@@ -534,11 +542,24 @@ bool lld::elf2::includeInDynamicSymtab(c
 }
 
 template <class ELFT>
-bool lld::elf2::shouldKeepInSymtab(StringRef SymName,
+bool lld::elf2::shouldKeepInSymtab(const ObjectFile<ELFT> &File,
+                                   StringRef SymName,
                                    const typename ELFFile<ELFT>::Elf_Sym &Sym) {
   if (Sym.getType() == STT_SECTION)
     return false;
 
+  // If sym references a section in a discarded group, don't keep it.
+  uint32_t SecIndex = Sym.st_shndx;
+  if (SecIndex != SHN_ABS) {
+    if (SecIndex == SHN_XINDEX)
+      SecIndex = File.getObj().getExtendedSymbolTableIndex(
+          &Sym, File.getSymbolTable(), File.getSymbolTableShndx());
+    ArrayRef<InputSection<ELFT> *> Sections = File.getSections();
+    const InputSection<ELFT> *Section = Sections[SecIndex];
+    if (Section == &InputSection<ELFT>::Discarded)
+      return false;
+  }
+
   if (Config->DiscardNone)
     return true;
 
@@ -597,8 +618,9 @@ void SymbolTableSection<ELFT>::writeLoca
       ErrorOr<StringRef> SymNameOrErr = Sym.getName(File.getStringTable());
       error(SymNameOrErr);
       StringRef SymName = *SymNameOrErr;
-      if (!shouldKeepInSymtab<ELFT>(SymName, Sym))
+      if (!shouldKeepInSymtab<ELFT>(File, SymName, Sym))
         continue;
+
       auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
       Buf += sizeof(*ESym);
       ESym->st_name = StrTabSec.getFileOff(SymName);
@@ -774,13 +796,17 @@ template bool includeInSymtab<ELF32BE>(c
 template bool includeInSymtab<ELF64LE>(const SymbolBody &);
 template bool includeInSymtab<ELF64BE>(const SymbolBody &);
 
-template bool shouldKeepInSymtab<ELF32LE>(StringRef,
+template bool shouldKeepInSymtab<ELF32LE>(const ObjectFile<ELF32LE> &,
+                                          StringRef,
                                           const ELFFile<ELF32LE>::Elf_Sym &);
-template bool shouldKeepInSymtab<ELF32BE>(StringRef,
+template bool shouldKeepInSymtab<ELF32BE>(const ObjectFile<ELF32BE> &,
+                                          StringRef,
                                           const ELFFile<ELF32BE>::Elf_Sym &);
-template bool shouldKeepInSymtab<ELF64LE>(StringRef,
+template bool shouldKeepInSymtab<ELF64LE>(const ObjectFile<ELF64LE> &,
+                                          StringRef,
                                           const ELFFile<ELF64LE>::Elf_Sym &);
-template bool shouldKeepInSymtab<ELF64BE>(StringRef,
+template bool shouldKeepInSymtab<ELF64BE>(const ObjectFile<ELF64BE> &,
+                                          StringRef,
                                           const ELFFile<ELF64BE>::Elf_Sym &);
 }
 }

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=249881&r1=249880&r2=249881&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Fri Oct  9 14:25:07 2015
@@ -46,7 +46,8 @@ bool includeInDynamicSymtab(const Symbol
 
 template <class ELFT>
 bool shouldKeepInSymtab(
-    StringRef Name, const typename llvm::object::ELFFile<ELFT>::Elf_Sym &Sym);
+    const ObjectFile<ELFT> &File, StringRef Name,
+    const typename llvm::object::ELFFile<ELFT>::Elf_Sym &Sym);
 
 // This represents a section in an output file.
 // Different sub classes represent different types of sections. Some contain

Modified: lld/trunk/ELF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.cpp?rev=249881&r1=249880&r2=249881&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.cpp (original)
+++ lld/trunk/ELF/SymbolTable.cpp Fri Oct  9 14:25:07 2015
@@ -45,8 +45,10 @@ void SymbolTable::addFile(std::unique_pt
     S->parseSoName();
     if (!IncludedSoNames.insert(S->getSoName()).second)
       return;
+    S->parse();
+  } else {
+    cast<ObjectFileBase>(File.get())->parse(Comdats);
   }
-  File->parse();
   addELFFile(cast<ELFFileBase>(File.release()));
 }
 

Modified: lld/trunk/ELF/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.h?rev=249881&r1=249880&r2=249881&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.h (original)
+++ lld/trunk/ELF/SymbolTable.h Fri Oct  9 14:25:07 2015
@@ -95,6 +95,8 @@ private:
   llvm::MapVector<StringRef, Symbol *> Symtab;
   llvm::BumpPtrAllocator Alloc;
 
+  llvm::DenseSet<StringRef> Comdats;
+
   // The writer needs to infer the machine type from the object files.
   std::vector<std::unique_ptr<ObjectFileBase>> ObjectFiles;
 

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=249881&r1=249880&r2=249881&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Fri Oct  9 14:25:07 2015
@@ -295,8 +295,9 @@ template <class ELFT> void Writer<ELFT>:
       ErrorOr<StringRef> SymNameOrErr = Sym.getName(File.getStringTable());
       error(SymNameOrErr);
       StringRef SymName = *SymNameOrErr;
-      if (shouldKeepInSymtab<ELFT>(SymName, Sym))
-        Out<ELFT>::SymTab->addSymbol(SymName, true);
+      if (!shouldKeepInSymtab<ELFT>(File, SymName, Sym))
+        continue;
+      Out<ELFT>::SymTab->addSymbol(SymName, true);
     }
   }
 }
@@ -398,11 +399,11 @@ template <class ELFT> void Writer<ELFT>:
   for (const std::unique_ptr<ObjectFileBase> &FileB : Symtab.getObjectFiles()) {
     auto &File = cast<ObjectFile<ELFT>>(*FileB);
     for (InputSection<ELFT> *C : File.getSections()) {
-      if (!C)
+      if (!C || C == &InputSection<ELFT>::Discarded)
         continue;
       const Elf_Shdr *H = C->getSectionHdr();
-      SectionKey<ELFT::Is64Bits> Key{C->getSectionName(), H->sh_type,
-                                     H->sh_flags};
+      uintX_t OutFlags = H->sh_flags & ~SHF_GROUP;
+      SectionKey<ELFT::Is64Bits> Key{C->getSectionName(), H->sh_type, OutFlags};
       OutputSection<ELFT> *&Sec = Map[Key];
       if (!Sec) {
         Sec = new (CAlloc.Allocate())

Added: lld/trunk/test/elf2/Inputs/comdat.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/Inputs/comdat.s?rev=249881&view=auto
==============================================================================
--- lld/trunk/test/elf2/Inputs/comdat.s (added)
+++ lld/trunk/test/elf2/Inputs/comdat.s Fri Oct  9 14:25:07 2015
@@ -0,0 +1,3 @@
+        .section .text3,"axG", at progbits,zed,comdat,unique,0
+        .global abc
+abc:

Added: lld/trunk/test/elf2/comdat.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/comdat.s?rev=249881&view=auto
==============================================================================
--- lld/trunk/test/elf2/comdat.s (added)
+++ lld/trunk/test/elf2/comdat.s Fri Oct  9 14:25:07 2015
@@ -0,0 +1,72 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/comdat.s -o %t2.o
+// RUN: ld.lld2 -shared %t.o %t.o %t2.o -o %t
+// RUN: llvm-objdump -d %t | FileCheck %s
+// RUN: llvm-readobj -s -t %t | FileCheck --check-prefix=READ %s
+// REQUIRES: x86
+
+        .section	.text2,"axG", at progbits,foo,comdat,unique,0
+foo:
+        nop
+
+// CHECK: Disassembly of section .text2:
+// CHECK-NEXT: foo:
+// CHECK-NEXT:   2000: {{.*}}  nop
+// CHECK-NOT: nop
+
+        .section bar, "ax"
+        call foo
+
+// CHECK: Disassembly of section bar:
+// CHECK-NEXT: bar:
+// 0x2000 - 0x2001 - 5 = -6
+// 0      - 0x2006 - 5 = -8203
+// CHECK-NEXT:   2001:	{{.*}}  callq  -6
+// CHECK-NEXT:   2006:	{{.*}}  callq  -8203
+
+        .section .text3,"axG", at progbits,zed,comdat,unique,0
+
+
+// READ:      Name: .text2
+// READ-NEXT: Type: SHT_PROGBITS
+// READ-NEXT: Flags [
+// READ-NEXT:   SHF_ALLOC
+// READ-NEXT:   SHF_EXECINSTR
+// READ-NEXT: ]
+
+// READ:      Name: .text3
+// READ-NEXT: Type: SHT_PROGBITS
+// READ-NEXT: Flags [
+// READ-NEXT:   SHF_ALLOC
+// READ-NEXT:   SHF_EXECINSTR
+// READ-NEXT: ]
+
+// READ:      Symbols [
+// READ-NEXT:   Symbol {
+// READ-NEXT:     Name:  (0)
+// READ-NEXT:     Value: 0x0
+// READ-NEXT:     Size: 0
+// READ-NEXT:     Binding: Local
+// READ-NEXT:     Type: None
+// READ-NEXT:     Other: 0
+// READ-NEXT:     Section: Undefined
+// READ-NEXT:   }
+// READ-NEXT:   Symbol {
+// READ-NEXT:     Name: foo
+// READ-NEXT:     Value
+// READ-NEXT:     Size: 0
+// READ-NEXT:     Binding: Local
+// READ-NEXT:     Type: None
+// READ-NEXT:     Other: 0
+// READ-NEXT:     Section: .text
+// READ-NEXT:   }
+// READ-NEXT:   Symbol {
+// READ-NEXT:     Name: abc
+// READ-NEXT:     Value: 0x0
+// READ-NEXT:     Size: 0
+// READ-NEXT:     Binding: Global
+// READ-NEXT:     Type: None
+// READ-NEXT:     Other: 0
+// READ-NEXT:     Section: Undefined
+// READ-NEXT:   }
+// READ-NEXT: ]




More information about the llvm-commits mailing list