Index: test/tools/llvm-objcopy/basic-only-keep.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/basic-only-keep.test @@ -0,0 +1,21 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy -j=.test %t %t2 +# RUN: llvm-readobj -file-headers -sections %t2 | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .test + Type: SHT_PROGBITS + Flags: [ ] + +# CHECK: SectionHeaderCount: 5 + +# CHECK: Name: .test +# CHECK: Name: .symtab +# CHECK: Name: .strtab +# CHECK: Name: .shstrtab Index: test/tools/llvm-objcopy/binary-only-keep-error.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/binary-only-keep-error.test @@ -0,0 +1,11 @@ +# RUN: yaml2obj %s > %t +# RUN: not llvm-objcopy -O binary -j .foo -j .bar %t %t2 2>&1 >/dev/null | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 + +# CHECK: -O binary and -j can only be used together with a single -j Index: test/tools/llvm-objcopy/dump-section.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/dump-section.test @@ -0,0 +1,26 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy -O binary -j .text %t %t2 +# RUN: od -t x1 %t2 | FileCheck %s +# RUN: wc -c %t2 | FileCheck %s --check-prefix=SIZE + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000001000 + Content: "DEADBEEF" +ProgramHeaders: +- Type: PT_LOAD + Flags: [ PF_X, PF_R ] + Sections: + - Section: .text + +#CHECK: 0000000 de ad be ef + +#SIZE: 4 Index: test/tools/llvm-objcopy/only-keep-many.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/only-keep-many.test @@ -0,0 +1,28 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy -j .test1 -j .test2 %t %t2 +# RUN: llvm-readobj -file-headers -sections %t2 | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .test1 + Type: SHT_PROGBITS + Flags: [ ] + - Name: .test2 + Type: SHT_PROGBITS + Flags: [ ] + - Name: .test3 + Type: SHT_PROGBITS + Flags: [ ] + +# CHECK: SectionHeaderCount: 6 + +# CHECK: Name: .test1 +# CHECK: Name: .test2 +# CHECK: Name: .symtab +# CHECK: Name: .strtab +# CHECK: Name: .shstrtab Index: tools/llvm-objcopy/Object.h =================================================================== --- tools/llvm-objcopy/Object.h +++ tools/llvm-objcopy/Object.h @@ -179,6 +179,7 @@ public: void setStrTab(StringTableSection *StrTab) { SymbolNames = StrTab; } + const StringTableSection *getStrTab() const { return SymbolNames; } void addSymbol(llvm::StringRef Name, uint8_t Bind, uint8_t Type, SectionBase *DefinedIn, uint64_t Value, uint16_t Shndx, uint64_t Sz); @@ -349,6 +350,10 @@ bool WriteSectionHeaders = true; Object(const llvm::object::ELFObjectFile &Obj); + const StringTableSection *getSectionHeaderStrTab() const { + return SectionNames; + } + const SymbolTableSection *getSymTab() const { return SymbolTable; } void removeSections(std::function ToRemove); virtual size_t totalSize() const = 0; virtual void finalize() = 0; @@ -389,4 +394,24 @@ size_t totalSize() const override; void write(llvm::FileOutputBuffer &Out) const override; }; + +template class SectionDump : public Object { +private: + SectionBase *SectionToOutput = nullptr; + +public: + SectionDump(const llvm::object::ELFObjectFile &Obj, + llvm::StringRef SecName) + : Object(Obj) { + for (auto &Sec : this->Sections) { + if (Sec->Name == SecName) { + SectionToOutput = Sec.get(); + return; + } + } + } + void finalize() override; + size_t totalSize() const override; + void write(llvm::FileOutputBuffer &Out) const override; +}; #endif Index: tools/llvm-objcopy/Object.cpp =================================================================== --- tools/llvm-objcopy/Object.cpp +++ tools/llvm-objcopy/Object.cpp @@ -825,11 +825,31 @@ TotalSize = Offset; } +template size_t SectionDump::totalSize() const { + if (SectionToOutput == nullptr) + return 0; + return SectionToOutput->Size; +} + +template +void SectionDump::write(FileOutputBuffer &Out) const { + SectionToOutput->writeSection(Out); +} + +template void SectionDump::finalize() { + SectionToOutput->Offset = 0; +} + template class Object; template class Object; template class Object; template class Object; +template class SectionDump; +template class SectionDump; +template class SectionDump; +template class SectionDump; + template class ELFObject; template class ELFObject; template class ELFObject; Index: tools/llvm-objcopy/llvm-objcopy.cpp =================================================================== --- tools/llvm-objcopy/llvm-objcopy.cpp +++ tools/llvm-objcopy/llvm-objcopy.cpp @@ -58,6 +58,10 @@ "\n\tbinary")); cl::list ToRemove("remove-section", cl::desc("Remove a specific section")); +cl::list + OnlySection("only-section", cl::desc("Remove all but a specific section")); +cl::alias OnlySectionA("j", cl::desc("Alias for only-section"), + cl::aliasopt(OnlySection)); cl::alias ToRemoveA("R", cl::desc("Alias for remove-section"), cl::aliasopt(ToRemove)); cl::opt StripSections("strip-sections", @@ -70,10 +74,20 @@ std::unique_ptr> Obj; if (!OutputFormat.empty() && OutputFormat != "binary") error("invalid output format '" + OutputFormat + "'"); - if (!OutputFormat.empty() && OutputFormat == "binary") - Obj = llvm::make_unique>(ObjFile); - else + if (!OutputFormat.empty() && OutputFormat == "binary") { + // When the user uses -O binary and -j together they're likely meaning to + // dump the section contents of that section. This is a fairly common + // pattern in GNU objcopy so we should support it. + if (!OnlySection.empty()) { + if (OnlySection.size() != 1) + error("-O binary and -j can only be used together with a single -j"); + Obj = llvm::make_unique>(ObjFile, OnlySection[0]); + } else { + Obj = llvm::make_unique>(ObjFile); + } + } else { Obj = llvm::make_unique>(ObjFile); + } SectionPred RemovePred = [](const SectionBase &) { return false; }; @@ -84,6 +98,21 @@ }; } + if (!OnlySection.empty()) { + RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { + if (RemovePred(Sec)) + return true; + if (&Sec == Obj->getSectionHeaderStrTab()) + return false; + if (&Sec == Obj->getSymTab() || &Sec == Obj->getSymTab()->getStrTab()) + return false; + if (Sec.Type == SHT_SYMTAB) + return false; + return std::find(std::begin(OnlySection), std::end(OnlySection), + Sec.Name) == std::end(OnlySection); + }; + } + if (StripSections) { RemovePred = [RemovePred](const SectionBase &Sec) { return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0;