Index: llvm/trunk/test/tools/llvm-objcopy/ELF/dynrelocsec-remove-shinfo-reference.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/ELF/dynrelocsec-remove-shinfo-reference.test +++ llvm/trunk/test/tools/llvm-objcopy/ELF/dynrelocsec-remove-shinfo-reference.test @@ -0,0 +1,30 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy -R .got.plt %t %t2 + +## .rela.plt is a dynamic relocation section that has a connection +## via sh_info field with its target section .got.plt. +## Here we check that if the target section is removed then dynamic +## relocation section is also removed and we do not end up with a broken +## sh_info value, for example. + +# RUN: llvm-readelf --sections %t2 \ +# RUN: | FileCheck %s --implicit-check-not=".got.plt" --implicit-check-not=".rela.plt" + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .rela.plt + Type: SHT_RELA + Flags: [ SHF_ALLOC ] + Link: .dynsym + Info: .got.plt + - Name: .got.plt + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] +DynamicSymbols: + - Name: bar + Binding: STB_GLOBAL Index: llvm/trunk/test/tools/llvm-objcopy/ELF/dynrelocsec-remove-shlink-reference.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/ELF/dynrelocsec-remove-shlink-reference.test +++ llvm/trunk/test/tools/llvm-objcopy/ELF/dynrelocsec-remove-shlink-reference.test @@ -0,0 +1,34 @@ +# RUN: yaml2obj %s > %t + +## Check we cannot remove the .dynsym symbol table because dynamic +## relocation section .rela.dyn still references it via sh_link field. +# RUN: not llvm-objcopy -R .dynsym %t %t2 2>&1 >/dev/null | FileCheck %s --check-prefix=ERR +# ERR: error: Symbol table .dynsym cannot be removed because it is referenced by the relocation section .rela.dyn. + +## Check we can remove .dynsym after removing the reference. +# RUN: llvm-objcopy -R .dynsym -R .rela.dyn %t %t2 +# RUN: llvm-readelf --sections %t2 | FileCheck %s --implicit-check-not=".dynsym" + +## Check we zero out sh_link field and allow producing output with the --allow-broken-links switch. +# RUN: llvm-objcopy -R .dynsym --allow-broken-links %t %t2 +# RUN: llvm-readelf --sections %t2 | FileCheck %s --check-prefix=DROP-LINK +# DROP-LINK: [Nr] Name Type Address Off Size ES Flg L +# DROP-LINK: [ 1] .rela.dyn RELA 0000000000000270 000040 000000 18 A 0 +# DROP-LINK-NOT: .dynsym + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .rela.dyn + Type: SHT_RELA + Flags: [ SHF_ALLOC ] + Address: 0x0000000000000270 + Link: .dynsym + EntSize: 0x0000000000000018 +DynamicSymbols: + - Name: bar + Binding: STB_GLOBAL Index: llvm/trunk/tools/llvm-objcopy/ELF/Object.h =================================================================== --- llvm/trunk/tools/llvm-objcopy/ELF/Object.h +++ llvm/trunk/tools/llvm-objcopy/ELF/Object.h @@ -682,12 +682,15 @@ public: explicit DynamicRelocationSection(ArrayRef Data) : Contents(Data) {} - - void accept(SectionVisitor &) const override; - void accept(MutableSectionVisitor &Visitor) override; - - static bool classof(const SectionBase *S) { - if (!(S->Flags & ELF::SHF_ALLOC)) + + void accept(SectionVisitor &) const override; + void accept(MutableSectionVisitor &Visitor) override; + Error removeSectionReferences( + bool AllowBrokenLinks, + function_ref ToRemove) override; + + static bool classof(const SectionBase *S) { + if (!(S->Flags & ELF::SHF_ALLOC)) return false; return S->Type == ELF::SHT_REL || S->Type == ELF::SHT_RELA; } Index: llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp =================================================================== --- llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp +++ llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp @@ -680,12 +680,33 @@ } void DynamicRelocationSection::accept(MutableSectionVisitor &Visitor) { - Visitor.visit(*this); -} - -Error Section::removeSectionReferences(bool AllowBrokenDependency, - function_ref ToRemove) { - if (ToRemove(LinkSection)) { + Visitor.visit(*this); +} + +Error DynamicRelocationSection::removeSectionReferences( + bool AllowBrokenLinks, function_ref ToRemove) { + if (ToRemove(Symbols)) { + if (!AllowBrokenLinks) + return createStringError( + llvm::errc::invalid_argument, + "Symbol table %s cannot be removed because it is " + "referenced by the relocation section %s.", + Symbols->Name.data(), this->Name.data()); + Symbols = nullptr; + } + + // SecToApplyRel contains a section referenced by sh_info field. It keeps + // a section to which the relocation section applies. When we remove any + // sections we also remove their relocation sections. Since we do that much + // earlier, this assert should never be triggered. + assert(!SecToApplyRel || !ToRemove(SecToApplyRel)); + + return Error::success(); +} + +Error Section::removeSectionReferences(bool AllowBrokenDependency, + function_ref ToRemove) { + if (ToRemove(LinkSection)) { if (!AllowBrokenDependency) return createStringError(llvm::errc::invalid_argument, "Section %s cannot be removed because it is "