diff --git a/test/tools/llvm-objcopy/dynsym-error-remove-strtab.test b/test/tools/llvm-objcopy/dynsym-error-remove-strtab.test new file mode 100644 index 00000000000..ef6ef243295 --- /dev/null +++ b/test/tools/llvm-objcopy/dynsym-error-remove-strtab.test @@ -0,0 +1,3 @@ +# RUN: not llvm-objcopy -R .dynstr %p/Inputs/dynsym.so %t 2>&1 >/dev/null | FileCheck %s + +# CHECK: String table .dynstr cannot be removed because it is referenced by the section .dynsym diff --git a/test/tools/llvm-objcopy/reloc-error-remove-symtab.test b/test/tools/llvm-objcopy/reloc-error-remove-symtab.test new file mode 100644 index 00000000000..539e6ea1ce1 --- /dev/null +++ b/test/tools/llvm-objcopy/reloc-error-remove-symtab.test @@ -0,0 +1,32 @@ +# RUN: yaml2obj %s > %t +# RUN: not llvm-objcopy -R .symtab %t %t2 2>&1 >/dev/null | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x1000 + AddressAlign: 0x0000000000000010 + Content: "0000000000000000" + - Name: .rel.text + Type: SHT_REL + Link: .symtab + Info: .text + Relocations: + - Offset: 0x1000 + Symbol: foo + Type: R_X86_64_PC32 + +Symbols: + Global: + - Name: foo + Type: STT_FUNC + Size: 4 + +# CHECK: Symbol table .symtab cannot be removed because it is referenced by the relocation section .rel.text. diff --git a/test/tools/llvm-objcopy/remove-section-with-symbol.test b/test/tools/llvm-objcopy/remove-section-with-symbol.test new file mode 100644 index 00000000000..5695abd3388 --- /dev/null +++ b/test/tools/llvm-objcopy/remove-section-with-symbol.test @@ -0,0 +1,54 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy -R .test %t %t2 +# RUN: llvm-readobj -file-headers -symbols %t2 | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .test + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + - Name: .test2 + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] +Symbols: + Global: + - Name: test + Type: STT_FUNC + Section: .test + Value: 0x1000 + Size: 4 + - Name: test2 + Type: STT_FUNC + Section: .test2 + Value: 0x1000 + Size: 4 + +# The remianing sections should be the null section, .test2, .symtab, .strtab, +# and .shstrtab. +#CHECK: SectionHeaderCount: 5 + +#CHECK: Symbols [ +#CHECK-NEXT: Symbol { +#CHECK-NEXT: Name: +#CHECK-NEXT: Value: 0x0 +#CHECK-NEXT: Size: 0 +#CHECK-NEXT: Binding: Local +#CHECK-NEXT: Type: None +#CHECK-NEXT: Other: 0 +#CHECK-NEXT: Section: Undefined +#CHECK-NEXT: } +#CHECK-NEXT: Symbol { +#CHECK-NEXT: Name: test2 +#CHECK-NEXT: Value: 0x1000 +#CHECK-NEXT: Size: 4 +#CHECK-NEXT: Binding: Global +#CHECK-NEXT: Type: Function +#CHECK-NEXT: Other: 0 +#CHECK-NEXT: Section: .test2 +#CHECK-NEXT: } +#CHECK-NEXT:] diff --git a/test/tools/llvm-objcopy/remove-section.test b/test/tools/llvm-objcopy/remove-section.test new file mode 100644 index 00000000000..0fa26bc3874 --- /dev/null +++ b/test/tools/llvm-objcopy/remove-section.test @@ -0,0 +1,109 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy -R=.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: 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: .test3 +# 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: .symtab +# CHECK: Type: SHT_SYMTAB (0x2) +# CHECK: Flags [ (0x0) +# CHECK: ] +# CHECK: Address: 0x0 +# CHECK: Offset: +# CHECK: Size: +# CHECK: Link: 4 +# CHECK: Info: 1 +# CHECK: AddressAlignment: 8 +# CHECK: EntrySize: 24 +# CHECK: } +# CHECK: Section { +# CHECK: Index: 4 +# CHECK: Name: .strtab +# 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: Section { +# CHECK: Index: 5 +# 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: ] diff --git a/test/tools/llvm-objcopy/remove-shstrtab-error.test b/test/tools/llvm-objcopy/remove-shstrtab-error.test new file mode 100644 index 00000000000..7d297ef8fe2 --- /dev/null +++ b/test/tools/llvm-objcopy/remove-shstrtab-error.test @@ -0,0 +1,11 @@ +# RUN: yaml2obj %s > %t +# RUN: not llvm-objcopy -R .shstrtab %t %t2 2>&1 >/dev/null | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 + +# CHECK: Cannot remove .shstrtab because it is the section header string table. diff --git a/test/tools/llvm-objcopy/remove-symtab.test b/test/tools/llvm-objcopy/remove-symtab.test new file mode 100644 index 00000000000..0e3f82b3a0d --- /dev/null +++ b/test/tools/llvm-objcopy/remove-symtab.test @@ -0,0 +1,57 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy -R .symtab %t %t2 +# RUN: llvm-readobj -file-headers -sections %t2 | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 + +#CHECK: SectionHeaderCount: 3 + +#CHECK: Sections [ +#CHECK-NEXT: Section { +#CHECK-NEXT: Index: 0 +#CHECK-NEXT: Name: (0) +#CHECK-NEXT: Type: SHT_NULL (0x0) +#CHECK-NEXT: Flags [ (0x0) +#CHECK-NEXT: ] +#CHECK-NEXT: Address: 0x0 +#CHECK-NEXT: Offset: 0x0 +#CHECK-NEXT: Size: 0 +#CHECK-NEXT: Link: 0 +#CHECK-NEXT: Info: 0 +#CHECK-NEXT: AddressAlignment: 0 +#CHECK-NEXT: EntrySize: 0 +#CHECK-NEXT: } +#CHECK-NEXT: Section { +#CHECK-NEXT: Index: 1 +#CHECK-NEXT: Name: .strtab +#CHECK-NEXT: Type: SHT_STRTAB (0x3) +#CHECK-NEXT: Flags [ (0x0) +#CHECK-NEXT: ] +#CHECK-NEXT: Address: 0x0 +#CHECK-NEXT: Offset: +#CHECK-NEXT: Size: 1 +#CHECK-NEXT: Link: 0 +#CHECK-NEXT: Info: 0 +#CHECK-NEXT: AddressAlignment: 1 +#CHECK-NEXT: EntrySize: 0 +#CHECK-NEXT: } +#CHECK-NEXT: Section { +#CHECK-NEXT: Index: 2 +#CHECK-NEXT: Name: .shstrtab (1) +#CHECK-NEXT: Type: SHT_STRTAB (0x3) +#CHECK-NEXT: Flags [ (0x0) +#CHECK-NEXT: ] +#CHECK-NEXT: Address: 0x0 +#CHECK-NEXT: Offset: +#CHECK-NEXT: Size: +#CHECK-NEXT: Link: 0 +#CHECK-NEXT: Info: 0 +#CHECK-NEXT: AddressAlignment: 1 +#CHECK-NEXT: EntrySize: 0 +#CHECK-NEXT: } +#CHECK-NEXT: ] diff --git a/test/tools/llvm-objcopy/segment-shift-section-remove.test b/test/tools/llvm-objcopy/segment-shift-section-remove.test new file mode 100644 index 00000000000..caeb5596ef7 --- /dev/null +++ b/test/tools/llvm-objcopy/segment-shift-section-remove.test @@ -0,0 +1,164 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-objcopy -R .text2 %t %t2 +# RUN: llvm-readobj -file-headers -sections -program-headers %t2 | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x1000 + AddressAlign: 0x1000 + Size: 0x1000 + - Name: .text2 + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x2000 + AddressAlign: 0x1000 + Size: 0x1000 + - Name: .text3 + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x3000 + AddressAlign: 0x1000 + Size: 0x1000 +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_R ] + VAddr: 0x1000 + PAddr: 0x1000 + Sections: + - Section: .text + - Type: PT_LOAD + Flags: [ PF_X, PF_R ] + VAddr: 0x3000 + PAddr: 0x3000 + Sections: + - Section: .text3 + +#CHECK: SectionHeaderCount: 6 + +# CHECK: Sections [ +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 0 +# CHECK-NEXT: Name: (0) +# CHECK-NEXT: Type: SHT_NULL (0x0) +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x0 +# CHECK-NEXT: Offset: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 0 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 1 +# CHECK-NEXT: Name: .text +# CHECK-NEXT: Type: SHT_PROGBITS (0x1) +# CHECK-NEXT: Flags [ (0x6) +# CHECK-NEXT: SHF_ALLOC (0x2) +# CHECK-NEXT: SHF_EXECINSTR (0x4) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x1000 +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: Size: 4096 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 4096 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Name: .text3 +# CHECK-NEXT: Type: SHT_PROGBITS (0x1) +# CHECK-NEXT: Flags [ (0x6) +# CHECK-NEXT: SHF_ALLOC (0x2) +# CHECK-NEXT: SHF_EXECINSTR (0x4) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x3000 +# CHECK-NEXT: Offset: 0x2000 +# CHECK-NEXT: Size: 4096 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 4096 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 3 +# CHECK-NEXT: Name: .symtab +# CHECK-NEXT: Type: SHT_SYMTAB (0x2) +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x0 +# CHECK-NEXT: Offset: 0x3000 +# CHECK-NEXT: Size: 24 +# CHECK-NEXT: Link: 4 +# CHECK-NEXT: Info: 1 +# CHECK-NEXT: AddressAlignment: 8 +# CHECK-NEXT: EntrySize: 24 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 4 +# CHECK-NEXT: Name: .strtab +# CHECK-NEXT: Type: SHT_STRTAB (0x3) +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x0 +# CHECK-NEXT: Offset: 0x3018 +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 1 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 5 +# CHECK-NEXT: Name: .shstrtab +# CHECK-NEXT: Type: SHT_STRTAB (0x3) +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x0 +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 1 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK-NEXT: ] + + +# CHECK: ProgramHeaders [ +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD (0x1) +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: VirtualAddress: 0x1000 +# CHECK-NEXT: PhysicalAddress: 0x1000 +# CHECK-NEXT: FileSize: 4096 +# CHECK-NEXT: MemSize: 4096 +# CHECK-NEXT: Flags [ (0x4) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD (0x1) +# CHECK-NEXT: Offset: 0x2000 +# CHECK-NEXT: VirtualAddress: 0x3000 +# CHECK-NEXT: PhysicalAddress: 0x3000 +# CHECK-NEXT: FileSize: 4096 +# CHECK-NEXT: MemSize: 4096 +# CHECK-NEXT: Flags [ (0x5) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: PF_X (0x1) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } +# CHECK-NEXT:] diff --git a/test/tools/llvm-objcopy/segment-test-remove-section.test b/test/tools/llvm-objcopy/segment-test-remove-section.test new file mode 100644 index 00000000000..9b98dc8611f --- /dev/null +++ b/test/tools/llvm-objcopy/segment-test-remove-section.test @@ -0,0 +1,156 @@ +# This test is checking to ensure that if a section is removed in the presence +# of a segment that the segment maintains its shape and properties and that any +# section inside that segment maintains the relative positioning it had in the +# segment. Note worthy is that .text3 keeps its offset despite it being +# possible to place it after .text when .text2 is removed. + +# RUN: yaml2obj %s -o %t +# RUN: llvm-objcopy -R .text2 %t %t2 +# RUN: llvm-readobj -file-headers -program-headers -sections %t2 | FileCheck %s +# RUN: od -t x1 -j 8192 %t2 | FileCheck %s --check-prefix=DATA + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x1000 + AddressAlign: 0x1000 + Size: 4096 + - Name: .text2 + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x2000 + AddressAlign: 0x1000 + Size: 4096 + Content: "DEADBEEF" + - Name: .text3 + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x3000 + AddressAlign: 0x1000 + Size: 4096 +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_X, PF_R ] + Sections: + - Section: .text + - Section: .text2 + - Section: .text3 + +# Make sure that when we remove a section we overwrite it with zeros +# DATA: 0020000 00 00 00 00 + +#CHECK: SectionHeaderCount: 6 + +# CHECK: Sections [ +# CHECK: Section { +# CHECK-NEXT: Index: 0 +# CHECK-NEXT: Name: (0) +# CHECK-NEXT: Type: SHT_NULL (0x0) +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x0 +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 0 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 1 +# CHECK-NEXT: Name: .text +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_EXECINSTR +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x1000 +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 4096 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Name: .text3 +# CHECK-NEXT: Type: SHT_PROGBITS (0x1) +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_EXECINSTR +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x3000 +# CHECK-NEXT: Offset: 0x3000 +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 4096 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 3 +# CHECK-NEXT: Name: .symtab +# CHECK-NEXT: Type: SHT_SYMTAB (0x2) +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x0 +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: 4 +# CHECK-NEXT: Info: 1 +# CHECK-NEXT: AddressAlignment: 8 +# CHECK-NEXT: EntrySize: 24 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 4 +# CHECK-NEXT: Name: .strtab +# CHECK-NEXT: Type: SHT_STRTAB (0x3) +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x0 +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 1 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 5 +# CHECK-NEXT: Name: .shstrtab +# CHECK-NEXT: Type: SHT_STRTAB (0x3) +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x0 +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 1 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK-NEXT: ] + +#CHECK: ProgramHeaders [ +#CHECK-NEXT: ProgramHeader { +#CHECK-NEXT: Type: PT_LOAD (0x1) +#CHECK-NEXT: Offset: 0x1000 +#CHECK-NEXT: VirtualAddress: 0x0 +#CHECK-NEXT: PhysicalAddress: 0x0 +#CHECK-NEXT: FileSize: 12288 +#CHECK-NEXT: MemSize: 12288 +#CHECK-NEXT: Flags [ (0x5) +#CHECK-NEXT: PF_R (0x4) +#CHECK-NEXT: PF_X (0x1) +#CHECK-NEXT: ] +#CHECK-NEXT: Alignment: 4096 +#CHECK-NEXT: } +#CHECK-NEXT:] diff --git a/test/tools/llvm-objcopy/symtab-error-on-remove-strtab.test b/test/tools/llvm-objcopy/symtab-error-on-remove-strtab.test new file mode 100644 index 00000000000..d9603996d7f --- /dev/null +++ b/test/tools/llvm-objcopy/symtab-error-on-remove-strtab.test @@ -0,0 +1,11 @@ +# RUN: yaml2obj %s > %t +# RUN: not llvm-objcopy -R .strtab %t %t2 2>&1 >/dev/null | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 + +# CHECK: String table .strtab cannot be removed because it is referenced by the symbol table .symtab diff --git a/tools/llvm-objcopy/Object.cpp b/tools/llvm-objcopy/Object.cpp index 3e6606f7095..bb79e4269d4 100644 --- a/tools/llvm-objcopy/Object.cpp +++ b/tools/llvm-objcopy/Object.cpp @@ -37,6 +37,7 @@ void Segment::writeSegment(FileOutputBuffer &Out) const { std::copy(std::begin(Contents), std::end(Contents), Buf); } +void SectionBase::removeSectionReferences(const SectionBase *Sec) {} void SectionBase::initialize(SectionTableRef SecTable) {} void SectionBase::finalize() {} @@ -138,6 +139,19 @@ void SymbolTableSection::addSymbol(StringRef Name, uint8_t Bind, uint8_t Type, Size += this->EntrySize; } +void SymbolTableSection::removeSectionReferences(const SectionBase *Sec) { + if (SymbolNames == Sec) { + error("String table " + SymbolNames->Name + + " cannot be removed because it is referenced by the symbol table " + + this->Name); + } + auto Iter = + std::remove_if(std::begin(Symbols), std::end(Symbols), + [=](const SymPtr &Sym) { return Sym->DefinedIn == Sec; }); + Size -= (std::end(Symbols) - Iter) * this->EntrySize; + Symbols.erase(Iter, std::end(Symbols)); +} + void SymbolTableSection::initialize(SectionTableRef SecTable) { Size = 0; setStrTab(SecTable.getSectionOfType( @@ -195,7 +209,19 @@ void SymbolTableSectionImpl::writeSection( } template -void RelocationSectionBase::initialize(SectionTableRef SecTable) { +void RelocSectionWithSymtabBase::removeSectionReferences( + const SectionBase *Sec) { + if (Symbols == Sec) { + error("Symbol table " + Symbols->Name + " cannot be removed because it is " + "referenced by the relocation " + "section " + + this->Name); + } +} + +template +void RelocSectionWithSymtabBase::initialize( + SectionTableRef SecTable) { setSymTab(SecTable.getSectionOfType( Link, "Link field value " + Twine(Link) + " in section " + Name + " is invalid", @@ -210,7 +236,8 @@ void RelocationSectionBase::initialize(SectionTableRef SecTable) { setSection(nullptr); } -template void RelocationSectionBase::finalize() { +template +void RelocSectionWithSymtabBase::finalize() { this->Link = Symbols->Index; if (SecToApplyRel != nullptr) this->Info = SecToApplyRel->Index; @@ -249,6 +276,14 @@ void DynamicRelocationSection::writeSection(llvm::FileOutputBuffer &Out) const { Out.getBufferStart() + Offset); } +void SectionWithStrTab::removeSectionReferences(const SectionBase *Sec) { + if (StrTab == Sec) { + error("String table " + StrTab->Name + " cannot be removed because it is " + "referenced by the section " + + this->Name); + } +} + bool SectionWithStrTab::classof(const SectionBase *S) { return isa(S) || isa(S); } @@ -589,6 +624,41 @@ void Object::writeSectionData(FileOutputBuffer &Out) const { Section->writeSection(Out); } +template +void Object::removeSections( + std::function ToRemove) { + + auto Iter = std::stable_partition( + std::begin(Sections), std::end(Sections), [=](const SecPtr &Sec) { + if (ToRemove(*Sec)) + return false; + if (auto RelSec = dyn_cast(Sec.get())) + return !ToRemove(*RelSec->getSection()); + return true; + }); + if (SymbolTable != nullptr && ToRemove(*SymbolTable)) + SymbolTable = nullptr; + if (ToRemove(*SectionNames)) { + // Right now llvm-objcopy always outputs section headers. This will not + // always be the case. Eventully the section header table will become + // optional and if no section header is output then there dosn't need to be + // a section header string table. + error("Cannot remove " + SectionNames->Name + + " because it is the section header string table."); + } + // Now make sure there are no remaining references to the sections that will + // be removed. Sometimes it is impossible to remove a reference so we emit + // an error here instead. + for (auto &RemoveSec : make_range(Iter, std::end(Sections))) { + for (auto &Segment : Segments) + Segment->removeSection(RemoveSec.get()); + for (auto &KeepSec : make_range(std::begin(Sections), Iter)) + KeepSec->removeSectionReferences(RemoveSec.get()); + } + // Now finally get rid of them all togethor. + Sections.erase(Iter, std::end(Sections)); +} + template void ELFObject::sortSections() { // Put all sections in offset order. Maintain the ordering as closely as // possible while meeting that demand however. @@ -692,7 +762,8 @@ template void ELFObject::finalize() { this->SectionNames->addString(Section->Name); } // Make sure we add the names of all the symbols. - this->SymbolTable->addSymbolNames(); + if (this->SymbolTable != nullptr) + this->SymbolTable->addSymbolNames(); sortSections(); assignOffsets(); diff --git a/tools/llvm-objcopy/Object.h b/tools/llvm-objcopy/Object.h index 398eed7e16c..3def0930a94 100644 --- a/tools/llvm-objcopy/Object.h +++ b/tools/llvm-objcopy/Object.h @@ -58,6 +58,7 @@ public: virtual ~SectionBase() {} virtual void initialize(SectionTableRef SecTable); virtual void finalize(); + virtual void removeSectionReferences(const SectionBase *Sec); template void writeHeader(llvm::FileOutputBuffer &Out) const; virtual void writeSection(llvm::FileOutputBuffer &Out) const = 0; }; @@ -98,7 +99,8 @@ public: return *Sections.begin(); return nullptr; } - void addSection(const SectionBase *sec) { Sections.insert(sec); } + void removeSection(const SectionBase *Sec) { Sections.erase(Sec); } + void addSection(const SectionBase *Sec) { Sections.insert(Sec); } template void writeHeader(llvm::FileOutputBuffer &Out) const; void writeSegment(llvm::FileOutputBuffer &Out) const; }; @@ -164,6 +166,8 @@ protected: std::vector> Symbols; StringTableSection *SymbolNames = nullptr; + typedef std::unique_ptr SymPtr; + public: void setStrTab(StringTableSection *StrTab) { SymbolNames = StrTab; } void addSymbol(llvm::StringRef Name, uint8_t Bind, uint8_t Type, @@ -171,6 +175,7 @@ public: uint64_t Sz); void addSymbolNames(); const Symbol *getSymbolByIndex(uint32_t Index) const; + void removeSectionReferences(const SectionBase *Sec) override; void initialize(SectionTableRef SecTable) override; void finalize() override; static bool classof(const SectionBase *S) { @@ -190,20 +195,49 @@ struct Relocation { uint32_t Type; }; -template class RelocationSectionBase : public SectionBase { -private: - SymTabType *Symbols = nullptr; +// All relocation sections denote relocations to apply to another section. +// However, some relocation sections use a dynamic symbol table and others use +// a regular symbol table. Because the types of the two symbol tables differ in +// our system (because they should behave differently) we can't uniformly +// represent all relocations with the same base class if we expose an interface +// that mentions the symbol table type. So we split the two base types into two +// different classes, one which handles the section the relocation is applied to +// and another which handles the symbol table type. The symbol table type is +// taken as a type parameter to the class (see RelocSectionWithSymtabBase). +class RelocationSectionBase : public SectionBase { +protected: SectionBase *SecToApplyRel = nullptr; public: - void setSymTab(SymTabType *StrTab) { Symbols = StrTab; } + const SectionBase *getSection() const { return SecToApplyRel; } void setSection(SectionBase *Sec) { SecToApplyRel = Sec; } + + static bool classof(const SectionBase *S) { + return S->Type == llvm::ELF::SHT_REL || S->Type == llvm::ELF::SHT_RELA; + } +}; + +// Takes the symbol table type to use as a parameter so that we can deduplicate +// that code between the two symbol table types. +template +class RelocSectionWithSymtabBase : public RelocationSectionBase { +private: + SymTabType *Symbols = nullptr; + +protected: + RelocSectionWithSymtabBase() {} + +public: + void setSymTab(SymTabType *StrTab) { Symbols = StrTab; } + + void removeSectionReferences(const SectionBase *Sec) override; void initialize(SectionTableRef SecTable) override; void finalize() override; }; template -class RelocationSection : public RelocationSectionBase { +class RelocationSection + : public RelocSectionWithSymtabBase { private: typedef typename ELFT::Rel Elf_Rel; typedef typename ELFT::Rela Elf_Rela; @@ -230,6 +264,7 @@ private: public: SectionWithStrTab(llvm::ArrayRef Data) : Section(Data) {} void setStrTab(StringTableSection *StringTable) { StrTab = StringTable; } + void removeSectionReferences(const SectionBase *Sec) override; void initialize(SectionTableRef SecTable) override; void finalize() override; static bool classof(const SectionBase *S); @@ -253,7 +288,7 @@ public: }; class DynamicRelocationSection - : public RelocationSectionBase { + : public RelocSectionWithSymtabBase { private: llvm::ArrayRef Contents; @@ -304,6 +339,7 @@ public: uint32_t Flags; Object(const llvm::object::ELFObjectFile &Obj); + void removeSections(std::function ToRemove); virtual size_t totalSize() const = 0; virtual void finalize() = 0; virtual void write(llvm::FileOutputBuffer &Out) const = 0; diff --git a/tools/llvm-objcopy/llvm-objcopy.cpp b/tools/llvm-objcopy/llvm-objcopy.cpp index 9b233951b8d..775c5ae42b6 100644 --- a/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/tools/llvm-objcopy/llvm-objcopy.cpp @@ -56,17 +56,24 @@ cl::opt OutputFilename(cl::Positional, cl::desc(""), cl::opt OutputFormat("O", cl::desc("set output format to one of the following:" "\n\tbinary")); +// TODO: make this a cl::list to support removing multiple sections +cl::opt ToRemove("remove-section", + cl::desc("Remove a specific section")); +cl::alias ToRemoveA("R", cl::desc("Alias for remove-section"), cl::aliasopt(ToRemove)); void CopyBinary(const ELFObjectFile &ObjFile) { std::unique_ptr Buffer; 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 Obj = llvm::make_unique>(ObjFile); + if (!ToRemove.empty()) { + Obj->removeSections( + [&](const SectionBase &Sec) { return ToRemove == Sec.Name; }); + } Obj->finalize(); ErrorOr> BufferOrErr = FileOutputBuffer::create(OutputFilename, Obj->totalSize(),