Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -111,13 +111,9 @@ void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) { uint64_t Val = E().getValue(); - if (Val < Dot) { - if (InSec) - error(Loc + ": unable to move location counter backward for: " + - CurOutSec->Name); - else - error(Loc + ": unable to move location counter backward"); - } + if (Val < Dot && InSec) + error(Loc + + ": unable to move location counter backward for: " + CurOutSec->Name); Dot = Val; // Update to location counter means update to section size. if (InSec) Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1641,12 +1641,41 @@ SectionHeaderOff + (OutputSectionCommands.size() + 1) * sizeof(Elf_Shdr); } +static std::vector getSectionsInLoad(OutputSection *First) { + std::vector Ret; + for (OutputSectionCommand *Cmd : OutputSectionCommands) + if (Cmd->Sec->FirstInPtLoad == First) + Ret.push_back(Cmd->Sec); + return Ret; +} + +// Using linker script is it possible to assign any virtual addresses +// to sections. We currently support only the case when all sections +// in a PT_LOAD segment have assending VA order. +static void checkSectionsOrder(OutputSection *FirstInPtLoad) { + std::vector V = getSectionsInLoad(FirstInPtLoad); + OutputSection *Prev = nullptr; + for (OutputSection *Sec : V) { + if (Prev && Prev->Addr + Prev->Size > Sec->Addr) + error("section " + Sec->Name + " overlaps or out of order with " + + Prev->Name + " in the same segment" + "\n>>> " + Prev->Name + + " [0x" + utohexstr(Prev->Addr) + ",0x" + + utohexstr(Prev->Addr + Prev->Size) + "]" + "\n>>> " + Sec->Name + + " [0x" + utohexstr(Sec->Addr) + ",0x" + + utohexstr(Sec->Addr + Sec->Size) + "]"); + Prev = Sec; + } +} + // Finalize the program headers. We call this function after we assign // file offsets and VAs to all sections. template void Writer::setPhdrs() { for (PhdrEntry &P : Phdrs) { OutputSection *First = P.First; OutputSection *Last = P.Last; + if (Script->Opt.HasSections && P.p_type == PT_LOAD) + checkSectionsOrder(First); + if (First) { P.p_filesz = Last->Offset - First->Offset; if (Last->Type != SHT_NOBITS) Index: test/ELF/linkerscript/locationcounter-moveback.s =================================================================== --- test/ELF/linkerscript/locationcounter-moveback.s +++ test/ELF/linkerscript/locationcounter-moveback.s @@ -2,8 +2,10 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: echo "SECTIONS {" > %t.script # RUN: echo ". = 0x20; . = 0x10; .text : {} }" >> %t.script -# RUN: not ld.lld %t.o --script %t.script -o %t -shared 2>&1 | FileCheck %s -# CHECK: {{.*}}.script:2: unable to move location counter backward +# RUN: ld.lld %t.o --script %t.script -o %t -shared +# RUN: llvm-objdump -section-headers %t | FileCheck %s +# CHECK: Idx Name Size Address +# CHECK: 1 .text 00000000 0000000000000010 # RUN: echo "SECTIONS { . = 0x20; . = ASSERT(0x1, "foo"); }" > %t2.script # RUN: ld.lld %t.o --script %t2.script -o %t -shared Index: test/ELF/linkerscript/locationcountererr2.s =================================================================== --- test/ELF/linkerscript/locationcountererr2.s +++ test/ELF/linkerscript/locationcountererr2.s @@ -1,9 +1,20 @@ # REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: echo "SECTIONS {" > %t.script -# RUN: echo ". = 0x20; . = 0x10; .text : {} }" >> %t.script -# RUN: not ld.lld %t.o --script %t.script -o %t -shared 2>&1 | FileCheck %s -# CHECK: {{.*}}.script:2: unable to move location counter backward +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "SECTIONS { \ +# RUN: .aaa 0x2000 : { *(.aaa) } \ +# RUN: .bbb 0x1000 : { *(.bbb) } \ +# RUN: }" > %t.script +# RUN: not ld.lld %t.o --script %t.script -o %t 2>&1 | FileCheck %s +# CHECK: error: section .bbb overlaps or out of order with .aaa in the same segment +# CHECK-NEXT: >>> .aaa [0x2000,0x2008] +# CHECK-NEXT: >>> .bbb [0x1000,0x1008] -# RUN: echo "SECTIONS { . = 0x20; . = ASSERT(0x1, "foo"); }" > %t2.script -# RUN: ld.lld %t.o --script %t2.script -o %t -shared +.globl _start +_start: +nop + +.section .aaa, "a" +.quad 0 + +.section .bbb, "a" +.quad 0 Index: test/ELF/linkerscript/out-of-order.s =================================================================== --- test/ELF/linkerscript/out-of-order.s +++ test/ELF/linkerscript/out-of-order.s @@ -1,9 +1,18 @@ # 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 +# RUN: ld.lld -o %t.so --script %t.script %t.o -shared +# RUN: llvm-objdump -section-headers %t.so | FileCheck %s -# CHECK: error: {{.*}}.script:1: unable to move location counter backward +# CHECK: Sections: +# CHECK-NEXT: Idx Name Size Address Type +# CHECK-NEXT: 0 00000000 0000000000000000 +# CHECK-NEXT: 1 .data 00000008 0000000000004000 DATA +# CHECK-NEXT: 2 .dynamic 00000060 0000000000004008 +# CHECK-NEXT: 3 .text 00000008 0000000000002000 TEXT DATA +# CHECK-NEXT: 4 .dynsym 00000018 0000000000002008 +# CHECK-NEXT: 5 .hash 00000010 0000000000002020 +# CHECK-NEXT: 6 .dynstr 00000001 0000000000002030 .quad 0 .data