forked from OSchip/llvm-project
Add support for comdats.
The implementation is a direct translation to c++ of the rules in the ELF spec. llvm-svn: 249881
This commit is contained in:
parent
0ac8eb9171
commit
444576d4c4
|
@ -95,19 +95,65 @@ typename ObjectFile<ELFT>::Elf_Sym_Range ObjectFile<ELFT>::getLocalSymbols() {
|
|||
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::ObjectFile<ELFT>::initializeSections() {
|
|||
Sections[I] = new (Alloc) InputSection<ELFT>(this, &Sec);
|
||||
break;
|
||||
}
|
||||
++I;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,8 +222,12 @@ SymbolBody *elf2::ObjectFile<ELFT>::createSymbolBody(StringRef StringTable,
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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, public ELFData<ELFT> {
|
|||
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>
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -475,6 +475,14 @@ lld::elf2::getLocalSymVA(const typename ELFFile<ELFT>::Elf_Sym *Sym,
|
|||
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(const SymbolBody &B) {
|
|||
}
|
||||
|
||||
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>::writeLocalSymbols(uint8_t *&Buf) {
|
|||
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>(const SymbolBody &);
|
|||
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 &);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,8 @@ bool includeInDynamicSymtab(const SymbolBody &B);
|
|||
|
||||
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
|
||||
|
|
|
@ -45,8 +45,10 @@ void SymbolTable::addFile(std::unique_ptr<InputFile> File) {
|
|||
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()));
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -295,8 +295,9 @@ template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
|
|||
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>::createSections() {
|
|||
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())
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
.section .text3,"axG",@progbits,zed,comdat,unique,0
|
||||
.global abc
|
||||
abc:
|
|
@ -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",@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",@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: ]
|
Loading…
Reference in New Issue