Skip to content

Commit

Permalink
Merging r369828:
Browse files Browse the repository at this point in the history
------------------------------------------------------------------------
r369828 | maskray | 2019-08-24 02:41:15 +0200 (Sat, 24 Aug 2019) | 18 lines

[ELF] Align the first section of a PT_LOAD even if its type is SHT_NOBITS

Reported at https://reviews.llvm.org/D64930#1642223

If the only section of a PT_LOAD is a SHT_NOBITS section (e.g. .bss), we
may not align its sh_offset. p_offset of the PT_LOAD will be set to
sh_offset, and we will get p_offset!=p_vaddr (mod p_align).  If such
executable is mapped by the Linux kernel, it will segfault.

After D64906, this may happen the non-linker script case.

The linker script case has had this issue for a long time.
This was fixed by rL321657 (but the test linkerscript/nobits-offset.s
failed to test a SHT_NOBITS section), but broken by rL345154.

Reviewed By: peter.smith

Differential Revision: https://reviews.llvm.org/D66658
------------------------------------------------------------------------

llvm-svn: 371196
  • Loading branch information
zmodem committed Sep 6, 2019
1 parent 5fc0367 commit 501ad1d
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 27 deletions.
23 changes: 12 additions & 11 deletions lld/ELF/Writer.cpp
Expand Up @@ -2230,25 +2230,26 @@ template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
// same with its virtual address modulo the page size, so that the loader can
// load executables without any address adjustment.
static uint64_t computeFileOffset(OutputSection *os, uint64_t off) {
// File offsets are not significant for .bss sections. By convention, we keep
// section offsets monotonically increasing rather than setting to zero.
if (os->type == SHT_NOBITS)
return off;

// If the section is not in a PT_LOAD, we just have to align it.
if (!os->ptLoad)
return alignTo(off, os->alignment);

// The first section in a PT_LOAD has to have congruent offset and address
// module the page size.
OutputSection *first = os->ptLoad->firstSec;
if (os == first) {
if (os->ptLoad && os->ptLoad->firstSec == os) {
uint64_t alignment = std::max<uint64_t>(os->alignment, config->maxPageSize);
return alignTo(off, alignment, os->addr);
}

// File offsets are not significant for .bss sections other than the first one
// in a PT_LOAD. By convention, we keep section offsets monotonically
// increasing rather than setting to zero.
if (os->type == SHT_NOBITS)
return off;

// If the section is not in a PT_LOAD, we just have to align it.
if (!os->ptLoad)
return alignTo(off, os->alignment);

// If two sections share the same PT_LOAD the file offset is calculated
// using this formula: Off2 = Off1 + (VA2 - VA1).
OutputSection *first = os->ptLoad->firstSec;
return first->offset + os->addr - first->addr;
}

Expand Down
12 changes: 6 additions & 6 deletions lld/test/ELF/basic-ppc64.s
Expand Up @@ -35,7 +35,7 @@
// CHECK-NEXT: Version: 1
// CHECK-NEXT: Entry: 0x10000
// CHECK-NEXT: ProgramHeaderOffset: 0x40
// CHECK-NEXT: SectionHeaderOffset: 0x200F8
// CHECK-NEXT: SectionHeaderOffset: 0x30098
// CHECK-NEXT: Flags [ (0x2)
// CHECK-NEXT: 0x2
// CHECK-NEXT: ]
Expand Down Expand Up @@ -178,7 +178,7 @@
// CHECK-NEXT: SHF_WRITE (0x1)
// CHECK-NEXT: ]
// CHECK-NEXT: Address: 0x30000
// CHECK-NEXT: Offset: 0x20060
// CHECK-NEXT: Offset: 0x30000
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Link: 0
// CHECK-NEXT: Info: 0
Expand All @@ -194,7 +194,7 @@
// CHECK-NEXT: SHF_STRINGS (0x20)
// CHECK-NEXT: ]
// CHECK-NEXT: Address: 0x0
// CHECK-NEXT: Offset: 0x20060
// CHECK-NEXT: Offset: 0x30000
// CHECK-NEXT: Size: 8
// CHECK-NEXT: Link: 0
// CHECK-NEXT: Info: 0
Expand All @@ -211,7 +211,7 @@
// CHECK-NEXT: Flags [ (0x0)
// CHECK-NEXT: ]
// CHECK-NEXT: Address: 0x0
// CHECK-NEXT: Offset: 0x20068
// CHECK-NEXT: Offset: 0x30008
// CHECK-NEXT: Size: 48
// CHECK-NEXT: Link: 10
// CHECK-NEXT: Info: 2
Expand All @@ -233,7 +233,7 @@
// CHECK-NEXT: Flags [ (0x0)
// CHECK-NEXT: ]
// CHECK-NEXT: Address: 0x0
// CHECK-NEXT: Offset: 0x20098
// CHECK-NEXT: Offset: 0x30038
// CHECK-NEXT: Size: 84
// CHECK-NEXT: Link: 0
// CHECK-NEXT: Info: 0
Expand All @@ -255,7 +255,7 @@
// CHECK-NEXT: Flags [ (0x0)
// CHECK-NEXT: ]
// CHECK-NEXT: Address: 0x0
// CHECK-NEXT: Offset: 0x200EC
// CHECK-NEXT: Offset: 0x3008C
// CHECK-NEXT: Size: 10
// CHECK-NEXT: Link: 0
// CHECK-NEXT: Info: 0
Expand Down
25 changes: 16 additions & 9 deletions lld/test/ELF/linkerscript/nobits-offset.s
Expand Up @@ -2,17 +2,24 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
# RUN: echo "SECTIONS { \
# RUN: .sec1 (NOLOAD) : { . += 1; } \
# RUN: .text : { *(.text) } \
# RUN: .bss : { *(.bss) } \
# RUN: };" > %t.script
# RUN: ld.lld %t.o -T %t.script -o %t
# RUN: llvm-readelf --sections %t | FileCheck %s
# RUN: llvm-readelf -S -l %t | FileCheck %s

# We used to misalign section offsets if the first section in a
# PT_LOAD was SHT_NOBITS.
## If a SHT_NOBITS section is the only section of a PT_LOAD segment,
## p_offset will be set to the sh_offset field of the section. Check we align
## sh_offset to sh_addr modulo max-page-size, so that p_vaddr=p_offset (mod
## p_align).

# CHECK: [ 2] .text PROGBITS 0000000000000010 001010 000010 00 AX 0 0 16
# CHECK: Name Type Address Off Size ES Flg Lk Inf Al
# CHECK: .bss NOBITS 0000000000000400 001400 000001 00 WA 0 0 1024

.global _start
_start:
nop
.p2align 4
# CHECK: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
# CHECK: LOAD 0x001400 0x0000000000000400 0x0000000000000400 0x000000 0x000001 RW 0x1000

# CHECK: 00 .bss

.bss
.p2align 10
.byte 0
21 changes: 21 additions & 0 deletions lld/test/ELF/nobits-offset.s
@@ -0,0 +1,21 @@
# REQUIRES: aarch64
# RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o
# RUN: ld.lld %t.o -o %t
# RUN: llvm-readelf -S -l %t | FileCheck %s

## If a SHT_NOBITS section is the only section of a PT_LOAD segment,
## p_offset will be set to the sh_offset field of the section. Check we align
## sh_offset to sh_addr modulo max-page-size, so that p_vaddr=p_offset (mod
## p_align).

# CHECK: Name Type Address Off Size ES Flg Lk Inf Al
# CHECK: .bss NOBITS 0000000000210000 010000 000001 00 WA 0 0 4096

# CHECK: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
# CHECK: LOAD 0x010000 0x0000000000210000 0x0000000000210000 0x000000 0x000001 RW 0x10000

# CHECK: 02 .bss

.bss
.p2align 12
.byte 0
2 changes: 1 addition & 1 deletion lld/test/ELF/relocation-copy-align-common.s
Expand Up @@ -15,7 +15,7 @@
# CHECK-NEXT: SHF_WRITE
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x203000
# CHECK-NEXT: Offset: 0x20B0
# CHECK-NEXT: Offset: 0x3000
# CHECK-NEXT: Size: 16
# CHECK-NEXT: Link: 0
# CHECK-NEXT: Info: 0
Expand Down

0 comments on commit 501ad1d

Please sign in to comment.