From 679828ff920b6f879b21a30b3e78a519a07f147b Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Fri, 17 Feb 2017 16:26:13 +0000 Subject: [PATCH] Diagnose another case of the location counter moving backwards. This case should be possible to handle, but it is hard: * In order to create program headers correctly, we have to scan the sections in the order they are in the file. * To find that order, we have to "execute" the linker script. * The linker script can contain SIZEOF_HEADERS. So to support this we have to start with a guess of how many headers we need (3), run the linker script and try to create the program headers. If it turns out we need more headers, we run the script again with a larger SIZEOF_HEADERS. Also, running the linker script depends on knowing the size of the sections, so we have to finalize them. But creating the program headers can change the value stored in some sections, so we have to split size finalization and content finalization. Looks like the last part is also needed for range extension thunks, so we might support this at some point. For now just report an error instead of producing broken files. llvm-svn: 295458 --- lld/ELF/LinkerScript.cpp | 32 +++++++++++++----------- lld/ELF/LinkerScript.h | 1 + lld/test/ELF/linkerscript/out-of-order.s | 10 ++++++++ 3 files changed, 29 insertions(+), 14 deletions(-) create mode 100644 lld/test/ELF/linkerscript/out-of-order.s diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 480b2f0c25b2..9f2ac61b463f 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -91,24 +91,27 @@ static bool isUnderSysroot(StringRef Path) { return false; } +template void LinkerScript::setDot(Expr E, bool InSec) { + uintX_t Val = E(Dot); + if (Val < Dot) { + if (InSec) + error("unable to move location counter backward for: " + CurOutSec->Name); + else + error("unable to move location counter backward"); + } + Dot = Val; + // Update to location counter means update to section size. + if (InSec) + CurOutSec->Size = Dot - CurOutSec->Addr; +} + // Sets value of a symbol. Two kinds of symbols are processed: synthetic // symbols, whose value is an offset from beginning of section and regular // symbols whose value is absolute. template void LinkerScript::assignSymbol(SymbolAssignment *Cmd, bool InSec) { if (Cmd->Name == ".") { - uintX_t Val = Cmd->Expression(Dot); - if (Val < Dot) { - if (InSec) - error("unable to move location counter backward for: " + - CurOutSec->Name); - else - error("unable to move location counter backward"); - } - Dot = Val; - // Update to location counter means update to section size. - if (InSec) - CurOutSec->Size = Dot - CurOutSec->Addr; + setDot(Cmd->Expression, InSec); return; } @@ -566,6 +569,9 @@ void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) { if (!Sec) return; + if (Cmd->AddrExpr && Sec->Flags & SHF_ALLOC) + setDot(Cmd->AddrExpr); + // Handle align (e.g. ".foo : ALIGN(16) { ... }"). if (Cmd->AlignExpr) Sec->updateAlignment(Cmd->AlignExpr(0)); @@ -801,8 +807,6 @@ void LinkerScript::assignAddresses(std::vector &Phdrs) { } auto *Cmd = cast(Base.get()); - if (Cmd->AddrExpr) - Dot = Cmd->AddrExpr(Dot); assignOffsets(Cmd); } diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index 2063db482627..a3b9c128f7ac 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -278,6 +278,7 @@ private: void assignSymbol(SymbolAssignment *Cmd, bool InSec = false); void addSymbol(SymbolAssignment *Cmd); void computeInputSections(InputSectionDescription *); + void setDot(Expr E, bool InSec = false); void discard(ArrayRef *> V); diff --git a/lld/test/ELF/linkerscript/out-of-order.s b/lld/test/ELF/linkerscript/out-of-order.s new file mode 100644 index 000000000000..274a94a6e549 --- /dev/null +++ b/lld/test/ELF/linkerscript/out-of-order.s @@ -0,0 +1,10 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-linux %s -o %t.o +# RUN: echo "SECTIONS { .data 0x4000 : { *(.data) } .text 0x2000 : { *(.text) } }" > %t.script +# RUN: not ld.lld -o %t.so --script %t.script %t.o -shared 2>&1 | FileCheck %s + +# CHECK: error: unable to move location counter backward + +.quad 0 +.data +.quad 0