[llvm] [llvm-objdump] Fix lma display issue for non-bss sections (PR #72141)
Jason Liu via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 27 09:00:10 PST 2023
https://github.com/jasonliudev updated https://github.com/llvm/llvm-project/pull/72141
>From 484b735dc513075858152924e755cde69c78ac1b Mon Sep 17 00:00:00 2001
From: Jason Liu <jasonliu.development at gmail.com>
Date: Mon, 13 Nov 2023 12:07:00 -0500
Subject: [PATCH] [llvm-objdump] Fix lma display issue for non-bss sections
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.
---
llvm/include/llvm/Object/ELF.h | 44 +++++++++++++++
.../tools/llvm-objdump/X86/phdrs-lma3.test | 54 +++++++++++++++++++
llvm/tools/llvm-objdump/ELFDump.cpp | 6 ++-
llvm/tools/llvm-readobj/ELFDumper.cpp | 42 ++-------------
4 files changed, 105 insertions(+), 41 deletions(-)
create mode 100644 llvm/test/tools/llvm-objdump/X86/phdrs-lma3.test
diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h
index 927deeea2cd6aef..3fca00592f73b4c 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 <class ELFT>
+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 <class ELFT>
+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 <class ELFT>
+bool isSectionInSegment(const typename ELFT::Phdr &Phdr,
+ const typename ELFT::Shdr &Sec) {
+ return checkSectionOffsets<ELFT>(Phdr, Sec) &&
+ checkSectionVMA<ELFT>(Phdr, Sec);
+}
+
template <class ELFT>
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 000000000000000..663882ecd529029
--- /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 299a7e3cf3fa523..34861ee92128fdd 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) &&
+ (isSectionInSegment<ELFT>(
+ 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..7a3c1381f8d8ca4 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 (isSectionInSegment<ELFT>(Phdr, Sec) &&
+ checkTLSSections<ELFT>(Phdr, Sec) &&
+ checkPTDynamic<ELFT>(Phdr, Sec)) {
Sections +=
unwrapOrError(this->FileName, this->Obj.getSectionName(Sec)).str() +
" ";
More information about the llvm-commits
mailing list