From d8a5c6cf19e7245f0c9d076831ebeabc29d6e174 Mon Sep 17 00:00:00 2001 From: George Rimar Date: Mon, 11 Mar 2019 11:01:24 +0000 Subject: [PATCH] [llvm-objcopy] - Fix --compress-debug-sections when there are relocations. When --compress-debug-sections is given, llvm-objcopy removes the uncompressed sections and adds compressed to the section list. This makes all the pointers to old sections to be outdated. Currently, code already has logic for replacing the target sections of the relocation sections. But we also have to update the relocations by themselves. This fixes https://bugs.llvm.org/show_bug.cgi?id=40885. Differential revision: https://reviews.llvm.org/D58960 llvm-svn: 355821 --- .../ELF/Inputs/compress-debug-sections.yaml | 11 ++++++++ .../ELF/compress-debug-sections-zlib-gnu.test | 3 ++- .../ELF/compress-debug-sections-zlib.test | 4 +-- llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp | 29 ++++++++++------------ llvm/tools/llvm-objcopy/ELF/Object.cpp | 15 +++++++++++ llvm/tools/llvm-objcopy/ELF/Object.h | 4 +++ 6 files changed, 47 insertions(+), 19 deletions(-) diff --git a/llvm/test/tools/llvm-objcopy/ELF/Inputs/compress-debug-sections.yaml b/llvm/test/tools/llvm-objcopy/ELF/Inputs/compress-debug-sections.yaml index bb1e9e6..0f9f5a1 100644 --- a/llvm/test/tools/llvm-objcopy/ELF/Inputs/compress-debug-sections.yaml +++ b/llvm/test/tools/llvm-objcopy/ELF/Inputs/compress-debug-sections.yaml @@ -18,4 +18,15 @@ Sections: - Offset: 0x1 Symbol: .debug_foo Type: R_X86_64_32 + - Offset: 0x2 + Symbol: .notdebug_foo + Type: R_X86_64_32 +Symbols: + Global: + - Name: .debug_foo + Type: STT_SECTION + Section: .debug_foo + - Name: .notdebug_foo + Type: STT_SECTION + Section: .notdebug_foo ... diff --git a/llvm/test/tools/llvm-objcopy/ELF/compress-debug-sections-zlib-gnu.test b/llvm/test/tools/llvm-objcopy/ELF/compress-debug-sections-zlib-gnu.test index 0a360d0..70eb2e8 100644 --- a/llvm/test/tools/llvm-objcopy/ELF/compress-debug-sections-zlib-gnu.test +++ b/llvm/test/tools/llvm-objcopy/ELF/compress-debug-sections-zlib-gnu.test @@ -57,7 +57,8 @@ # CHECK-FLAGS: Relocations [ # CHECK-FLAGS-NEXT: .rela.debug_foo { -# CHECK-FLAGS-NEXT: 0x1 R_X86_64_32 - 0x0 +# CHECK-FLAGS-NEXT: 0x1 R_X86_64_32 .zdebug_foo 0x0 +# CHECK-FLAGS-NEXT: 0x2 R_X86_64_32 .notdebug_foo 0x0 # CHECK-FLAGS-NEXT: } # CHECK-FLAGS-NEXT: ] diff --git a/llvm/test/tools/llvm-objcopy/ELF/compress-debug-sections-zlib.test b/llvm/test/tools/llvm-objcopy/ELF/compress-debug-sections-zlib.test index 1e7dfc9..d6c7429 100644 --- a/llvm/test/tools/llvm-objcopy/ELF/compress-debug-sections-zlib.test +++ b/llvm/test/tools/llvm-objcopy/ELF/compress-debug-sections-zlib.test @@ -57,7 +57,7 @@ # CHECK-FLAGS: Relocations [ # CHECK-FLAGS-NEXT: .rela.debug_foo { -# CHECK-FLAGS-NEXT: 0x1 R_X86_64_32 - 0x0 +# CHECK-FLAGS-NEXT: 0x1 R_X86_64_32 .debug_foo 0x0 +# CHECK-FLAGS-NEXT: 0x2 R_X86_64_32 .notdebug_foo 0x0 # CHECK-FLAGS-NEXT: } # CHECK-FLAGS-NEXT: ] - diff --git a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp index 6f21db9..83f1f0e 100644 --- a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -232,27 +232,24 @@ static void replaceDebugSections( const CopyConfig &Config, Object &Obj, SectionPred &RemovePred, function_ref shouldReplace, function_ref addSection) { + // Build a list of the debug sections we are going to replace. + // We can't call `addSection` while iterating over sections, + // because it would mutate the sections array. SmallVector ToReplace; - SmallVector RelocationSections; - for (auto &Sec : Obj.sections()) { - if (RelocationSection *R = dyn_cast(&Sec)) { - if (shouldReplace(*R->getSection())) - RelocationSections.push_back(R); - continue; - } - + for (auto &Sec : Obj.sections()) if (shouldReplace(Sec)) ToReplace.push_back(&Sec); - } - for (SectionBase *S : ToReplace) { - SectionBase *NewSection = addSection(S); + // Build a mapping from original section to a new one. + DenseMap FromTo; + for (SectionBase *S : ToReplace) + FromTo[S] = addSection(S); - for (RelocationSection *RS : RelocationSections) { - if (RS->getSection() == S) - RS->setSection(NewSection); - } - } + // Now we want to update the target sections of relocation + // sections. Also we will update the relocations themselves + // to update the symbol references. + for (auto &Sec : Obj.sections()) + Sec.replaceSectionReferences(FromTo); RemovePred = [shouldReplace, RemovePred](const SectionBase &Sec) { return shouldReplace(Sec) || RemovePred(Sec); diff --git a/llvm/tools/llvm-objcopy/ELF/Object.cpp b/llvm/tools/llvm-objcopy/ELF/Object.cpp index ead2a88..d859c7e 100644 --- a/llvm/tools/llvm-objcopy/ELF/Object.cpp +++ b/llvm/tools/llvm-objcopy/ELF/Object.cpp @@ -62,6 +62,8 @@ Error SectionBase::removeSymbols(function_ref ToRemove) { void SectionBase::initialize(SectionTableRef SecTable) {} void SectionBase::finalize() {} void SectionBase::markSymbols() {} +void SectionBase::replaceSectionReferences( + const DenseMap &) {} template void ELFWriter::writeShdr(const SectionBase &Sec) { uint8_t *B = Buf.getBufferStart(); @@ -634,6 +636,19 @@ void RelocationSection::markSymbols() { Reloc.RelocSymbol->Referenced = true; } +void RelocationSection::replaceSectionReferences( + const DenseMap &FromTo) { + // Update the target section if it was replaced. + if (SectionBase *To = FromTo.lookup(SecToApplyRel)) + SecToApplyRel = To; + + // Change the sections where symbols are defined in if their + // original sections were replaced. + for (const Relocation &R : Relocations) + if (SectionBase *To = FromTo.lookup(R.RelocSymbol->DefinedIn)) + R.RelocSymbol->DefinedIn = To; +} + void SectionWriter::visit(const DynamicRelocationSection &Sec) { llvm::copy(Sec.Contents, Out.getBufferStart() + Sec.Offset); diff --git a/llvm/tools/llvm-objcopy/ELF/Object.h b/llvm/tools/llvm-objcopy/ELF/Object.h index 2c6c590..dabec85 100644 --- a/llvm/tools/llvm-objcopy/ELF/Object.h +++ b/llvm/tools/llvm-objcopy/ELF/Object.h @@ -280,6 +280,8 @@ public: virtual void accept(SectionVisitor &Visitor) const = 0; virtual void accept(MutableSectionVisitor &Visitor) = 0; virtual void markSymbols(); + virtual void + replaceSectionReferences(const DenseMap &); }; class Segment { @@ -596,6 +598,8 @@ public: function_ref ToRemove) override; Error removeSymbols(function_ref ToRemove) override; void markSymbols() override; + void replaceSectionReferences( + const DenseMap &FromTo) override; static bool classof(const SectionBase *S) { if (S->Flags & ELF::SHF_ALLOC) -- 2.7.4