[ELF] Don't advance sh_offset for an empty section whose PT_LOAD is removed (due to p_memsz=0)

removeEmptyPTLoad() removes empty (p_memsz=0) PT_LOAD segments.  In
assignFileOffsets(), setFileOffset() unnecessarily advances file offsets
for containing empty sections.

This is exposed by arm Linux kernel's multi_v5_defconfig
(see https://bugs.llvm.org/show_bug.cgi?id=45632)

```
ld.lld (max-page-size=65536):
  [34] .init.data        PROGBITS        c0c24000 c34000 0128ac 00  WA  0   0 4096
  [35] .text_itcm        PROGBITS        fffe0000 c50000 000000 00  WA  0   0  1
  [36] .data_dtcm        PROGBITS        fffe8000 c58000 000000 00  WA  0   0  1
  [37] .data             PROGBITS        c0c38000 c58000 0647a0 00  WA  0   0 32

arm-linux-gnueabi-ld (max-page-size=65536):
  [23] .init.data        PROGBITS        c0c12000 c22000 0128ac 00  WA  0   0 4096
  [24] .text_itcm        PROGBITS        fffe0000 ca2558 000000 00   W  0   0  1
  [25] .data_dtcm        PROGBITS        fffe8000 ca2558 000000 00   W  0   0  1
  [26] .data             PROGBITS        c0c26000 c36000 0647a0 00  WA  0   0 32
```

This patch clears OutputSection::ptLoad if ptLoad is removed by
removeEmptyPTLoad(). Conceptually this removes "dangling" references.

Reviewed By: psmith

Differential Revision: https://reviews.llvm.org/D79254
This commit is contained in:
Fangrui Song
2020-05-01 09:50:37 -07:00
parent db015fdd20
commit c49f83b6e9
4 changed files with 24 additions and 15 deletions

View File

@@ -153,14 +153,23 @@ template <class ELFT> void writeResult() {
}
static void removeEmptyPTLoad(std::vector<PhdrEntry *> &phdrs) {
llvm::erase_if(phdrs, [&](const PhdrEntry *p) {
if (p->p_type != PT_LOAD)
return false;
if (!p->firstSec)
return true;
uint64_t size = p->lastSec->addr + p->lastSec->size - p->firstSec->addr;
return size == 0;
});
auto it = std::stable_partition(
phdrs.begin(), phdrs.end(), [&](const PhdrEntry *p) {
if (p->p_type != PT_LOAD)
return true;
if (!p->firstSec)
return false;
uint64_t size = p->lastSec->addr + p->lastSec->size - p->firstSec->addr;
return size != 0;
});
// Clear OutputSection::ptLoad for sections contained in removed
// segments.
DenseSet<PhdrEntry *> removed(it, phdrs.end());
for (OutputSection *sec : outputSections)
if (removed.count(sec->ptLoad))
sec->ptLoad = nullptr;
phdrs.erase(it, phdrs.end());
}
void copySectionsIntoPartitions() {

View File

@@ -20,7 +20,7 @@ SECTIONS {
# PT_LOAD header.
# CHECK: Name Type Address Off
# CHECK: .text PROGBITS 0000000008000000 001000
# CHECK: .text PROGBITS 0000000008000000 000158
# CHECK: .sec1 PROGBITS 0000000020000000 001000
# CHECK: .sec2 PROGBITS 0000000020000008 001008
# CHECK: .sec3 PROGBITS 0000000020000010 001010

View File

@@ -9,7 +9,7 @@
# CHECK: Name Type Address Off Size
# CHECK-NEXT: NULL 0000000000000000 000000 000000
# CHECK-NEXT: .empty PROGBITS 0000000000080000 001000 000000
# CHECK-NEXT: .empty PROGBITS 0000000000080000 000158 000000
# CHECK-NEXT: .text PROGBITS 0000000000080000 001000 000001
# CHECK-NEXT: .data PROGBITS 0000000000080001 001001 000001
@@ -19,7 +19,7 @@
# CHECK-NEXT: LOAD 0x001001 0x0000000000080001 0x0000000000082000
# CHECK: Section to Segment mapping:
# CHECK: 00 .empty .text {{$}}
# CHECK: 00 .text {{$}}
# CHECK-NEXT: 01 .data {{$}}
SECTIONS {

View File

@@ -14,12 +14,12 @@
# CHECK: Name Type Address Off Size
# CHECK-NEXT: NULL 0000000000000000 000000 000000
# CHECK-NEXT: .text PROGBITS 0000000000000000 001000 000000
# CHECK-NEXT: .sec1 NOBITS 0000000000000000 001000 000001
# CHECK-NEXT: .bss NOBITS 0000000000000400 001400 000001
# CHECK-NEXT: .text PROGBITS 0000000000000000 000158 000000
# CHECK-NEXT: .sec1 NOBITS 0000000000000000 000158 000001
# CHECK-NEXT: .bss NOBITS 0000000000000400 000400 000001
# CHECK: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
# CHECK-NEXT: LOAD 0x001400 0x0000000000000400 0x0000000000000400 0x000000 0x000001 RW 0x1000
# CHECK-NEXT: LOAD 0x000400 0x0000000000000400 0x0000000000000400 0x000000 0x000001 RW 0x1000
# CHECK: 00 .bss {{$}}