diff --git a/llvm/test/tools/llvm-objcopy/ELF/compress-debug-sections-zlib-gnu.test b/llvm/test/tools/llvm-objcopy/ELF/compress-debug-sections-zlib-gnu.test --- a/llvm/test/tools/llvm-objcopy/ELF/compress-debug-sections-zlib-gnu.test +++ b/llvm/test/tools/llvm-objcopy/ELF/compress-debug-sections-zlib-gnu.test @@ -14,8 +14,7 @@ # CHECK: .debug_foo: # CHECK-NEXT: 0000 00000000 00000000 -# CHECK-HEADER: Index: 1 -# CHECK-HEADER-NEXT: Name: .debug_foo +# CHECK-HEADER: Name: .debug_foo # CHECK-HEADER-NEXT: Type: SHT_PROGBITS # CHECK-HEADER-NEXT: Flags [ # CHECK-HEADER-NEXT: ] @@ -27,9 +26,8 @@ # CHECK-COMPRESSED: ZLIB # CHECK-COMPRESSED: .notdebug_foo: -# CHECK-FLAGS-NOT: Name: .debug_foo -# CHECK-FLAGS: Index: 1 -# CHECK-FLAGS-NEXT: Name: .zdebug_foo +# CHECK-FLAGS-NOT: Name: .debug_foo +# CHECK-FLAGS: Name: .zdebug_foo # CHECK-FLAGS-NEXT: Type: SHT_PROGBITS # CHECK-FLAGS-NEXT: Flags [ # CHECK-FLAGS-NEXT: ] @@ -49,11 +47,6 @@ # CHECK-FLAGS-NEXT: Type: SHT_RELA # CHECK-FLAGS-NEXT: Flags [ # CHECK-FLAGS-NEXT: ] -# CHECK-FLAGS-NEXT: Address: -# CHECK-FLAGS-NEXT: Offset: -# CHECK-FLAGS-NEXT: Size: -# CHECK-FLAGS-NEXT: Link: -# CHECK-FLAGS-NEXT: Info: 1 # CHECK-FLAGS: Relocations [ # CHECK-FLAGS-NEXT: .rela.debug_foo { diff --git a/llvm/test/tools/llvm-objcopy/ELF/compress-debug-sections-zlib.test b/llvm/test/tools/llvm-objcopy/ELF/compress-debug-sections-zlib.test --- a/llvm/test/tools/llvm-objcopy/ELF/compress-debug-sections-zlib.test +++ b/llvm/test/tools/llvm-objcopy/ELF/compress-debug-sections-zlib.test @@ -14,8 +14,7 @@ # CHECK: .debug_foo: # CHECK-NEXT: 0000 00000000 00000000 -# CHECK-HEADER: Index: 1 -# CHECK-HEADER-NEXT: Name: .debug_foo +# CHECK-HEADER: Name: .debug_foo # CHECK-HEADER-NEXT: Type: SHT_PROGBITS # CHECK-HEADER-NEXT: Flags [ # CHECK-HEADER-NEXT: ] @@ -26,8 +25,7 @@ # CHECK-COMPRESSED: .debug_foo: # CHECK-COMPRESSED: .notdebug_foo: -# CHECK-FLAGS: Index: 1 -# CHECK-FLAGS-NEXT: Name: .debug_foo +# CHECK-FLAGS: Name: .debug_foo # CHECK-FLAGS-NEXT: Type: SHT_PROGBITS # CHECK-FLAGS-NEXT: Flags [ # CHECK-FLAGS-NEXT: SHF_COMPRESSED @@ -53,7 +51,6 @@ # CHECK-FLAGS-NEXT: Offset: # CHECK-FLAGS-NEXT: Size: # CHECK-FLAGS-NEXT: Link: -# CHECK-FLAGS-NEXT: Info: 1 # CHECK-FLAGS: Relocations [ # CHECK-FLAGS-NEXT: .rela.debug_foo { diff --git a/llvm/test/tools/llvm-objcopy/ELF/group-reorder.test b/llvm/test/tools/llvm-objcopy/ELF/group-reorder.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/ELF/group-reorder.test @@ -0,0 +1,64 @@ +# RUN: yaml2obj %s > %t.o +# RUN: llvm-objcopy %t.o %t.2.o +# RUN: llvm-readelf --elf-section-groups --sections %t.o | FileCheck %s --check-prefix=IN +# RUN: llvm-readelf --elf-section-groups --sections %t.2.o | FileCheck %s --check-prefix=OUT + +# In this test, .group gets moved to the beginning. Run readelf -gS on input as +# well as output to make sure it really moved, as well as to verify that we +# aren't purely sorting based on offsets (it gets moved to the beginning +# despite having a larger offset). + +# IN: There are 7 section headers, starting at offset 0x40: +# IN: [Nr] Name Type Address Off Size +# IN-NEXT: [ 0] NULL 0000000000000000 000000 000000 +# IN-NEXT: [ 1] .foo PROGBITS 0000000000000000 000200 000040 +# IN-NEXT: [ 2] .group GROUP 0000000000000000 000240 000008 +# IN-NEXT: [ 3] .bar PROGBITS 0000000000000000 000248 000040 + +# IN: COMDAT group section [ 2] `.group' [bar] contains 1 sections: +# IN-NEXT: [Index] Name +# IN-NEXT: [ 3] .bar + +# OUT: There are 7 section headers, starting at offset 0x160: +# OUT: [Nr] Name Type Address Off Size +# OUT-NEXT: [ 0] NULL 0000000000000000 000000 000000 +# OUT-NEXT: [ 1] .group GROUP 0000000000000000 000040 000008 +# OUT-NEXT: [ 2] .foo PROGBITS 0000000000000000 000048 000040 +# OUT-NEXT: [ 3] .bar PROGBITS 0000000000000000 000088 000040 + +# OUT: COMDAT group section [ 1] `.group' [bar] contains 1 sections: +# OUT-NEXT: [Index] Name +# OUT-NEXT: [ 3] .bar + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .foo + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Size: 64 + - Name: .group + Type: SHT_GROUP + Link: .symtab + Info: bar + Members: + - SectionOrType: GRP_COMDAT + - SectionOrType: .bar + - Name: .bar + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ] + Size: 64 +Symbols: + - Name: .foo + Type: STT_SECTION + Section: .foo + - Name: .bar + Type: STT_SECTION + Section: .bar + - Name: bar + Type: STT_FUNC + Section: .foo diff --git a/llvm/test/tools/llvm-objcopy/ELF/strip-dwo-groups.test b/llvm/test/tools/llvm-objcopy/ELF/strip-dwo-groups.test --- a/llvm/test/tools/llvm-objcopy/ELF/strip-dwo-groups.test +++ b/llvm/test/tools/llvm-objcopy/ELF/strip-dwo-groups.test @@ -27,14 +27,14 @@ // Link, Info and the content of this section. CHECK: Name: .group (179) -CHECK-NEXT: Index: 17 +CHECK-NEXT: Index: 1{{$}} CHECK-NEXT: Link: 19 CHECK-NEXT: Info: 14 -CHECK: .text._ZN1SIiE4getXEv (2) +CHECK: .text._ZN1SIiE4getXEv CHECK: Name: .group (179) -CHECK-NEXT: Index: 18 +CHECK-NEXT: Index: 2{{$}} CHECK-NEXT: Link: 19 CHECK-NEXT: Info: 13 -CHECK: .text._ZN1SIdE4getXEv (4) -CHECK-NEXT: .rela.text._ZN1SIdE4getXEv (21) +CHECK: .text._ZN1SIdE4getXEv +CHECK-NEXT: .rela.text._ZN1SIdE4getXEv diff --git a/llvm/tools/llvm-objcopy/ELF/Object.cpp b/llvm/tools/llvm-objcopy/ELF/Object.cpp --- a/llvm/tools/llvm-objcopy/ELF/Object.cpp +++ b/llvm/tools/llvm-objcopy/ELF/Object.cpp @@ -1637,9 +1637,15 @@ } void Object::sortSections() { - // Put all sections in offset order. Maintain the ordering as closely as - // possible while meeting that demand however. + // Use stable_sort to maintain the original ordering as closely as possible. llvm::stable_sort(Sections, [](const SecPtr &A, const SecPtr &B) { + // Put SHT_GROUP sections first, since group section headers must come + // before the sections they contain. This also matches what GNU objcopy + // does. + if (A->Type != B->Type && + (A->Type == ELF::SHT_GROUP || B->Type == ELF::SHT_GROUP)) + return A->Type == ELF::SHT_GROUP; + // For all other sections, sort by offset order. return A->OriginalOffset < B->OriginalOffset; }); }