Skip to content

Commit

Permalink
[obj2yaml] - Teach tool to emit the "SectionHeaderTable" key and sort…
Browse files Browse the repository at this point in the history
… 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
  • Loading branch information
Georgii Rymar committed Dec 1, 2020
1 parent 398b729 commit ea8c8a5
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 71 deletions.
2 changes: 1 addition & 1 deletion llvm/lib/ObjectYAML/ELFYAML.cpp
Expand Up @@ -1648,12 +1648,12 @@ void MappingTraits<ELFYAML::Object>::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);
Expand Down
8 changes: 4 additions & 4 deletions llvm/test/Object/X86/obj2yaml-dup-section-name.s
Expand Up @@ -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:
Expand Down
92 changes: 57 additions & 35 deletions llvm/test/Object/obj2yaml.test
Expand Up @@ -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 ]
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand All @@ -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 ]
Expand All @@ -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
Expand All @@ -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
Expand Down
93 changes: 62 additions & 31 deletions llvm/test/tools/obj2yaml/ELF/offset.yaml
Expand Up @@ -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:
Expand Down Expand Up @@ -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.
Expand Down
29 changes: 29 additions & 0 deletions llvm/tools/obj2yaml/elf2yaml.cpp
Expand Up @@ -359,6 +359,20 @@ template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
return ChunksOrErr.takeError();
std::vector<std::unique_ptr<ELFYAML::Chunk>> Chunks = std::move(*ChunksOrErr);

std::vector<ELFYAML::Section *> OriginalOrder;
if (!Chunks.empty())
for (const std::unique_ptr<ELFYAML::Chunk> &C :
makeArrayRef(Chunks).drop_front())
OriginalOrder.push_back(cast<ELFYAML::Section>(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<ELFYAML::Chunk> &A,
const std::unique_ptr<ELFYAML::Chunk> &B) {
return Sections[cast<ELFYAML::Section>(A.get())->OriginalSecNdx].sh_offset <
Sections[cast<ELFYAML::Section>(B.get())->OriginalSecNdx].sh_offset;
});

// Dump program headers.
Expected<std::vector<ELFYAML::ProgramHeader>> PhdrsOrErr =
dumpProgramHeaders(Chunks);
Expand All @@ -372,6 +386,21 @@ template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::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<ELFYAML::Chunk> &A,
const std::unique_ptr<ELFYAML::Chunk> &B) {
return cast<ELFYAML::Section>(A.get())->OriginalSecNdx <
cast<ELFYAML::Section>(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<ELFYAML::Chunk> &C) {
const ELFYAML::Section &S = cast<ELFYAML::Section>(*C.get());
return !shouldPrintSection(S, Sections[S.OriginalSecNdx], Y->DWARF);
Expand Down

0 comments on commit ea8c8a5

Please sign in to comment.