diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h --- a/llvm/include/llvm/Object/ELF.h +++ b/llvm/include/llvm/Object/ELF.h @@ -14,6 +14,7 @@ #define LLVM_OBJECT_ELF_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/ELF.h" @@ -182,6 +183,7 @@ private: StringRef Buf; std::vector FakeSections; + SmallString<0> FakeSectionStrings; ELFFile(StringRef Object); @@ -648,8 +650,11 @@ Index = Sections[0].sh_link; } - if (!Index) // no section string table. - return ""; + // There is no section name string table. Return FakeSectionStrings which + // is non-empty if we have created fake sections. + if (!Index) + return FakeSectionStrings; + if (Index >= Sections.size()) return createError("section header string table index " + Twine(Index) + " does not exist"); @@ -770,8 +775,9 @@ if (!PhdrsOrErr) return; - for (auto Phdr : *PhdrsOrErr) { - if (!(Phdr.p_type & ELF::PT_LOAD) || !(Phdr.p_flags & ELF::PF_X)) + FakeSectionStrings += '\0'; + for (auto [Idx, Phdr] : llvm::enumerate(*PhdrsOrErr)) { + if (Phdr.p_type != ELF::PT_LOAD || !(Phdr.p_flags & ELF::PF_X)) continue; Elf_Shdr FakeShdr = {}; FakeShdr.sh_type = ELF::SHT_PROGBITS; @@ -779,6 +785,10 @@ FakeShdr.sh_addr = Phdr.p_vaddr; FakeShdr.sh_size = Phdr.p_memsz; FakeShdr.sh_offset = Phdr.p_offset; + // Create a section name based on the p_type and index. + FakeShdr.sh_name = FakeSectionStrings.size(); + FakeSectionStrings += ("PT_LOAD#" + Twine(Idx)).str(); + FakeSectionStrings += '\0'; FakeSections.push_back(FakeShdr); } } diff --git a/llvm/test/Object/objdump-no-sectionheaders.test b/llvm/test/Object/objdump-no-sectionheaders.test --- a/llvm/test/Object/objdump-no-sectionheaders.test +++ b/llvm/test/Object/objdump-no-sectionheaders.test @@ -1,8 +1,59 @@ -; RUN: llvm-objdump -h %p/Inputs/no-sections.elf-x86-64 \ -; RUN: | FileCheck %s +## Check llvm-objdump -h can handle ELF files without section info. +## Only PT_LOAD segments with the PF_X flag will be displayed as fake sections. -; CHECK: Sections: -; CHECK-NEXT: Idx Name Size VMA Type -; CHECK-NEXT: 0 000006ec 0000000000400000 TEXT -; CHECK-NEXT: 1 00000000 0000000000000000 TEXT -; CHECK-NOT: {{.}} +# RUN: yaml2obj %s -o %t +# RUN: llvm-objdump -h %t | FileCheck %s + +# CHECK: Sections: +# CHECK-NEXT: Idx Name Size VMA Type +# CHECK-NEXT: 0 PT_LOAD#1 00000100 0000000000400000 TEXT +# CHECK-NEXT: 1 PT_LOAD#3 00000200 0000000000600400 TEXT +# CHECK-NOT: {{.}} + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_CORE + Machine: EM_X86_64 +Sections: + - Type: SectionHeaderTable + NoHeaders: true + - Type: Fill + Name: code1 + Pattern: "cc" + Size: 0x100 + Offset: 0x200 + - Type: Fill + Name: data1 + Pattern: "aa55" + Size: 0x100 + Offset: 0x300 + - Type: Fill + Name: code2 + Pattern: "ff" + Size: 0x200 + Offset: 0x400 +ProgramHeaders: + - Type: PT_PHDR + Flags: [ PF_X ] + VAddr: 0x400000 + MemSize: 0x100 + - Type: PT_LOAD + Flags: [ PF_X ] + VAddr: 0x400000 + MemSize: 0x100 + FirstSec: code1 + LastSec: code1 + - Type: PT_LOAD + Flags: [ PF_R ] + VAddr: 0x500300 + MemSize: 0x100 + FirstSec: data1 + LastSec: data1 + - Type: PT_LOAD + Flags: [ PF_R, PF_X ] + VAddr: 0x600400 + MemSize: 0x200 + FirstSec: code2 + LastSec: code2 diff --git a/llvm/test/tools/llvm-objdump/X86/disassemble-no-section.test b/llvm/test/tools/llvm-objdump/X86/disassemble-no-section.test --- a/llvm/test/tools/llvm-objdump/X86/disassemble-no-section.test +++ b/llvm/test/tools/llvm-objdump/X86/disassemble-no-section.test @@ -6,9 +6,9 @@ # RUN: yaml2obj %s -o %t # RUN: llvm-objdump -d %t | FileCheck %s -# CHECK: Disassembly of section : +# CHECK: Disassembly of section PT_LOAD#0: # CHECK-EMPTY: -# CHECK-NEXT: <>: +# CHECK-NEXT: : # CHECK-NEXT: 55 pushq %rbp # CHECK-NEXT: 48 89 e5 movq %rsp, %rbp # CHECK-NEXT: 0f 1f 40 00 nopl (%rax) @@ -22,9 +22,9 @@ # RANGE: no section overlaps the range # RANGE-EMPTY: -# RANGE-NEXT: Disassembly of section : +# RANGE-NEXT: Disassembly of section PT_LOAD#0: # RANGE-EMPTY: -# RANGE-NEXT: <>: +# RANGE-NEXT: : # RANGE-NEXT: 55 pushq %rbp # RANGE-NEXT: 48 89 e5 movq %rsp, %rbp # RANGE-EMPTY: diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -2166,6 +2166,9 @@ } void objdump::printSectionHeaders(ObjectFile &Obj) { + if (Obj.isELF() && Obj.sections().empty()) + createFakeELFSections(Obj); + size_t NameWidth = getMaxSectionNameWidth(Obj); size_t AddressWidth = 2 * Obj.getBytesInAddress(); bool HasLMAColumn = shouldDisplayLMA(Obj); @@ -2178,9 +2181,6 @@ outs() << "Idx " << left_justify("Name", NameWidth) << " Size " << left_justify("VMA", AddressWidth) << " Type\n"; - if (Obj.isELF() && Obj.sections().empty()) - createFakeELFSections(Obj); - uint64_t Idx; for (const SectionRef &Section : ToolSectionFilter(Obj, &Idx)) { StringRef Name = unwrapOrError(Section.getName(), Obj.getFileName());