]> granicus.if.org Git - llvm/commitdiff
[llvm-objcopy] Fix SHT_GROUP ordering.
authorJordan Rupprecht <rupprecht@google.com>
Mon, 10 Jun 2019 18:35:01 +0000 (18:35 +0000)
committerJordan Rupprecht <rupprecht@google.com>
Mon, 10 Jun 2019 18:35:01 +0000 (18:35 +0000)
Summary:
When llvm-objcopy sorts sections during finalization, it only sorts based on the offset, which can cause the group section to come after the sections it contains. This causes link failures when using gold to link objects created by llvm-objcopy.

Fix this for now by copying GNU objcopy's behavior of placing SHT_GROUP sections first. In the future, we may want to remove this sorting entirely to more closely preserve the input file layout.

This fixes https://bugs.llvm.org/show_bug.cgi?id=42052.

Reviewers: jakehehrlich, jhenderson, MaskRay, espindola, alexshap

Reviewed By: MaskRay

Subscribers: phuongtrang148993, emaste, arichardson, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D62620

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@362973 91177308-0d34-0410-b5e6-96231b3b80d8

test/tools/llvm-objcopy/ELF/compress-debug-sections-zlib-gnu.test
test/tools/llvm-objcopy/ELF/compress-debug-sections-zlib.test
test/tools/llvm-objcopy/ELF/group-reorder.test [new file with mode: 0644]
test/tools/llvm-objcopy/ELF/strip-dwo-groups.test
tools/llvm-objcopy/ELF/Object.cpp

index 2abd22e5781eb67846d02e5fa14aeb8a5e4ed841..d2811b9ffad1ef7f9c938f18b64468987ada255a 100644 (file)
@@ -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: ]
 # 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 {
index 374a8264af0528cb5ccfeaa53647307f5d720347..481071a9829cef0f96c0b840719e429c017d5a23 100644 (file)
@@ -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/test/tools/llvm-objcopy/ELF/group-reorder.test b/test/tools/llvm-objcopy/ELF/group-reorder.test
new file mode 100644 (file)
index 0000000..25d0cd5
--- /dev/null
@@ -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
index 724b0635b91b7d14e024979ac0507e98ea591c15..6404bba2461c4635b3e85deefc9dd9868f5d3f1e 100644 (file)
 // 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
index 89f25a4f321cb56c133417644e11d9007754979b..05f2164fb8d776e02586bf9785ecadf3d173ce6e 100644 (file)
@@ -1668,9 +1668,15 @@ Error Object::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) {
 }
 
 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;
   });
 }