Index: test/tools/llvm-objcopy/basic-only-keep.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/basic-only-keep.test @@ -0,0 +1,61 @@ +# 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: 3 + +# CHECK: Sections [ +# CHECK: Section { +# CHECK: Index: 0 +# CHECK: Name: (0) +# CHECK: Type: SHT_NULL (0x0) +# CHECK: Flags [ (0x0) +# CHECK: ] +# CHECK: Address: 0x0 +# CHECK: Offset: +# CHECK: Size: +# CHECK: Link: 0 +# CHECK: Info: 0 +# CHECK: AddressAlignment: 0 +# CHECK: EntrySize: 0 +# CHECK: } +# CHECK: Section { +# CHECK: Index: 1 +# CHECK: Name: .test +# CHECK: Type: SHT_PROGBITS (0x1) +# CHECK: Flags [ (0x0) +# CHECK: ] +# CHECK: Address: 0x0 +# CHECK: Offset: +# CHECK: Size: +# CHECK: Link: 0 +# CHECK: Info: 0 +# CHECK: AddressAlignment: 0 +# CHECK: EntrySize: 0 +# CHECK: } +# CHECK: Section { +# CHECK: Index: 2 +# CHECK: Name: .shstrtab +# CHECK: Type: SHT_STRTAB (0x3) +# CHECK: Flags [ (0x0) +# CHECK: ] +# CHECK: Address: 0x0 +# CHECK: Offset: +# CHECK: Size: +# CHECK: Link: 0 +# CHECK: Info: 0 +# CHECK: AddressAlignment: 1 +# CHECK: EntrySize: 0 +# CHECK: } +# CHECK: ] 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 togethor 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,81 @@ +# 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: 4 + +# CHECK: Sections [ +# CHECK: Section { +# CHECK: Index: 0 +# CHECK: Name: (0) +# CHECK: Type: SHT_NULL (0x0) +# CHECK: Flags [ (0x0) +# CHECK: ] +# CHECK: Address: 0x0 +# CHECK: Offset: +# CHECK: Size: +# CHECK: Link: 0 +# CHECK: Info: 0 +# CHECK: AddressAlignment: 0 +# CHECK: EntrySize: 0 +# CHECK: } +# CHECK: Section { +# CHECK: Index: 1 +# CHECK: Name: .test1 +# CHECK: Type: SHT_PROGBITS (0x1) +# CHECK: Flags [ (0x0) +# CHECK: ] +# CHECK: Address: 0x0 +# CHECK: Offset: +# CHECK: Size: +# CHECK: Link: 0 +# CHECK: Info: 0 +# CHECK: AddressAlignment: 0 +# CHECK: EntrySize: 0 +# CHECK: } +# CHECK: Section { +# CHECK: Index: 2 +# CHECK: Name: .test2 +# CHECK: Type: SHT_PROGBITS (0x1) +# CHECK: Flags [ (0x0) +# CHECK: ] +# CHECK: Address: 0x0 +# CHECK: Offset: +# CHECK: Size: +# CHECK: Link: 0 +# CHECK: Info: 0 +# CHECK: AddressAlignment: 0 +# CHECK: EntrySize: 0 +# CHECK: } +# CHECK: Section { +# CHECK: Index: 3 +# CHECK: Name: .shstrtab +# CHECK: Type: SHT_STRTAB (0x3) +# CHECK: Flags [ (0x0) +# CHECK: ] +# CHECK: Address: 0x0 +# CHECK: Offset: +# CHECK: Size: +# CHECK: Link: 0 +# CHECK: Info: 0 +# CHECK: AddressAlignment: 1 +# CHECK: EntrySize: 0 +# CHECK: } +# CHECK: ] Index: tools/llvm-objcopy/Object.h =================================================================== --- tools/llvm-objcopy/Object.h +++ tools/llvm-objcopy/Object.h @@ -349,6 +349,7 @@ bool WriteSectionHeaders = true; Object(const llvm::object::ELFObjectFile &Obj); + const SectionBase *getSectionHeaderStrTab() const { return SectionNames; } void removeSections(std::function ToRemove); virtual size_t totalSize() const = 0; virtual void finalize() = 0; @@ -389,4 +390,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,19 @@ 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") { + // Strange exception to support this unique use case in a way that's + // compatible with what GNU objcopy does + if (!OnlySection.empty()) { + if (OnlySection.size() != 1) + error("-O binary and -j can only be used togethor 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 +97,17 @@ }; } + if (!OnlySection.empty()) { + RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { + if (RemovePred(Sec)) + return true; + if (&Sec == Obj->getSectionHeaderStrTab()) + 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;