Skip to content

Commit 623cd75

Browse files
authored
[llvm-objdump] Fix lma display issue for non-bss sections (#72141)
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.
1 parent 9a37653 commit 623cd75

File tree

4 files changed

+105
-41
lines changed

4 files changed

+105
-41
lines changed

llvm/include/llvm/Object/ELF.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,50 @@ static inline Error defaultWarningHandler(const Twine &Msg) {
163163
return createError(Msg);
164164
}
165165

166+
template <class ELFT>
167+
bool checkSectionOffsets(const typename ELFT::Phdr &Phdr,
168+
const typename ELFT::Shdr &Sec) {
169+
// SHT_NOBITS sections don't need to have an offset inside the segment.
170+
if (Sec.sh_type == ELF::SHT_NOBITS)
171+
return true;
172+
173+
if (Sec.sh_offset < Phdr.p_offset)
174+
return false;
175+
176+
// Only non-empty sections can be at the end of a segment.
177+
if (Sec.sh_size == 0)
178+
return (Sec.sh_offset + 1 <= Phdr.p_offset + Phdr.p_filesz);
179+
return Sec.sh_offset + Sec.sh_size <= Phdr.p_offset + Phdr.p_filesz;
180+
}
181+
182+
// Check that an allocatable section belongs to a virtual address
183+
// space of a segment.
184+
template <class ELFT>
185+
bool checkSectionVMA(const typename ELFT::Phdr &Phdr,
186+
const typename ELFT::Shdr &Sec) {
187+
if (!(Sec.sh_flags & ELF::SHF_ALLOC))
188+
return true;
189+
190+
if (Sec.sh_addr < Phdr.p_vaddr)
191+
return false;
192+
193+
bool IsTbss =
194+
(Sec.sh_type == ELF::SHT_NOBITS) && ((Sec.sh_flags & ELF::SHF_TLS) != 0);
195+
// .tbss is special, it only has memory in PT_TLS and has NOBITS properties.
196+
bool IsTbssInNonTLS = IsTbss && Phdr.p_type != ELF::PT_TLS;
197+
// Only non-empty sections can be at the end of a segment.
198+
if (Sec.sh_size == 0 || IsTbssInNonTLS)
199+
return Sec.sh_addr + 1 <= Phdr.p_vaddr + Phdr.p_memsz;
200+
return Sec.sh_addr + Sec.sh_size <= Phdr.p_vaddr + Phdr.p_memsz;
201+
}
202+
203+
template <class ELFT>
204+
bool isSectionInSegment(const typename ELFT::Phdr &Phdr,
205+
const typename ELFT::Shdr &Sec) {
206+
return checkSectionOffsets<ELFT>(Phdr, Sec) &&
207+
checkSectionVMA<ELFT>(Phdr, Sec);
208+
}
209+
166210
template <class ELFT>
167211
class ELFFile {
168212
public:
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# RUN: yaml2obj %s -o %t
2+
3+
## .data and .data_copy have the same VMA but different sh_offset values.
4+
## Check that we can still print LMA correctly.
5+
# RUN: llvm-objdump --section-headers %t | FileCheck %s
6+
7+
# CHECK: Sections:
8+
# CHECK-NEXT: Idx Name Size VMA LMA Type
9+
# CHECK-NEXT: 0 00000000 0000000000000000 0000000000000000
10+
# CHECK-NEXT: 1 .text 00000004 0000000000001000 0000000000002000 TEXT
11+
# CHECK-NEXT: 2 .data 00000004 0000000000002000 0000000000003000 DATA
12+
# CHECK-NEXT: 3 .data_copy 00000004 0000000000002000 0000000000004000 DATA
13+
14+
!ELF
15+
FileHeader:
16+
Class: ELFCLASS64
17+
Data: ELFDATA2LSB
18+
Type: ET_EXEC
19+
Machine: EM_X86_64
20+
Sections:
21+
- Name: .text
22+
Type: SHT_PROGBITS
23+
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
24+
Content: "00000000"
25+
Address: 0x00001000
26+
- Name: .data
27+
Type: SHT_PROGBITS
28+
Flags: [ SHF_ALLOC ]
29+
Content: "00000000"
30+
Address: 0x00002000
31+
- Name: .data_copy
32+
Type: SHT_PROGBITS
33+
Flags: [ SHF_ALLOC ]
34+
Content: "00000000"
35+
Address: 0x00002000
36+
ProgramHeaders:
37+
- Type: PT_LOAD
38+
Flags: [ PF_X, PF_R ]
39+
VAddr: 0x00001000
40+
PAddr: 0x00002000
41+
FirstSec: .text
42+
LastSec: .text
43+
- Type: PT_LOAD
44+
Flags: [ PF_R ]
45+
VAddr: 0x00002000
46+
PAddr: 0x00003000
47+
FirstSec: .data
48+
LastSec: .data
49+
- Type: PT_LOAD
50+
Flags: [ PF_R ]
51+
VAddr: 0x00002000
52+
PAddr: 0x00004000
53+
FirstSec: .data_copy
54+
LastSec: .data_copy

llvm/tools/llvm-objdump/ELFDump.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,10 @@ static uint64_t getSectionLMA(const ELFFile<ELFT> &Obj,
181181
// Search for a PT_LOAD segment containing the requested section. Use this
182182
// segment's p_addr to calculate the section's LMA.
183183
for (const typename ELFT::Phdr &Phdr : *PhdrRangeOrErr)
184-
if ((Phdr.p_type == ELF::PT_LOAD) && (Phdr.p_vaddr <= Sec.getAddress()) &&
185-
(Phdr.p_vaddr + Phdr.p_memsz > Sec.getAddress()))
184+
if ((Phdr.p_type == ELF::PT_LOAD) &&
185+
(isSectionInSegment<ELFT>(
186+
Phdr, *cast<const ELFObjectFile<ELFT>>(Sec.getObject())
187+
->getSection(Sec.getRawDataRefImpl()))))
186188
return Sec.getAddress() - Phdr.p_vaddr + Phdr.p_paddr;
187189

188190
// Return section's VMA if it isn't in a PT_LOAD segment.

llvm/tools/llvm-readobj/ELFDumper.cpp

Lines changed: 3 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4511,43 +4511,6 @@ static bool checkTLSSections(const typename ELFT::Phdr &Phdr,
45114511
return Phdr.p_type != ELF::PT_TLS;
45124512
}
45134513

4514-
template <class ELFT>
4515-
static bool checkOffsets(const typename ELFT::Phdr &Phdr,
4516-
const typename ELFT::Shdr &Sec) {
4517-
// SHT_NOBITS sections don't need to have an offset inside the segment.
4518-
if (Sec.sh_type == ELF::SHT_NOBITS)
4519-
return true;
4520-
4521-
if (Sec.sh_offset < Phdr.p_offset)
4522-
return false;
4523-
4524-
// Only non-empty sections can be at the end of a segment.
4525-
if (Sec.sh_size == 0)
4526-
return (Sec.sh_offset + 1 <= Phdr.p_offset + Phdr.p_filesz);
4527-
return Sec.sh_offset + Sec.sh_size <= Phdr.p_offset + Phdr.p_filesz;
4528-
}
4529-
4530-
// Check that an allocatable section belongs to a virtual address
4531-
// space of a segment.
4532-
template <class ELFT>
4533-
static bool checkVMA(const typename ELFT::Phdr &Phdr,
4534-
const typename ELFT::Shdr &Sec) {
4535-
if (!(Sec.sh_flags & ELF::SHF_ALLOC))
4536-
return true;
4537-
4538-
if (Sec.sh_addr < Phdr.p_vaddr)
4539-
return false;
4540-
4541-
bool IsTbss =
4542-
(Sec.sh_type == ELF::SHT_NOBITS) && ((Sec.sh_flags & ELF::SHF_TLS) != 0);
4543-
// .tbss is special, it only has memory in PT_TLS and has NOBITS properties.
4544-
bool IsTbssInNonTLS = IsTbss && Phdr.p_type != ELF::PT_TLS;
4545-
// Only non-empty sections can be at the end of a segment.
4546-
if (Sec.sh_size == 0 || IsTbssInNonTLS)
4547-
return Sec.sh_addr + 1 <= Phdr.p_vaddr + Phdr.p_memsz;
4548-
return Sec.sh_addr + Sec.sh_size <= Phdr.p_vaddr + Phdr.p_memsz;
4549-
}
4550-
45514514
template <class ELFT>
45524515
static bool checkPTDynamic(const typename ELFT::Phdr &Phdr,
45534516
const typename ELFT::Shdr &Sec) {
@@ -4679,8 +4642,9 @@ template <class ELFT> void GNUELFDumper<ELFT>::printSectionMapping() {
46794642
// readelf additionally makes sure it does not print zero sized sections
46804643
// at end of segments and for PT_DYNAMIC both start and end of section
46814644
// .tbss must only be shown in PT_TLS section.
4682-
if (checkTLSSections<ELFT>(Phdr, Sec) && checkOffsets<ELFT>(Phdr, Sec) &&
4683-
checkVMA<ELFT>(Phdr, Sec) && checkPTDynamic<ELFT>(Phdr, Sec)) {
4645+
if (isSectionInSegment<ELFT>(Phdr, Sec) &&
4646+
checkTLSSections<ELFT>(Phdr, Sec) &&
4647+
checkPTDynamic<ELFT>(Phdr, Sec)) {
46844648
Sections +=
46854649
unwrapOrError(this->FileName, this->Obj.getSectionName(Sec)).str() +
46864650
" ";

0 commit comments

Comments
 (0)