Skip to content

Commit 02f3f20

Browse files
jasonliudevfarazs-github
authored andcommitted
[llvm-objdump] Fix lma display issue for non-bss sections (llvm#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. (cherry picked from 484B735DC5)
1 parent 1c19f83 commit 02f3f20

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
@@ -150,8 +150,10 @@ static uint64_t getSectionLMA(const ELFFile<ELFT> &Obj,
150150
// Search for a PT_LOAD segment containing the requested section. Use this
151151
// segment's p_addr to calculate the section's LMA.
152152
for (const typename ELFT::Phdr &Phdr : *PhdrRangeOrErr)
153-
if ((Phdr.p_type == ELF::PT_LOAD) && (Phdr.p_vaddr <= Sec.getAddress()) &&
154-
(Phdr.p_vaddr + Phdr.p_memsz > Sec.getAddress()))
153+
if ((Phdr.p_type == ELF::PT_LOAD) &&
154+
(isSectionInSegment<ELFT>(
155+
Phdr, *cast<const ELFObjectFile<ELFT>>(Sec.getObject())
156+
->getSection(Sec.getRawDataRefImpl()))))
155157
return Sec.getAddress() - Phdr.p_vaddr + Phdr.p_paddr;
156158

157159
// 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
@@ -4246,43 +4246,6 @@ static bool checkTLSSections(const typename ELFT::Phdr &Phdr,
42464246
return Phdr.p_type != ELF::PT_TLS;
42474247
}
42484248

4249-
template <class ELFT>
4250-
static bool checkOffsets(const typename ELFT::Phdr &Phdr,
4251-
const typename ELFT::Shdr &Sec) {
4252-
// SHT_NOBITS sections don't need to have an offset inside the segment.
4253-
if (Sec.sh_type == ELF::SHT_NOBITS)
4254-
return true;
4255-
4256-
if (Sec.sh_offset < Phdr.p_offset)
4257-
return false;
4258-
4259-
// Only non-empty sections can be at the end of a segment.
4260-
if (Sec.sh_size == 0)
4261-
return (Sec.sh_offset + 1 <= Phdr.p_offset + Phdr.p_filesz);
4262-
return Sec.sh_offset + Sec.sh_size <= Phdr.p_offset + Phdr.p_filesz;
4263-
}
4264-
4265-
// Check that an allocatable section belongs to a virtual address
4266-
// space of a segment.
4267-
template <class ELFT>
4268-
static bool checkVMA(const typename ELFT::Phdr &Phdr,
4269-
const typename ELFT::Shdr &Sec) {
4270-
if (!(Sec.sh_flags & ELF::SHF_ALLOC))
4271-
return true;
4272-
4273-
if (Sec.sh_addr < Phdr.p_vaddr)
4274-
return false;
4275-
4276-
bool IsTbss =
4277-
(Sec.sh_type == ELF::SHT_NOBITS) && ((Sec.sh_flags & ELF::SHF_TLS) != 0);
4278-
// .tbss is special, it only has memory in PT_TLS and has NOBITS properties.
4279-
bool IsTbssInNonTLS = IsTbss && Phdr.p_type != ELF::PT_TLS;
4280-
// Only non-empty sections can be at the end of a segment.
4281-
if (Sec.sh_size == 0 || IsTbssInNonTLS)
4282-
return Sec.sh_addr + 1 <= Phdr.p_vaddr + Phdr.p_memsz;
4283-
return Sec.sh_addr + Sec.sh_size <= Phdr.p_vaddr + Phdr.p_memsz;
4284-
}
4285-
42864249
template <class ELFT>
42874250
static bool checkPTDynamic(const typename ELFT::Phdr &Phdr,
42884251
const typename ELFT::Shdr &Sec) {
@@ -4414,8 +4377,9 @@ template <class ELFT> void GNUELFDumper<ELFT>::printSectionMapping() {
44144377
// readelf additionally makes sure it does not print zero sized sections
44154378
// at end of segments and for PT_DYNAMIC both start and end of section
44164379
// .tbss must only be shown in PT_TLS section.
4417-
if (checkTLSSections<ELFT>(Phdr, Sec) && checkOffsets<ELFT>(Phdr, Sec) &&
4418-
checkVMA<ELFT>(Phdr, Sec) && checkPTDynamic<ELFT>(Phdr, Sec)) {
4380+
if (isSectionInSegment<ELFT>(Phdr, Sec) &&
4381+
checkTLSSections<ELFT>(Phdr, Sec) &&
4382+
checkPTDynamic<ELFT>(Phdr, Sec)) {
44194383
Sections +=
44204384
unwrapOrError(this->FileName, this->Obj.getSectionName(Sec)).str() +
44214385
" ";

0 commit comments

Comments
 (0)