diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h index 927deeea2cd6a..3fca00592f73b 100644 --- a/llvm/include/llvm/Object/ELF.h +++ b/llvm/include/llvm/Object/ELF.h @@ -163,6 +163,50 @@ static inline Error defaultWarningHandler(const Twine &Msg) { return createError(Msg); } +template +bool checkSectionOffsets(const typename ELFT::Phdr &Phdr, + const typename ELFT::Shdr &Sec) { + // SHT_NOBITS sections don't need to have an offset inside the segment. + if (Sec.sh_type == ELF::SHT_NOBITS) + return true; + + if (Sec.sh_offset < Phdr.p_offset) + return false; + + // Only non-empty sections can be at the end of a segment. + if (Sec.sh_size == 0) + return (Sec.sh_offset + 1 <= Phdr.p_offset + Phdr.p_filesz); + return Sec.sh_offset + Sec.sh_size <= Phdr.p_offset + Phdr.p_filesz; +} + +// Check that an allocatable section belongs to a virtual address +// space of a segment. +template +bool checkSectionVMA(const typename ELFT::Phdr &Phdr, + const typename ELFT::Shdr &Sec) { + if (!(Sec.sh_flags & ELF::SHF_ALLOC)) + return true; + + if (Sec.sh_addr < Phdr.p_vaddr) + return false; + + bool IsTbss = + (Sec.sh_type == ELF::SHT_NOBITS) && ((Sec.sh_flags & ELF::SHF_TLS) != 0); + // .tbss is special, it only has memory in PT_TLS and has NOBITS properties. + bool IsTbssInNonTLS = IsTbss && Phdr.p_type != ELF::PT_TLS; + // Only non-empty sections can be at the end of a segment. + if (Sec.sh_size == 0 || IsTbssInNonTLS) + return Sec.sh_addr + 1 <= Phdr.p_vaddr + Phdr.p_memsz; + return Sec.sh_addr + Sec.sh_size <= Phdr.p_vaddr + Phdr.p_memsz; +} + +template +bool isSectionInSegment(const typename ELFT::Phdr &Phdr, + const typename ELFT::Shdr &Sec) { + return checkSectionOffsets(Phdr, Sec) && + checkSectionVMA(Phdr, Sec); +} + template class ELFFile { public: diff --git a/llvm/test/tools/llvm-objdump/X86/phdrs-lma3.test b/llvm/test/tools/llvm-objdump/X86/phdrs-lma3.test new file mode 100644 index 0000000000000..663882ecd5290 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/X86/phdrs-lma3.test @@ -0,0 +1,54 @@ +# RUN: yaml2obj %s -o %t + +## .data and .data_copy have the same VMA but different sh_offset values. +## Check that we can still print LMA correctly. +# RUN: llvm-objdump --section-headers %t | FileCheck %s + +# CHECK: Sections: +# CHECK-NEXT: Idx Name Size VMA LMA Type +# CHECK-NEXT: 0 00000000 0000000000000000 0000000000000000 +# CHECK-NEXT: 1 .text 00000004 0000000000001000 0000000000002000 TEXT +# CHECK-NEXT: 2 .data 00000004 0000000000002000 0000000000003000 DATA +# CHECK-NEXT: 3 .data_copy 00000004 0000000000002000 0000000000004000 DATA + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Content: "00000000" + Address: 0x00001000 + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Content: "00000000" + Address: 0x00002000 + - Name: .data_copy + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Content: "00000000" + Address: 0x00002000 +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_X, PF_R ] + VAddr: 0x00001000 + PAddr: 0x00002000 + FirstSec: .text + LastSec: .text + - Type: PT_LOAD + Flags: [ PF_R ] + VAddr: 0x00002000 + PAddr: 0x00003000 + FirstSec: .data + LastSec: .data + - Type: PT_LOAD + Flags: [ PF_R ] + VAddr: 0x00002000 + PAddr: 0x00004000 + FirstSec: .data_copy + LastSec: .data_copy diff --git a/llvm/tools/llvm-objdump/ELFDump.cpp b/llvm/tools/llvm-objdump/ELFDump.cpp index 299a7e3cf3fa5..34861ee92128f 100644 --- a/llvm/tools/llvm-objdump/ELFDump.cpp +++ b/llvm/tools/llvm-objdump/ELFDump.cpp @@ -181,8 +181,10 @@ static uint64_t getSectionLMA(const ELFFile &Obj, // Search for a PT_LOAD segment containing the requested section. Use this // segment's p_addr to calculate the section's LMA. for (const typename ELFT::Phdr &Phdr : *PhdrRangeOrErr) - if ((Phdr.p_type == ELF::PT_LOAD) && (Phdr.p_vaddr <= Sec.getAddress()) && - (Phdr.p_vaddr + Phdr.p_memsz > Sec.getAddress())) + if ((Phdr.p_type == ELF::PT_LOAD) && + (isSectionInSegment( + Phdr, *cast>(Sec.getObject()) + ->getSection(Sec.getRawDataRefImpl())))) return Sec.getAddress() - Phdr.p_vaddr + Phdr.p_paddr; // Return section's VMA if it isn't in a PT_LOAD segment. diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index 64f343a9b37a3..7a3c1381f8d8c 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -4507,43 +4507,6 @@ static bool checkTLSSections(const typename ELFT::Phdr &Phdr, return Phdr.p_type != ELF::PT_TLS; } -template -static bool checkOffsets(const typename ELFT::Phdr &Phdr, - const typename ELFT::Shdr &Sec) { - // SHT_NOBITS sections don't need to have an offset inside the segment. - if (Sec.sh_type == ELF::SHT_NOBITS) - return true; - - if (Sec.sh_offset < Phdr.p_offset) - return false; - - // Only non-empty sections can be at the end of a segment. - if (Sec.sh_size == 0) - return (Sec.sh_offset + 1 <= Phdr.p_offset + Phdr.p_filesz); - return Sec.sh_offset + Sec.sh_size <= Phdr.p_offset + Phdr.p_filesz; -} - -// Check that an allocatable section belongs to a virtual address -// space of a segment. -template -static bool checkVMA(const typename ELFT::Phdr &Phdr, - const typename ELFT::Shdr &Sec) { - if (!(Sec.sh_flags & ELF::SHF_ALLOC)) - return true; - - if (Sec.sh_addr < Phdr.p_vaddr) - return false; - - bool IsTbss = - (Sec.sh_type == ELF::SHT_NOBITS) && ((Sec.sh_flags & ELF::SHF_TLS) != 0); - // .tbss is special, it only has memory in PT_TLS and has NOBITS properties. - bool IsTbssInNonTLS = IsTbss && Phdr.p_type != ELF::PT_TLS; - // Only non-empty sections can be at the end of a segment. - if (Sec.sh_size == 0 || IsTbssInNonTLS) - return Sec.sh_addr + 1 <= Phdr.p_vaddr + Phdr.p_memsz; - return Sec.sh_addr + Sec.sh_size <= Phdr.p_vaddr + Phdr.p_memsz; -} - template static bool checkPTDynamic(const typename ELFT::Phdr &Phdr, const typename ELFT::Shdr &Sec) { @@ -4675,8 +4638,9 @@ template void GNUELFDumper::printSectionMapping() { // readelf additionally makes sure it does not print zero sized sections // at end of segments and for PT_DYNAMIC both start and end of section // .tbss must only be shown in PT_TLS section. - if (checkTLSSections(Phdr, Sec) && checkOffsets(Phdr, Sec) && - checkVMA(Phdr, Sec) && checkPTDynamic(Phdr, Sec)) { + if (isSectionInSegment(Phdr, Sec) && + checkTLSSections(Phdr, Sec) && + checkPTDynamic(Phdr, Sec)) { Sections += unwrapOrError(this->FileName, this->Obj.getSectionName(Sec)).str() + " ";