[llvm-objcopy] Fix SHT_GROUP ordering.

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

llvm-svn: 362973
This commit is contained in:
Jordan Rupprecht 2019-06-10 18:35:01 +00:00
parent b0f98d3422
commit f8f9d65f85
5 changed files with 82 additions and 22 deletions

View 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: ]
@ -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 {

View 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 {

View File

@ -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

View File

@ -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

View 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;
});
}