From ea8c8a50976fd5b9ca9799414bd3c412fce37f03 Mon Sep 17 00:00:00 2001 From: Georgii Rymar Date: Tue, 10 Nov 2020 16:33:57 +0300 Subject: [PATCH] [obj2yaml] - Teach tool to emit the "SectionHeaderTable" key and sort sections by file offset. Currently when we dump sections, we dump them in the order, which is specified in the sections header table. With that the order in the output might not match the order in the file. This patch starts sorting them by by file offsets when dumping. When the order in the section header table doesn't match the order in the file, we should emit the "SectionHeaderTable" key. This patch does it. Differential revision: https://reviews.llvm.org/D91249 --- llvm/lib/ObjectYAML/ELFYAML.cpp | 2 +- llvm/test/Object/X86/obj2yaml-dup-section-name.s | 8 +- llvm/test/Object/obj2yaml.test | 92 ++++++++++++++--------- llvm/test/tools/obj2yaml/ELF/offset.yaml | 93 ++++++++++++++++-------- llvm/tools/obj2yaml/elf2yaml.cpp | 29 ++++++++ 5 files changed, 153 insertions(+), 71 deletions(-) diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp index 5c60705..92b9c28 100644 --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -1648,12 +1648,12 @@ void MappingTraits::mapping(IO &IO, ELFYAML::Object &Object) { IO.setContext(&Object); IO.mapTag("!ELF", true); IO.mapRequired("FileHeader", Object.Header); - IO.mapOptional("SectionHeaderTable", Object.SectionHeaders); IO.mapOptional("ProgramHeaders", Object.ProgramHeaders); IO.mapOptional("Sections", Object.Chunks); IO.mapOptional("Symbols", Object.Symbols); IO.mapOptional("DynamicSymbols", Object.DynamicSymbols); IO.mapOptional("DWARF", Object.DWARF); + IO.mapOptional("SectionHeaderTable", Object.SectionHeaders); if (Object.DWARF) { Object.DWARF->IsLittleEndian = Object.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB); diff --git a/llvm/test/Object/X86/obj2yaml-dup-section-name.s b/llvm/test/Object/X86/obj2yaml-dup-section-name.s index 17fc7a4..9c0a2be 100644 --- a/llvm/test/Object/X86/obj2yaml-dup-section-name.s +++ b/llvm/test/Object/X86/obj2yaml-dup-section-name.s @@ -2,18 +2,18 @@ # RUN: obj2yaml %t.o | FileCheck %s # CHECK: Sections: +# CHECK: - Name: .text.foo{{$}} +# CHECK: - Name: '.text.foo (1)' # CHECK: - Name: .group{{$}} # CHECK: Members: # CHECK: - SectionOrType: .text.foo{{$}} # CHECK: - SectionOrType: .rela.text.foo{{$}} -# CHECK: - Name: .text.foo{{$}} -# CHECK: - Name: .rela.text.foo{{$}} -# CHECK: Info: .text.foo{{$}} # CHECK: - Name: '.group (1)' # CHECK: Members: # CHECK: - SectionOrType: '.text.foo (1)' # CHECK: - SectionOrType: '.rela.text.foo (1)' -# CHECK: - Name: '.text.foo (1)' +# CHECK: - Name: .rela.text.foo{{$}} +# CHECK: Info: .text.foo{{$}} # CHECK: - Name: '.rela.text.foo (1)' # CHECK: Info: '.text.foo (1)' # CHECK: Symbols: diff --git a/llvm/test/Object/obj2yaml.test b/llvm/test/Object/obj2yaml.test index 84044040..ea538a1 100644 --- a/llvm/test/Object/obj2yaml.test +++ b/llvm/test/Object/obj2yaml.test @@ -358,35 +358,10 @@ # ELF-MIPSEL-NEXT: Flags: [ SHF_ALLOC, SHF_EXECINSTR ] # ELF-MIPSEL-NEXT: AddressAlign: 0x4 # ELF-MIPSEL-NEXT: Content: 0000023C00004224E8FFBD271400BFAF1000B0AF218059000000018E000024240000198E09F8200321E000020000198E09F8200321E00002000002241000B08F1400BF8F0800E0031800BD27 -# ELF-MIPSEL-NEXT: - Name: .rel.text -# ELF-MIPSEL-NEXT: Type: SHT_REL -# ELF-MIPSEL-NEXT: Link: .symtab -# ELF-MIPSEL-NEXT: AddressAlign: 0x4 -# ELF-MIPSEL-NEXT: Offset: 0x434 -# ELF-MIPSEL-NEXT: Info: .text -# ELF-MIPSEL-NEXT: Relocations: -# ELF-MIPSEL-NEXT: - Symbol: _gp_disp -# ELF-MIPSEL-NEXT: Type: R_MIPS_HI16 -# ELF-MIPSEL-NEXT: - Offset: 0x4 -# ELF-MIPSEL-NEXT: Symbol: _gp_disp -# ELF-MIPSEL-NEXT: Type: R_MIPS_LO16 -# ELF-MIPSEL-NEXT: - Offset: 0x18 -# ELF-MIPSEL-NEXT: Symbol: '$.str' -# ELF-MIPSEL-NEXT: Type: R_MIPS_GOT16 -# ELF-MIPSEL-NEXT: - Offset: 0x1C -# ELF-MIPSEL-NEXT: Symbol: '$.str' -# ELF-MIPSEL-NEXT: Type: R_MIPS_LO16 -# ELF-MIPSEL-NEXT: - Offset: 0x20 -# ELF-MIPSEL-NEXT: Symbol: puts -# ELF-MIPSEL-NEXT: Type: R_MIPS_CALL16 -# ELF-MIPSEL-NEXT: - Offset: 0x2C -# ELF-MIPSEL-NEXT: Symbol: SomeOtherFunction -# ELF-MIPSEL-NEXT: Type: R_MIPS_CALL16 # ELF-MIPSEL-NEXT: - Name: .data # ELF-MIPSEL-NEXT: Type: SHT_PROGBITS # ELF-MIPSEL-NEXT: Flags: [ SHF_WRITE, SHF_ALLOC ] # ELF-MIPSEL-NEXT: AddressAlign: 0x4 -# ELF-MIPSEL-NEXT: Offset: 0x80 # ELF-MIPSEL-NEXT: - Name: .bss # ELF-MIPSEL-NEXT: Type: SHT_NOBITS # ELF-MIPSEL-NEXT: Flags: [ SHF_WRITE, SHF_ALLOC ] @@ -416,6 +391,29 @@ # ELF-MIPSEL-NEXT: GPRSize: REG_32 # ELF-MIPSEL-NEXT: CPR1Size: REG_32 # ELF-MIPSEL-NEXT: Flags1: [ ODDSPREG ] +# ELF-MIPSEL-NEXT: - Name: .rel.text +# ELF-MIPSEL-NEXT: Type: SHT_REL +# ELF-MIPSEL-NEXT: Link: .symtab +# ELF-MIPSEL-NEXT: AddressAlign: 0x4 +# ELF-MIPSEL-NEXT: Info: .text +# ELF-MIPSEL-NEXT: Relocations: +# ELF-MIPSEL-NEXT: - Symbol: _gp_disp +# ELF-MIPSEL-NEXT: Type: R_MIPS_HI16 +# ELF-MIPSEL-NEXT: - Offset: 0x4 +# ELF-MIPSEL-NEXT: Symbol: _gp_disp +# ELF-MIPSEL-NEXT: Type: R_MIPS_LO16 +# ELF-MIPSEL-NEXT: - Offset: 0x18 +# ELF-MIPSEL-NEXT: Symbol: '$.str' +# ELF-MIPSEL-NEXT: Type: R_MIPS_GOT16 +# ELF-MIPSEL-NEXT: - Offset: 0x1C +# ELF-MIPSEL-NEXT: Symbol: '$.str' +# ELF-MIPSEL-NEXT: Type: R_MIPS_LO16 +# ELF-MIPSEL-NEXT: - Offset: 0x20 +# ELF-MIPSEL-NEXT: Symbol: puts +# ELF-MIPSEL-NEXT: Type: R_MIPS_CALL16 +# ELF-MIPSEL-NEXT: - Offset: 0x2C +# ELF-MIPSEL-NEXT: Symbol: SomeOtherFunction +# ELF-MIPSEL-NEXT: Type: R_MIPS_CALL16 # ELF-MIPSEL-NEXT: Symbols: # ELF-MIPSEL-NEXT: - Name: trivial.ll # ELF-MIPSEL-NEXT: Type: STT_FILE @@ -461,6 +459,20 @@ # ELF-MIPSEL-NEXT: Binding: STB_GLOBAL # ELF-MIPSEL-NEXT: - Name: puts # ELF-MIPSEL-NEXT: Binding: STB_GLOBAL +# ELF-MIPSEL-NEXT: SectionHeaderTable: +# ELF-MIPSEL-NEXT: Sections: +# ELF-MIPSEL-NEXT: - Name: .text +# ELF-MIPSEL-NEXT: - Name: .rel.text +# ELF-MIPSEL-NEXT: - Name: .data +# ELF-MIPSEL-NEXT: - Name: .bss +# ELF-MIPSEL-NEXT: - Name: .mdebug.abi32 +# ELF-MIPSEL-NEXT: - Name: .rodata.str1.1 +# ELF-MIPSEL-NEXT: - Name: .reginfo +# ELF-MIPSEL-NEXT: - Name: .MIPS.abiflags +# ELF-MIPSEL-NEXT: - Name: .shstrtab +# ELF-MIPSEL-NEXT: - Name: .symtab +# ELF-MIPSEL-NEXT: - Name: .strtab +# ELF-MIPSEL-NEXT: ... # RUN: obj2yaml %p/Inputs/trivial-object-test.elf-mips64el | FileCheck %s --check-prefix ELF-MIPS64EL @@ -480,20 +492,10 @@ # ELF-MIPS64EL-NEXT: Flags: [ SHF_WRITE, SHF_ALLOC ] # ELF-MIPS64EL-NEXT: AddressAlign: 0x10 # ELF-MIPS64EL-NEXT: Content: '00000000000000000000000000000000' -# ELF-MIPS64EL-NEXT: - Name: .rela.data -# ELF-MIPS64EL-NEXT: Type: SHT_RELA -# ELF-MIPS64EL-NEXT: Link: .symtab -# ELF-MIPS64EL-NEXT: AddressAlign: 0x8 -# ELF-MIPS64EL-NEXT: Offset: 0x410 -# ELF-MIPS64EL-NEXT: Info: .data -# ELF-MIPS64EL-NEXT: Relocations: -# ELF-MIPS64EL-NEXT: - Symbol: zed -# ELF-MIPS64EL-NEXT: Type: R_MIPS_64 # ELF-MIPS64EL-NEXT: - Name: .bss # ELF-MIPS64EL-NEXT: Type: SHT_NOBITS # ELF-MIPS64EL-NEXT: Flags: [ SHF_WRITE, SHF_ALLOC ] # ELF-MIPS64EL-NEXT: AddressAlign: 0x10 -# ELF-MIPS64EL-NEXT: Offset: 0x50 # ELF-MIPS64EL-NEXT: - Name: .MIPS.options # ELF-MIPS64EL-NEXT: Type: SHT_MIPS_OPTIONS # ELF-MIPS64EL-NEXT: Flags: [ SHF_ALLOC, SHF_MIPS_NOSTRIP ] @@ -503,6 +505,14 @@ # ELF-MIPS64EL-NEXT: - Name: .pdr # ELF-MIPS64EL-NEXT: Type: SHT_PROGBITS # ELF-MIPS64EL-NEXT: AddressAlign: 0x4 +# ELF-MIPS64EL-NEXT: - Name: .rela.data +# ELF-MIPS64EL-NEXT: Type: SHT_RELA +# ELF-MIPS64EL-NEXT: Link: .symtab +# ELF-MIPS64EL-NEXT: AddressAlign: 0x8 +# ELF-MIPS64EL-NEXT: Info: .data +# ELF-MIPS64EL-NEXT: Relocations: +# ELF-MIPS64EL-NEXT: - Symbol: zed +# ELF-MIPS64EL-NEXT: Type: R_MIPS_64 # ELF-MIPS64EL-NEXT: Symbols: # ELF-MIPS64EL-NEXT: - Name: .text # ELF-MIPS64EL-NEXT: Type: STT_SECTION @@ -523,6 +533,18 @@ # ELF-MIPS64EL-NEXT: Section: .pdr # ELF-MIPS64EL-NEXT: - Name: zed # ELF-MIPS64EL-NEXT: Binding: STB_GLOBAL +# ELF-MIPS64EL-NEXT: SectionHeaderTable: +# ELF-MIPS64EL-NEXT: Sections: +# ELF-MIPS64EL-NEXT: - Name: .text +# ELF-MIPS64EL-NEXT: - Name: .data +# ELF-MIPS64EL-NEXT: - Name: .rela.data +# ELF-MIPS64EL-NEXT: - Name: .bss +# ELF-MIPS64EL-NEXT: - Name: .MIPS.options +# ELF-MIPS64EL-NEXT: - Name: .pdr +# ELF-MIPS64EL-NEXT: - Name: .shstrtab +# ELF-MIPS64EL-NEXT: - Name: .symtab +# ELF-MIPS64EL-NEXT: - Name: .strtab +# ELF-MIPS64EL-NEXT: ... # RUN: yaml2obj %s -o %t-x86-64 # RUN: obj2yaml %t-x86-64 | FileCheck %s --check-prefix ELF-X86-64 diff --git a/llvm/test/tools/obj2yaml/ELF/offset.yaml b/llvm/test/tools/obj2yaml/ELF/offset.yaml index 2dc04b6..1eb464c 100644 --- a/llvm/test/tools/obj2yaml/ELF/offset.yaml +++ b/llvm/test/tools/obj2yaml/ELF/offset.yaml @@ -5,37 +5,49 @@ # RUN: yaml2obj %s -o %t1.o # RUN: obj2yaml %t1.o | FileCheck %s --check-prefix=BASIC -# BASIC: --- !ELF -# BASIC-NEXT: FileHeader: -# BASIC-NEXT: Class: ELFCLASS64 -# BASIC-NEXT: Data: ELFDATA2LSB -# BASIC-NEXT: Type: ET_REL -# BASIC-NEXT: Sections: -# BASIC-NEXT: - Name: .foo1 -# BASIC-NEXT: Type: SHT_PROGBITS -# BASIC-NEXT: Content: '00' -# BASIC-NEXT: - Name: .foo2 -# BASIC-NEXT: Type: SHT_PROGBITS -# BASIC-NEXT: Content: '00' -# BASIC-NEXT: - Name: .foo3 -# BASIC-NEXT: Type: SHT_PROGBITS -# BASIC-NEXT: Content: '00' -# BASIC-NEXT: - Name: .bar1 -# BASIC-NEXT: Type: SHT_PROGBITS -# BASIC-NEXT: Offset: 0x100 -# BASIC-NEXT: Content: '00' -# BASIC-NEXT: - Name: .bar2 -# BASIC-NEXT: Type: SHT_PROGBITS -# BASIC-NEXT: AddressAlign: 0x10 -# BASIC-NEXT: Content: '00' -# BASIC-NEXT: - Name: .bar3 -# BASIC-NEXT: Type: SHT_PROGBITS -# BASIC-NEXT: AddressAlign: 0x10 -# BASIC-NEXT: Offset: 0x200 -# BASIC-NEXT: - Name: .bar4 -# BASIC-NEXT: Type: SHT_PROGBITS -# BASIC-NEXT: AddressAlign: 0x100000000 -# BASIC-NEXT: Offset: 0x210 +# BASIC: --- !ELF +# BASIC-NEXT: FileHeader: +# BASIC-NEXT: Class: ELFCLASS64 +# BASIC-NEXT: Data: ELFDATA2LSB +# BASIC-NEXT: Type: ET_REL +# BASIC-NEXT: Sections: +# BASIC-NEXT: - Name: .foo1 +# BASIC-NEXT: Type: SHT_PROGBITS +# BASIC-NEXT: Content: '00' +# BASIC-NEXT: - Name: .foo2 +# BASIC-NEXT: Type: SHT_PROGBITS +# BASIC-NEXT: Content: '00' +# BASIC-NEXT: - Name: .foo3 +# BASIC-NEXT: Type: SHT_PROGBITS +# BASIC-NEXT: Content: '00' +# BASIC-NEXT: - Name: .bar1 +# BASIC-NEXT: Type: SHT_PROGBITS +# BASIC-NEXT: Offset: 0x100 +# BASIC-NEXT: Content: '00' +# BASIC-NEXT: - Name: .bar2 +# BASIC-NEXT: Type: SHT_PROGBITS +# BASIC-NEXT: AddressAlign: 0x10 +# BASIC-NEXT: Content: '00' +# BASIC-NEXT: - Name: .bar3 +# BASIC-NEXT: Type: SHT_PROGBITS +# BASIC-NEXT: AddressAlign: 0x10 +# BASIC-NEXT: Offset: 0x200 +# BASIC-NEXT: - Name: .bar4 +# BASIC-NEXT: Type: SHT_PROGBITS +# BASIC-NEXT: AddressAlign: 0x100000000 +# BASIC-NEXT: Offset: 0x210 +# HEADERS-NEXT: SectionHeaderTable: +# HEADERS-NEXT: Sections: +# HEADERS-NEXT: - Name: .bar4 +# HEADERS-NEXT: - Name: .bar3 +# HEADERS-NEXT: - Name: .bar2 +# HEADERS-NEXT: - Name: .bar1 +# HEADERS-NEXT: - Name: .foo3 +# HEADERS-NEXT: - Name: .foo2 +# HEADERS-NEXT: - Name: .foo1 +# HEADERS-NEXT: - Name: .strtab +# HEADERS-NEXT: - Name: .shstrtab +# BASIC-NEXT: ... --- !ELF FileHeader: @@ -91,6 +103,25 @@ Sections: Type: SHT_PROGBITS AddressAlign: 0x100000000 Offset: 0x210 +SectionHeaderTable: + Sections: +## By default we have the same order of sections as defined by the "Sections" key. + - Name: [[SEC1=.foo1]] + - Name: [[SEC2=.foo2]] + - Name: [[SEC3=.foo3]] + - Name: [[SEC4=.bar1]] + - Name: [[SEC5=.bar2]] + - Name: [[SEC6=.bar3]] + - Name: [[SEC7=.bar4]] + - Name: .strtab + - Name: .shstrtab + +## In this case we change the order of sections in the section header table. +## Check that we still dump offsets correctly. + +# RUN: yaml2obj %s -DSEC1=.bar4 -DSEC2=.bar3 -DSEC3=.bar2 \ +# RUN: -DSEC4=.bar1 -DSEC5=.foo3 -DSEC6=.foo2 -DSEC7=.foo1 -o %t1-sechdr.o +# RUN: obj2yaml %t1-sechdr.o | FileCheck --check-prefixes=BASIC,HEADERS %s ## Show we dump the "Offset" key for the first section when ## it has an unexpected file offset. diff --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp index ea2f291..0a85179 100644 --- a/llvm/tools/obj2yaml/elf2yaml.cpp +++ b/llvm/tools/obj2yaml/elf2yaml.cpp @@ -359,6 +359,20 @@ template Expected ELFDumper::dump() { return ChunksOrErr.takeError(); std::vector> Chunks = std::move(*ChunksOrErr); + std::vector OriginalOrder; + if (!Chunks.empty()) + for (const std::unique_ptr &C : + makeArrayRef(Chunks).drop_front()) + OriginalOrder.push_back(cast(C.get())); + + // Sometimes the order of sections in the section header table does not match + // their actual order. Here we sort sections by the file offset. + llvm::stable_sort(Chunks, [&](const std::unique_ptr &A, + const std::unique_ptr &B) { + return Sections[cast(A.get())->OriginalSecNdx].sh_offset < + Sections[cast(B.get())->OriginalSecNdx].sh_offset; + }); + // Dump program headers. Expected> PhdrsOrErr = dumpProgramHeaders(Chunks); @@ -372,6 +386,21 @@ template Expected ELFDumper::dump() { // Dump DWARF sections. Y->DWARF = dumpDWARFSections(Chunks); + // We emit the "SectionHeaderTable" key when the order of sections in the + // sections header table doesn't match the file order. + const bool SectionsSorted = + llvm::is_sorted(Chunks, [&](const std::unique_ptr &A, + const std::unique_ptr &B) { + return cast(A.get())->OriginalSecNdx < + cast(B.get())->OriginalSecNdx; + }); + if (!SectionsSorted) { + Y->SectionHeaders.emplace(); + Y->SectionHeaders->Sections.emplace(); + for (ELFYAML::Section *S : OriginalOrder) + Y->SectionHeaders->Sections->push_back({S->Name}); + } + llvm::erase_if(Chunks, [this, &Y](const std::unique_ptr &C) { const ELFYAML::Section &S = cast(*C.get()); return !shouldPrintSection(S, Sections[S.OriginalSecNdx], Y->DWARF); -- 2.7.4