[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