Index: llvm/lib/ObjectYAML/ELFYAML.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFYAML.cpp +++ llvm/lib/ObjectYAML/ELFYAML.cpp @@ -1648,12 +1648,12 @@ 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); Index: llvm/test/Object/X86/obj2yaml-dup-section-name.s =================================================================== --- llvm/test/Object/X86/obj2yaml-dup-section-name.s +++ 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: Index: llvm/test/Object/obj2yaml.test =================================================================== --- llvm/test/Object/obj2yaml.test +++ 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 Index: llvm/test/tools/obj2yaml/ELF/offset.yaml =================================================================== --- llvm/test/tools/obj2yaml/ELF/offset.yaml +++ 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 @@ 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. Index: llvm/test/tools/obj2yaml/ELF/section-headers.yaml =================================================================== --- /dev/null +++ llvm/test/tools/obj2yaml/ELF/section-headers.yaml @@ -0,0 +1,69 @@ +## Test how we dump objects where the order of sections in the +## section header table does not match their actual order. + +## Check we sort sections by their file offsets when dumping them. +## Check we emit the "SectionHeaderTable" key. + +# RUN: yaml2obj %s -o %t.o +# RUN: obj2yaml %t.o | FileCheck %s + +# CHECK: --- !ELF +# CHECK-NEXT: FileHeader: +# CHECK-NEXT: Class: ELFCLASS64 +# CHECK-NEXT: Data: ELFDATA2LSB +# CHECK-NEXT: Type: ET_EXEC +# CHECK-NEXT: Sections: +# CHECK-NEXT: - Name: .foo +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags: [ SHF_ALLOC ] +# CHECK-NEXT: Offset: 0x100 +# CHECK-NEXT: Content: '00' +# CHECK-NEXT: - Name: .bar +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags: [ SHF_ALLOC ] +# CHECK-NEXT: Address: 0x1 +# CHECK-NEXT: Offset: 0x200 +# CHECK-NEXT: Content: '0000' +# CHECK-NEXT: - Name: .zed +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags: [ SHF_ALLOC ] +# CHECK-NEXT: Address: 0x3 +# CHECK-NEXT: Offset: 0x300 +# CHECK-NEXT: Content: '000000' +# CHECK-NEXT: SectionHeaderTable: +# CHECK-NEXT: Sections: +# CHECK-NEXT: - Name: .zed +# CHECK-NEXT: - Name: .foo +# CHECK-NEXT: - Name: .bar +# CHECK-NEXT: - Name: .strtab +# CHECK-NEXT: - Name: .shstrtab +# CHECK-NEXT: ... + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC +Sections: + - Name: .foo + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Size: 0x1 + Offset: 0x100 + - Name: .bar + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Size: 0x2 + Offset: 0x200 + - Name: .zed + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Size: 0x3 + Offset: 0x300 +SectionHeaderTable: + Sections: + - Name: .zed + - Name: .foo + - Name: .bar + - Name: .strtab + - Name: .shstrtab Index: llvm/tools/obj2yaml/elf2yaml.cpp =================================================================== --- llvm/tools/obj2yaml/elf2yaml.cpp +++ llvm/tools/obj2yaml/elf2yaml.cpp @@ -359,6 +359,20 @@ 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 @@ // 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);