Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1823,6 +1823,12 @@ } } +static std::string rangeToString(uint64_t Addr, uint64_t Len) { + if (Len == 0) + return ""; + return "[0x" + utohexstr(Addr) + " -> 0x" + utohexstr(Addr + Len - 1) + "]"; +} + // Adjusts the file alignment for a given output section and returns // its new file offset. The file offset must be the same with its // virtual address (modulo the page size) so that the loader can load @@ -1893,6 +1899,15 @@ SectionHeaderOff = alignTo(Off, Config->Wordsize); FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr); + + // It is possible to get file offset overlaps or overflows with linker + // script. We perform checks required in checkNoOverlappingSections() and want + // to fully restrict file size overflows here because it would crash linker. + for (OutputSection *Sec : OutputSections) + if (Sec->Offset >= 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 @@ -1931,13 +1946,6 @@ } } -static std::string rangeToString(uint64_t Addr, uint64_t Len) { - if (Len == 0) - return ""; - return "[0x" + utohexstr(Addr) + " -> 0x" + - utohexstr(Addr + Len - 1) + "]"; -} - // Check whether sections overlap for a specific address range (file offsets, // load and virtual adresses). // Index: test/ELF/linkerscript/sections-va-overflow.s =================================================================== --- test/ELF/linkerscript/sections-va-overflow.s +++ test/ELF/linkerscript/sections-va-overflow.s @@ -0,0 +1,17 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "PHDRS{ ph_headers PT_PHDR PHDRS;" > %t.script +# RUN: echo "ph_text PT_LOAD FILEHDR PHDRS FLAGS (0x1 | 0x4); }" >> %t.script +# RUN: echo "SECTIONS { . = 0xffffffff20000000;" >> %t.script +# RUN: echo " .text : { *(.text*) } : ph_text .test 0x1000 : { BYTE(0) } }" >> %t.script +# RUN: not ld.lld -o %t.so --script %t.script %t.o 2>&1 | FileCheck %s -check-prefix=ERR + +## 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 broken script file and causes file offset calculation overlow. +## Seems we do not have to support it, so we don't and we report error in this case. +# ERR: error: unable to place section .text at file offset [0xFFFFFFFF20000000 -> 0xFFFFFFFE40000000], check your linker script for overflows + +.global _start +_start: + retq