[llvm] [llvm-objdump] Fix lma display issue for non-bss sections (PR #72141)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 13 09:55:30 PST 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-binary-utilities
Author: Jason Liu (jasonliudev)
<details>
<summary>Changes</summary>
llvm-readobj and llvm-objdump have inconsistent handling of display
lma for sections.
This patch tries to common code up and adapt the same approach for
both tools.
---
Full diff: https://github.com/llvm/llvm-project/pull/72141.diff
5 Files Affected:
- (modified) llvm/include/llvm/Object/ELF.h (+2)
- (modified) llvm/lib/Object/ELF.cpp (+43)
- (added) llvm/test/tools/llvm-objdump/X86/phdrs-lma3.test (+54)
- (modified) llvm/tools/llvm-objdump/ELFDump.cpp (+4-2)
- (modified) llvm/tools/llvm-readobj/ELFDumper.cpp (+3-39)
``````````diff
diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h
index 927deeea2cd6aef..e5201c9439e59ab 100644
--- a/llvm/include/llvm/Object/ELF.h
+++ b/llvm/include/llvm/Object/ELF.h
@@ -425,6 +425,8 @@ class ELFFile {
std::function<Expected<bool>(const Elf_Shdr &)> IsMatch) const;
void createFakeSections();
+
+ static bool isSectionInSegment(const Elf_Phdr &Phdr, const Elf_Shdr &Sec);
};
using ELF32LEFile = ELFFile<ELF32LE>;
diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp
index 0d1862e573712f5..e3dc4329aad3268 100644
--- a/llvm/lib/Object/ELF.cpp
+++ b/llvm/lib/Object/ELF.cpp
@@ -799,6 +799,49 @@ ELFFile<ELFT>::getSectionAndRelocations(
return SecToRelocMap;
}
+template <class ELFT>
+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 <class ELFT>
+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 <class ELFT>
+bool ELFFile<ELFT>::isSectionInSegment(const Elf_Phdr &Phdr,
+ const Elf_Shdr &Sec) {
+ return checkOffsets<ELFT>(Phdr, Sec) && checkVMA<ELFT>(Phdr, Sec);
+}
+
template class llvm::object::ELFFile<ELF32LE>;
template class llvm::object::ELFFile<ELF32BE>;
template class llvm::object::ELFFile<ELF64LE>;
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 000000000000000..e44d3f66310c0a8
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/X86/phdrs-lma3.test
@@ -0,0 +1,54 @@
+# RUN: yaml2obj %s > %t
+
+## Check when vma is the same, we could still print LMA correctly when dumping
+## section headers.
+# 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 299a7e3cf3fa523..8951bbc52ac94ed 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<ELFT> &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) &&
+ (Obj.isSectionInSegment(
+ Phdr, *cast<const ELFObjectFile<ELFT>>(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 64f343a9b37a343..3e6fa1d159210af 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 <class ELFT>
-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 <class ELFT>
-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 <class ELFT>
static bool checkPTDynamic(const typename ELFT::Phdr &Phdr,
const typename ELFT::Shdr &Sec) {
@@ -4675,8 +4638,9 @@ template <class ELFT> void GNUELFDumper<ELFT>::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<ELFT>(Phdr, Sec) && checkOffsets<ELFT>(Phdr, Sec) &&
- checkVMA<ELFT>(Phdr, Sec) && checkPTDynamic<ELFT>(Phdr, Sec)) {
+ if (this->Obj.isSectionInSegment(Phdr, Sec) &&
+ checkTLSSections<ELFT>(Phdr, Sec) &&
+ checkPTDynamic<ELFT>(Phdr, Sec)) {
Sections +=
unwrapOrError(this->FileName, this->Obj.getSectionName(Sec)).str() +
" ";
``````````
</details>
https://github.com/llvm/llvm-project/pull/72141
More information about the llvm-commits
mailing list