summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorge Rimar <grimar@accesssoftek.com>2018-03-13 08:47:17 +0000
committerGeorge Rimar <grimar@accesssoftek.com>2018-03-13 08:47:17 +0000
commit2313086726341dab02dc6381071327cb694eb57d (patch)
tree433d5fc6d24cc39f639516fcd479625fdc6fc0b7
parent5612bb292c861f41c71abf2cb3e48fff93a3f34f (diff)
downloadbcm5719-llvm-2313086726341dab02dc6381071327cb694eb57d.tar.gz
bcm5719-llvm-2313086726341dab02dc6381071327cb694eb57d.zip
[ELF] - Restrict section offsets that exceeds file size.
This is part of PR36515. With some linkerscripts it is possible to get file offset overlaps and overflows. Currently LLD checks overlaps in checkNoOverlappingSections(). And also we allow broken output with --no-inhibit-exec. Problem is that sometimes final offset of sections is completely broken and we calculate output file size wrong and might crash. Patch implements check to verify that there is no output section which offset exceeds file size. Differential revision: https://reviews.llvm.org/D43819 llvm-svn: 327376
-rw-r--r--lld/ELF/Writer.cpp31
-rw-r--r--lld/test/ELF/linkerscript/Inputs/sections-va-overflow.s6
-rw-r--r--lld/test/ELF/linkerscript/sections-va-overflow.test22
3 files changed, 53 insertions, 6 deletions
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index a59e19b8abc..fc292d6f461 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1873,6 +1873,12 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() {
FileSize = alignTo(Off, Config->Wordsize);
}
+static std::string rangeToString(uint64_t Addr, uint64_t Len) {
+ if (Len == 0)
+ return "<empty range at 0x" + utohexstr(Addr) + ">";
+ return "[0x" + utohexstr(Addr) + ", 0x" + utohexstr(Addr + Len - 1) + "]";
+}
+
// Assign file offsets to output sections.
template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
uint64_t Off = 0;
@@ -1897,6 +1903,25 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
SectionHeaderOff = alignTo(Off, Config->Wordsize);
FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr);
+
+ // Our logic assumes that sections have rising VA within the same segment.
+ // With use of linker scripts it is possible to violate this rule and get file
+ // offset overlaps or overflows. That should never happen with a valid script
+ // which does not move the location counter backwards and usually scripts do
+ // not do that. Unfortunately, there are apps in the wild, for example, Linux
+ // kernel, which control segment distribution explicitly and move the counter
+ // backwards, so we have to allow doing that to support linking them. We
+ // perform non-critical checks for overlaps in checkNoOverlappingSections(),
+ // but here we want to prevent file size overflows because it would crash the
+ // linker.
+ for (OutputSection *Sec : OutputSections) {
+ if (Sec->Type == SHT_NOBITS)
+ continue;
+ if ((Sec->Offset > FileSize) || (Sec->Offset + Sec->Size > FileSize))
+ error("unable to place section " + Sec->Name + " at file offset " +
+ rangeToString(Sec->Offset, Sec->Offset + Sec->Size) +
+ "; check your linker script for overflows");
+ }
}
// Finalize the program headers. We call this function after we assign
@@ -1935,12 +1960,6 @@ template <class ELFT> void Writer<ELFT>::setPhdrs() {
}
}
-static std::string rangeToString(uint64_t Addr, uint64_t Len) {
- if (Len == 0)
- return "<empty range at 0x" + utohexstr(Addr) + ">";
- return "[0x" + utohexstr(Addr) + ", 0x" + utohexstr(Addr + Len - 1) + "]";
-}
-
// Check whether sections overlap for a specific address range (file offsets,
// load and virtual adresses).
//
diff --git a/lld/test/ELF/linkerscript/Inputs/sections-va-overflow.s b/lld/test/ELF/linkerscript/Inputs/sections-va-overflow.s
new file mode 100644
index 00000000000..6bb049031c7
--- /dev/null
+++ b/lld/test/ELF/linkerscript/Inputs/sections-va-overflow.s
@@ -0,0 +1,6 @@
+.global _start
+_start:
+ retq
+
+.bss
+.space 0x2000
diff --git a/lld/test/ELF/linkerscript/sections-va-overflow.test b/lld/test/ELF/linkerscript/sections-va-overflow.test
new file mode 100644
index 00000000000..7ede6ecc3de
--- /dev/null
+++ b/lld/test/ELF/linkerscript/sections-va-overflow.test
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/sections-va-overflow.s -o %t.o
+# RUN: not ld.lld -o /dev/null --script %s %t.o 2>&1 | FileCheck %s -check-prefix=ERR
+
+PHDRS {
+ ph_headers PT_PHDR PHDRS;
+ ph_text PT_LOAD FILEHDR PHDRS FLAGS (0x1 | 0x4);
+}
+
+SECTIONS {
+ . = 0xffffffff20000000;
+ .text : { *(.text*) } : ph_text
+ .test 0x1000 : { BYTE(0) }
+ .bss : { *(.bss*) }
+}
+
+## Section .test has VA 0x1000 and placed in the same segment as section .text
+## with VA 0xffffffff20000000. That might be technically correct, but most probably
+## is a result of a broken script file and causes file offset calculation overflow.
+## It seems we do not have to support it, so we don't and we report an error in this case.
+# ERR: error: unable to place section .text at file offset [0xFFFFFFFF20000000, 0xFFFFFFFE40000000]; check your linker script for overflows
+# ERR-NOT: unable to place section .bss
OpenPOWER on IntegriCloud