Index: llvm/trunk/test/tools/llvm-objcopy/basic-keep.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/basic-keep.test +++ llvm/trunk/test/tools/llvm-objcopy/basic-keep.test @@ -0,0 +1,19 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy -strip-non-alloc -keep=.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: Name: .test +# CHECK: Name: .shstrtab Index: llvm/trunk/test/tools/llvm-objcopy/basic-only-keep.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/basic-only-keep.test +++ llvm/trunk/test/tools/llvm-objcopy/basic-only-keep.test @@ -0,0 +1,23 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy -only-keep=.test %t %t2 +# RUN: llvm-objcopy -j=.test %t %t3 +# RUN: llvm-readobj -file-headers -sections %t2 | FileCheck %s +# RUN: diff %t2 %t3 + +!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: llvm/trunk/test/tools/llvm-objcopy/dump-section.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/dump-section.test +++ llvm/trunk/test/tools/llvm-objcopy/dump-section.test @@ -0,0 +1,28 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy -O binary -j .text %t %t2 +# RUN: llvm-objcopy -O binary -only-keep .text %t %t3 +# RUN: od -t x1 %t2 | FileCheck %s +# RUN: wc -c %t2 | FileCheck %s --check-prefix=SIZE +# RUN: diff %t2 %t3 + +!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: llvm/trunk/test/tools/llvm-objcopy/explicit-keep-remove.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/explicit-keep-remove.test +++ llvm/trunk/test/tools/llvm-objcopy/explicit-keep-remove.test @@ -0,0 +1,21 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy -R=.test -keep=.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: llvm/trunk/test/tools/llvm-objcopy/explicit-only-keep-remove.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/explicit-only-keep-remove.test +++ llvm/trunk/test/tools/llvm-objcopy/explicit-only-keep-remove.test @@ -0,0 +1,21 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy -R=.test -only-keep=.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: llvm/trunk/test/tools/llvm-objcopy/keep-many.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/keep-many.test +++ llvm/trunk/test/tools/llvm-objcopy/keep-many.test @@ -0,0 +1,27 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy -strip-non-alloc -keep=.test -keep=.test3 %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: [ ] + - Name: .test2 + Type: SHT_PROGBITS + Flags: [ ] + - Name: .test3 + Type: SHT_PROGBITS + Flags: [ ] + + +# CHECK: SectionHeaderCount: 4 + +# CHECK: Name: .test +# CHECK: Name: .test3 +# CHECK: Name: .shstrtab Index: llvm/trunk/test/tools/llvm-objcopy/keep-only-keep.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/keep-only-keep.test +++ llvm/trunk/test/tools/llvm-objcopy/keep-only-keep.test @@ -0,0 +1,27 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy -keep=.test2 -only-keep=.test %t %t2 +# RUN: llvm-objcopy -j=.test -keep=.test2 %t %t3 +# RUN: llvm-readobj -file-headers -sections %t2 | FileCheck %s +# RUN: diff %t2 %t3 + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .test + Type: SHT_PROGBITS + - Name: .test2 + Type: SHT_PROGBITS + - Name: .test3 + Type: SHT_PROGBITS + +# CHECK: SectionHeaderCount: 6 + +# CHECK: Name: .test +# CHECK: Name: .test2 +# CHECK: Name: .symtab +# CHECK: Name: .strtab +# CHECK: Name: .shstrtab Index: llvm/trunk/test/tools/llvm-objcopy/only-keep-many.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/only-keep-many.test +++ llvm/trunk/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: llvm/trunk/test/tools/llvm-objcopy/only-keep-remove-strtab.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/only-keep-remove-strtab.test +++ llvm/trunk/test/tools/llvm-objcopy/only-keep-remove-strtab.test @@ -0,0 +1,21 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy -R .symtab -R .strtab -only-keep=.test %t %t2 +# RUN: llvm-objcopy -j=.test -R .strtab -R .symtab %t %t3 +# RUN: llvm-readobj -file-headers -sections %t2 | FileCheck %s +# RUN: diff %t2 %t3 + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .test + Type: SHT_PROGBITS + Flags: [ ] + +# CHECK: SectionHeaderCount: 3 + +# CHECK: Name: .test +# CHECK: Name: .shstrtab Index: llvm/trunk/test/tools/llvm-objcopy/only-keep-strip-non-alloc.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/only-keep-strip-non-alloc.test +++ llvm/trunk/test/tools/llvm-objcopy/only-keep-strip-non-alloc.test @@ -0,0 +1,19 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy -strip-non-alloc -only-keep=.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: Name: .test +# CHECK: Name: .shstrtab Index: llvm/trunk/test/tools/llvm-objcopy/strip-sections-keep.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/strip-sections-keep.test +++ llvm/trunk/test/tools/llvm-objcopy/strip-sections-keep.test @@ -0,0 +1,13 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy -strip-sections -keep=.shstrtab %t %t2 +# RUN: od -Ax -t c %t2 | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + +# CHECK: \0 . s h s t r t a b \0 Index: llvm/trunk/test/tools/llvm-objcopy/strip-sections-only-keep.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/strip-sections-only-keep.test +++ llvm/trunk/test/tools/llvm-objcopy/strip-sections-only-keep.test @@ -0,0 +1,20 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy -strip-sections -only-keep=.test %t %t2 +# RUN: od -Ax -t x1 %t2 | FileCheck %s +# RUN: od -Ax -t c %t2 | FileCheck %s -check-prefix=TEXT + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .test + Type: SHT_PROGBITS + Flags: [ ] + Content: "DEADBEEF" + +# CHECK: de ad be ef + +# TEXT-NOT: t e s t Index: llvm/trunk/tools/llvm-objcopy/Object.h =================================================================== --- llvm/trunk/tools/llvm-objcopy/Object.h +++ llvm/trunk/tools/llvm-objcopy/Object.h @@ -196,6 +196,7 @@ SectionBase *DefinedIn, uint64_t Value, uint16_t Shndx, uint64_t Sz); void addSymbolNames(); + const SectionBase *getStrTab() const { return SymbolNames; } const Symbol *getSymbolByIndex(uint32_t Index) const; void removeSectionReferences(const SectionBase *Sec) override; void initialize(SectionTableRef SecTable) override; @@ -368,6 +369,7 @@ Object(const object::ELFObjectFile &Obj); virtual ~Object() = default; + const SymbolTableSection *getSymTab() const { return SymbolTable; } const SectionBase *getSectionHeaderStrTab() const { return SectionNames; } void removeSections(std::function ToRemove); virtual size_t totalSize() const = 0; Index: llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp =================================================================== --- llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp +++ llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp @@ -89,6 +89,13 @@ static cl::opt StripAllGNU("strip-all-gnu", cl::desc("Removes symbol, relocation, and debug information")); +static cl::list Keep("keep", cl::desc("Keep
"), + cl::value_desc("section")); +static cl::list OnlyKeep("only-keep", + cl::desc("Remove all but
"), + cl::value_desc("section")); +static cl::alias OnlyKeepA("j", cl::desc("Alias for only-keep"), + cl::aliasopt(OnlyKeep)); static cl::opt StripDebug("strip-debug", cl::desc("Removes all debug information")); static cl::opt StripSections("strip-sections", @@ -150,6 +157,13 @@ WriteObjectFile(DWOFile, File); } +// This function handles the high level operations of GNU objcopy including +// handling command line options. It's important to outline certain properties +// we expect to hold of the command line operations. Any operation that "keeps" +// should keep regardless of a remove. Additionally any removal should respect +// any previous removals. Lastly whether or not something is removed shouldn't +// depend a) on the order the options occur in or b) on some opaque priority +// system. The only priority is that keeps/copies overrule removes. template void CopyBinary(const ELFObjectFile &ObjFile) { std::unique_ptr> Obj; @@ -166,6 +180,8 @@ SectionPred RemovePred = [](const SectionBase &) { return false; }; + // Removes: + if (!ToRemove.empty()) { RemovePred = [&](const SectionBase &Sec) { return std::find(std::begin(ToRemove), std::end(ToRemove), Sec.Name) != @@ -234,6 +250,43 @@ return (Sec.Flags & SHF_ALLOC) == 0; }; + // Explicit copies: + + if (!OnlyKeep.empty()) { + RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { + // Explicitly keep these sections regardless of previous removes. + if (std::find(std::begin(OnlyKeep), std::end(OnlyKeep), Sec.Name) != + std::end(OnlyKeep)) + return false; + + // Allow all implicit removes. + if (RemovePred(Sec)) { + return true; + } + + // Keep special sections. + if (Obj->getSectionHeaderStrTab() == &Sec) { + return false; + } + if (Obj->getSymTab() == &Sec || Obj->getSymTab()->getStrTab() == &Sec) { + return false; + } + // Remove everything else. + return true; + }; + } + + if (!Keep.empty()) { + RemovePred = [RemovePred](const SectionBase &Sec) { + // Explicitly keep these sections regardless of previous removes. + if (std::find(std::begin(Keep), std::end(Keep), Sec.Name) != + std::end(Keep)) + return false; + // Otherwise defer to RemovePred. + return RemovePred(Sec); + }; + } + Obj->removeSections(RemovePred); Obj->finalize(); WriteObjectFile(*Obj, OutputFilename.getValue());