From d5ba5901b903e6fa04a632131eedf3101c489c81 Mon Sep 17 00:00:00 2001 From: James Henderson Date: Thu, 14 Mar 2019 11:47:41 +0000 Subject: [PATCH] [llvm-objcopy]Don't implicitly strip sections in segments This patch changes llvm-objcopy's behaviour to not strip sections that are in segments, if they otherwise would be due to a stripping operation (--strip-all, --strip-sections, --strip-non-alloc). This preserves the segment contents. It does not change the behaviour of --strip-all-gnu (although we could choose to do so), because GNU objcopy's behaviour in this case seems to be to strip the section, nor does it prevent removing of sections in segments with --remove-section (if a user REALLY wants to remove a section, we should probably let them, although I could be persuaded that warning might be appropriate). Tests have been added to show this latter behaviour. This fixes https://bugs.llvm.org/show_bug.cgi?id=41006. Reviewed by: grimar, rupprecht, jakehehrlich Differential Revision: https://reviews.llvm.org/D59293 This is a reland of r356129, attempting to fix greendragon failures due to a suspected compatibility issue with od on the greendragon bots versus other versions. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@356136 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../ELF/remove-section-in-segment.test | 47 +++++++++++++++++++ .../tools/llvm-objcopy/ELF/strip-all-gnu.test | 19 +++++++- test/tools/llvm-objcopy/ELF/strip-all.test | 12 ++++- .../llvm-objcopy/ELF/strip-non-alloc.test | 12 ++++- .../llvm-objcopy/ELF/strip-sections.test | 11 +++-- tools/llvm-objcopy/ELF/ELFObjcopy.cpp | 6 ++- tools/llvm-objcopy/ObjcopyOpts.td | 19 ++++---- tools/llvm-objcopy/StripOpts.td | 7 ++- 8 files changed, 112 insertions(+), 21 deletions(-) create mode 100644 test/tools/llvm-objcopy/ELF/remove-section-in-segment.test diff --git a/test/tools/llvm-objcopy/ELF/remove-section-in-segment.test b/test/tools/llvm-objcopy/ELF/remove-section-in-segment.test new file mode 100644 index 00000000000..036c9541f30 --- /dev/null +++ b/test/tools/llvm-objcopy/ELF/remove-section-in-segment.test @@ -0,0 +1,47 @@ +# Show that --remove-section removes sections in segments. + +# RUN: yaml2obj %s -o %t + +# Validate the offsets for the later parts of the test. +# RUN: llvm-objcopy %t %t.copy +# Skip to the start of the sections, which should be immediately after the +# program header table (i.e. sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) == 120). +# RUN: od -t x1 -N 16 -j 120 %t.copy | FileCheck %s --check-prefix=COPY + +# COPY: 11 22 33 44 55 66 77 88 + +# RUN: llvm-objcopy --remove-section non_alloc %t %t.nonalloc +# RUN: llvm-readelf --sections %t.nonalloc | FileCheck %s --check-prefix=NONALLOC-SHDRS +# RUN: od -t x1 -N 16 -j 120 %t.nonalloc | FileCheck %s --check-prefix=NONALLOC-BYTES + +# NONALLOC-SHDRS-NOT: non_alloc +# NONALLOC-BYTES: 11 22 33 44 00 00 00 00 + +# RUN: llvm-objcopy --remove-section shf_alloc %t %t.alloc +# RUN: llvm-readelf --sections %t.alloc | FileCheck %s --check-prefix=ALLOC-SHDRS +# RUN: od -t x1 -N 16 -j 120 %t.alloc | FileCheck %s --check-prefix=ALLOC-BYTES + +# ALLOC-SHDRS-NOT: shf_alloc +# ALLOC-BYTES: 00 00 00 00 55 66 77 88 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: shf_alloc + Type: SHT_PROGBITS + Flags: [SHF_ALLOC] + Content: '11223344' + - Name: non_alloc + Type: SHT_PROGBITS + Flags: [] + Content: '55667788' +ProgramHeaders: + # Use an arbitrary segment type to show that the segment type is unimportant. + - Type: 0x61234567 + Sections: + - Section: shf_alloc + - Section: non_alloc diff --git a/test/tools/llvm-objcopy/ELF/strip-all-gnu.test b/test/tools/llvm-objcopy/ELF/strip-all-gnu.test index 8253526d23c..ea2cb635aec 100644 --- a/test/tools/llvm-objcopy/ELF/strip-all-gnu.test +++ b/test/tools/llvm-objcopy/ELF/strip-all-gnu.test @@ -1,10 +1,15 @@ # RUN: yaml2obj %s > %t -# RUN: cp %t %t1 # RUN: llvm-objcopy --strip-all-gnu %t %t2 # RUN: llvm-strip --strip-all-gnu %t -o %t3 # RUN: llvm-readobj --file-headers --sections %t2 | FileCheck %s # RUN: cmp %t2 %t3 +# Show that the debug section in a segment was removed, to match GNU. +# First validate that the offset in use is correct. +# RUN: llvm-objcopy %t %t4 +# RUN: od -t x1 -N 4 -j 120 %t4 | FileCheck %s --check-prefix=COPY-BYTES +# RUN: od -t x1 -N 4 -j 120 %t2 | FileCheck %s --check-prefix=STRIP-BYTES + !ELF FileHeader: Class: ELFCLASS64 @@ -12,6 +17,10 @@ FileHeader: Type: ET_REL Machine: EM_X86_64 Sections: + - Name: .debug_in_segment + Type: SHT_PROGBITS + Flags: [ ] + Content: "deadbeef" - Name: .dynstr Type: SHT_STRTAB Flags: [ SHF_ALLOC ] @@ -45,6 +54,11 @@ Sections: - Name: .rela.text Type: SHT_RELA Info: .text +ProgramHeaders: + # Use an arbitrary segment type to show that the segment type is unimportant. + - Type: 0x61234567 + Sections: + - Section: .debug_in_segment # CHECK: SectionHeaderCount: 8 @@ -55,3 +69,6 @@ Sections: # CHECK: Name: .comment # CHECK: Name: .random_section_name # CHECK: Name: .shstrtab + +# COPY-BYTES: de ad be ef +# STRIP-BYTES: 00 00 00 00 diff --git a/test/tools/llvm-objcopy/ELF/strip-all.test b/test/tools/llvm-objcopy/ELF/strip-all.test index 87388e09747..32a801d7a6c 100644 --- a/test/tools/llvm-objcopy/ELF/strip-all.test +++ b/test/tools/llvm-objcopy/ELF/strip-all.test @@ -57,6 +57,10 @@ FileHeader: Type: ET_REL Machine: EM_X86_64 Sections: + - Name: non_alloc_in_segment + Type: SHT_PROGBITS + Flags: [ ] + Size: 4 - Name: .bss Type: SHT_NOBITS Flags: [ SHF_ALLOC ] @@ -68,9 +72,15 @@ Sections: Flags: [ ] - Name: .gnu.warning.foo Type: SHT_PROGBITS +ProgramHeaders: + # Use an arbitrary segment type to show that the segment type is unimportant. + - Type: 0x61234567 + Sections: + - Section: non_alloc_in_segment -# CHECK: SectionHeaderCount: 5 +# CHECK: SectionHeaderCount: 6 +# CHECK: Name: non_alloc_in_segment # CHECK: Name: .bss # CHECK: Name: .text # CHECK: Name: .gnu.warning.foo diff --git a/test/tools/llvm-objcopy/ELF/strip-non-alloc.test b/test/tools/llvm-objcopy/ELF/strip-non-alloc.test index 8db732147d3..1f082bf4734 100644 --- a/test/tools/llvm-objcopy/ELF/strip-non-alloc.test +++ b/test/tools/llvm-objcopy/ELF/strip-non-alloc.test @@ -9,6 +9,10 @@ FileHeader: Type: ET_REL Machine: EM_X86_64 Sections: + - Name: non_alloc_in_segment + Type: SHT_PROGBITS + Flags: [ ] + Size: 4 - Name: .bss Type: SHT_NOBITS Flags: [ SHF_ALLOC ] @@ -18,9 +22,15 @@ Sections: - Name: .blarg Type: SHT_PROGBITS Flags: [ ] +ProgramHeaders: + # Use an arbitrary segment type to show that the segment type is unimportant. + - Type: 0x61234567 + Sections: + - Section: non_alloc_in_segment -# CHECK: SectionHeaderCount: 4 +# CHECK: SectionHeaderCount: 5 +# CHECK: Name: non_alloc_in_segment # CHECK: Name: .bss # CHECK: Name: .text # CHECK: Name: .shstrtab diff --git a/test/tools/llvm-objcopy/ELF/strip-sections.test b/test/tools/llvm-objcopy/ELF/strip-sections.test index 2dee6e2808d..244cdb31ba9 100644 --- a/test/tools/llvm-objcopy/ELF/strip-sections.test +++ b/test/tools/llvm-objcopy/ELF/strip-sections.test @@ -15,13 +15,18 @@ Sections: Flags: [ SHF_ALLOC, SHF_EXECINSTR ] AddressAlign: 0x0000000000001000 Content: "DEADBEEF" + - Name: .non_alloc_in_segment + Type: SHT_PROGBITS + Flags: [ ] + Content: "CAFEBABE" ProgramHeaders: - Type: PT_LOAD Flags: [ PF_X, PF_R ] Sections: - Section: .text + - Section: .non_alloc_in_segment -#DATA: 0010000 de ad be ef +#DATA: 0010000 de ad be ef ca fe ba be #CHECK: ElfHeader { #CHECK-NEXT: Ident { @@ -55,8 +60,8 @@ ProgramHeaders: #CHECK-NEXT: Offset: 0x1000 #CHECK-NEXT: VirtualAddress: 0x0 #CHECK-NEXT: PhysicalAddress: 0x0 -#CHECK-NEXT: FileSize: 4 -#CHECK-NEXT: MemSize: 4 +#CHECK-NEXT: FileSize: 8 +#CHECK-NEXT: MemSize: 8 #CHECK-NEXT: Flags [ (0x5) #CHECK-NEXT: PF_R (0x4) #CHECK-NEXT: PF_X (0x1) diff --git a/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/tools/llvm-objcopy/ELF/ELFObjcopy.cpp index cbf6a3d2777..250eeea1c81 100644 --- a/tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ b/tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -403,7 +403,7 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj, if (Config.StripSections) { RemovePred = [RemovePred](const SectionBase &Sec) { - return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0; + return RemovePred(Sec) || Sec.ParentSegment == nullptr; }; } @@ -419,7 +419,7 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj, return true; if (&Sec == Obj.SectionNames) return false; - return (Sec.Flags & SHF_ALLOC) == 0; + return (Sec.Flags & SHF_ALLOC) == 0 && Sec.ParentSegment == nullptr; }; if (Config.StripAll) @@ -430,6 +430,8 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj, return false; if (StringRef(Sec.Name).startswith(".gnu.warning")) return false; + if (Sec.ParentSegment != nullptr) + return false; return (Sec.Flags & SHF_ALLOC) == 0; }; diff --git a/tools/llvm-objcopy/ObjcopyOpts.td b/tools/llvm-objcopy/ObjcopyOpts.td index 44fd01cf4ab..a5f7119e328 100644 --- a/tools/llvm-objcopy/ObjcopyOpts.td +++ b/tools/llvm-objcopy/ObjcopyOpts.td @@ -103,10 +103,9 @@ defm set_section_flags "rom, share, contents, merge, strings.">, MetaVarName<"section=flag1[,flag2,...]">; -def strip_all - : Flag<["-", "--"], "strip-all">, - HelpText< - "Remove non-allocated sections other than .gnu.warning* sections">; +def strip_all : Flag<["-", "--"], "strip-all">, + HelpText<"Remove non-allocated sections outside segments. " + ".gnu.warning* sections are not removed">; def S : Flag<["-"], "S">, Alias; def strip_all_gnu : Flag<["-", "--"], "strip-all-gnu">, HelpText<"Compatible with GNU objcopy's --strip-all">; @@ -116,13 +115,15 @@ def g : Flag<["-"], "g">, Alias, HelpText<"Alias for --strip-debug">; def strip_dwo : Flag<["-", "--"], "strip-dwo">, HelpText<"Remove all DWARF .dwo sections from file">; -def strip_sections : Flag<["-", "--"], "strip-sections">, - HelpText<"Remove all section headers">; -def strip_non_alloc : Flag<["-", "--"], "strip-non-alloc">, - HelpText<"Remove all non-allocated sections">; +def strip_sections + : Flag<["-", "--"], "strip-sections">, + HelpText<"Remove all section headers and all sections not in segments">; +def strip_non_alloc + : Flag<["-", "--"], "strip-non-alloc">, + HelpText<"Remove all non-allocated sections outside segments">; def strip_unneeded : Flag<["-", "--"], "strip-unneeded">, HelpText<"Remove all symbols not needed by relocations">; -defm strip_unneeded_symbol +defm strip_unneeded_symbol : Eq<"strip-unneeded-symbol", "Remove symbol if it is not needed by relocations">, MetaVarName<"symbol">; diff --git a/tools/llvm-objcopy/StripOpts.td b/tools/llvm-objcopy/StripOpts.td index c3f351992a0..40b043a7630 100644 --- a/tools/llvm-objcopy/StripOpts.td +++ b/tools/llvm-objcopy/StripOpts.td @@ -31,10 +31,9 @@ def preserve_dates : Flag<["-", "--"], "preserve-dates">, HelpText<"Preserve access and modification timestamps">; def p : Flag<["-"], "p">, Alias; -def strip_all - : Flag<["-", "--"], "strip-all">, - HelpText< - "Remove non-allocated sections other than .gnu.warning* sections">; +def strip_all : Flag<["-", "--"], "strip-all">, + HelpText<"Remove non-allocated sections outside segments. " + ".gnu.warning* sections are not removed">; def s : Flag<["-"], "s">, Alias; def strip_all_gnu : Flag<["-", "--"], "strip-all-gnu">, -- 2.40.0