From 3b189d1643fe788ec4792984758a2c0bcaac1b36 Mon Sep 17 00:00:00 2001 From: George Rimar Date: Mon, 29 May 2017 08:37:50 +0000 Subject: [PATCH] [ELF] - Do not allow -r to eat comdats. This is PR33052, "Bug 33052 - -r eats comdats ". To fix it I stop removing group section from out when -r is given and fixing SHT_GROUP content when writing it just like we do some other fixup, e.g. for Rel[a]. (it needs fix for section indices that are in group). Differential revision: https://reviews.llvm.org/D33485 llvm-svn: 304140 --- lld/ELF/InputFiles.cpp | 22 ++++++++++----- lld/ELF/InputSection.cpp | 25 +++++++++++++++++ lld/ELF/InputSection.h | 2 ++ lld/ELF/OutputSections.cpp | 23 +++++++++++++++- lld/test/ELF/relocatable-comdat.s | 45 +++++++++++++++++++++++++++++++ 5 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 lld/test/ELF/relocatable-comdat.s diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 58fa9e0c5e63..98189825ccbf 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -305,13 +305,22 @@ void elf::ObjectFile::initializeSections( } switch (Sec.sh_type) { - case SHT_GROUP: - this->Sections[I] = &InputSection::Discarded; - if (ComdatGroups - .insert( - CachedHashStringRef(getShtGroupSignature(ObjSections, Sec))) - .second) + case SHT_GROUP: { + // We discard comdat sections usually. When -r we should not do that. We + // still do deduplication in this case to simplify implementation, because + // otherwise merging group sections together would requre additional + // regeneration of its contents. + bool New = ComdatGroups + .insert(CachedHashStringRef( + getShtGroupSignature(ObjSections, Sec))) + .second; + if (New && Config->Relocatable) + this->Sections[I] = createInputSection(Sec, SectionStringTable); + else + this->Sections[I] = &InputSection::Discarded; + if (New) continue; + for (uint32_t SecIndex : getShtGroupEntries(Sec)) { if (SecIndex >= Size) fatal(toString(this) + @@ -319,6 +328,7 @@ void elf::ObjectFile::initializeSections( this->Sections[SecIndex] = &InputSection::Discarded; } break; + } case SHT_SYMTAB: this->initSymtab(ObjSections, &Sec); break; diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 8bd3d846372c..466656efbf08 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -295,6 +295,24 @@ bool InputSectionBase::classof(const SectionBase *S) { return S->kind() != Output; } +void InputSection::copyShtGroup(uint8_t *Buf) { + assert(this->Type == SHT_GROUP); + + ArrayRef From = getDataAs(); + uint32_t *To = reinterpret_cast(Buf); + + // First entry is a flag word, we leave it unchanged. + *To++ = From[0]; + + // Here we adjust indices of sections that belong to group as it + // might change during linking. + ArrayRef Sections = this->File->getSections(); + for (uint32_t Val : From.slice(1)) { + uint32_t Index = read32(&Val, Config->Endianness); + write32(To++, Sections[Index]->OutSec->SectionIndex, Config->Endianness); + } +} + InputSectionBase *InputSection::getRelocatedSection() { assert(this->Type == SHT_RELA || this->Type == SHT_REL); ArrayRef Sections = this->File->getSections(); @@ -680,6 +698,13 @@ template void InputSection::writeTo(uint8_t *Buf) { return; } + // If -r is given, linker should keep SHT_GROUP sections. We should fixup + // them, see copyShtGroup(). + if (this->Type == SHT_GROUP) { + copyShtGroup(Buf + OutSecOff); + return; + } + // Copy section contents from source object file to output file // and then apply relocations. memcpy(Buf + OutSecOff, Data.data(), Data.size()); diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h index 75174969c48f..4ef4328e8a5d 100644 --- a/lld/ELF/InputSection.h +++ b/lld/ELF/InputSection.h @@ -319,6 +319,8 @@ public: private: template void copyRelocations(uint8_t *Buf, llvm::ArrayRef Rels); + + void copyShtGroup(uint8_t *Buf); }; // The list of all input sections. diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index e67e24098244..d82fdcdc31ba 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -112,6 +112,19 @@ template void OutputSection::maybeCompress() { Flags |= SHF_COMPRESSED; } +template static void finalizeShtGroup(OutputSection *Sec) { + // sh_link field for SHT_GROUP sections should contain the section index of + // the symbol table. + Sec->Link = InX::SymTab->OutSec->SectionIndex; + + // sh_link then contain index of an entry in symbol table section which + // provides signature of the section group. + elf::ObjectFile *Obj = Sec->Sections[0]->getFile(); + assert(Config->Relocatable && Sec->Sections.size() == 1); + ArrayRef Symbols = Obj->getSymbols(); + Sec->Info = InX::SymTab->getSymbolIndex(Symbols[Sec->Sections[0]->Info - 1]); +} + template void OutputSection::finalize() { if ((this->Flags & SHF_LINK_ORDER) && !this->Sections.empty()) { std::sort(Sections.begin(), Sections.end(), compareByFilePosition); @@ -126,6 +139,11 @@ template void OutputSection::finalize() { } uint32_t Type = this->Type; + if (Type == SHT_GROUP) { + finalizeShtGroup(this); + return; + } + if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL)) return; @@ -355,7 +373,10 @@ void OutputSectionFactory::addInputSec(InputSectionBase *IS, return; } - uint64_t Flags = IS->Flags & ~(uint64_t)SHF_GROUP; + uint64_t Flags = IS->Flags; + if (!Config->Relocatable) + Flags &= ~(uint64_t)SHF_GROUP; + if (Sec) { if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(IS->Flags)) error("incompatible section flags for " + Sec->Name + diff --git a/lld/test/ELF/relocatable-comdat.s b/lld/test/ELF/relocatable-comdat.s new file mode 100644 index 000000000000..24504d23884f --- /dev/null +++ b/lld/test/ELF/relocatable-comdat.s @@ -0,0 +1,45 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld -r %t.o %t.o -o %t +# RUN: llvm-readobj -elf-section-groups -sections %t | FileCheck %s + +# CHECK: Name: .text.bar +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_EXECINSTR +# CHECK-NEXT: SHF_GROUP +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 8 +# CHECK: Section { +# CHECK-NEXT: Index: 4 +# CHECK-NEXT: Name: .text.foo +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_EXECINSTR +# CHECK-NEXT: SHF_GROUP +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 4 + +# CHECK: Groups { +# CHECK-NEXT: Group { +# CHECK-NEXT: Name: .group +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Type: COMDAT +# CHECK-NEXT: Signature: abc +# CHECK-NEXT: Section(s) in group [ +# CHECK-NEXT: .text.bar +# CHECK-NEXT: .text.foo +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: } + +.section .text.bar,"axG",@progbits,abc,comdat +.quad 42 +.section .text.foo,"axG",@progbits,abc,comdat +.long 42