diff options
author | Hans Wennborg <hans@hanshq.net> | 2019-09-06 11:18:45 +0000 |
---|---|---|
committer | Hans Wennborg <hans@hanshq.net> | 2019-09-06 11:18:45 +0000 |
commit | 78fcb6ad74e6c86e5dd51bb517db2d13ed7f5757 (patch) | |
tree | 0fb8ccd324e3db847dd64e9ae37d6b8fe789dacc | |
parent | ed3ac59e3b2a83c44ff97d92cf600a573c78e0ba (diff) |
Merging r369828:
------------------------------------------------------------------------
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
------------------------------------------------------------------------
git-svn-id: https://llvm.org/svn/llvm-project/lld/branches/release_90@371196 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | ELF/Writer.cpp | 23 | ||||
-rw-r--r-- | test/ELF/basic-ppc64.s | 12 | ||||
-rw-r--r-- | test/ELF/linkerscript/nobits-offset.s | 25 | ||||
-rw-r--r-- | test/ELF/nobits-offset.s | 21 | ||||
-rw-r--r-- | test/ELF/relocation-copy-align-common.s | 2 |
5 files changed, 56 insertions, 27 deletions
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index b8c889164..b5b81e959 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -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; } diff --git a/test/ELF/basic-ppc64.s b/test/ELF/basic-ppc64.s index cab130212..d1e47464a 100644 --- a/test/ELF/basic-ppc64.s +++ b/test/ELF/basic-ppc64.s @@ -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: ] @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/test/ELF/linkerscript/nobits-offset.s b/test/ELF/linkerscript/nobits-offset.s index c41414876..051f3f99d 100644 --- a/test/ELF/linkerscript/nobits-offset.s +++ b/test/ELF/linkerscript/nobits-offset.s @@ -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 diff --git a/test/ELF/nobits-offset.s b/test/ELF/nobits-offset.s new file mode 100644 index 000000000..c01047329 --- /dev/null +++ b/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 diff --git a/test/ELF/relocation-copy-align-common.s b/test/ELF/relocation-copy-align-common.s index 124064c71..748f84546 100644 --- a/test/ELF/relocation-copy-align-common.s +++ b/test/ELF/relocation-copy-align-common.s @@ -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 |