Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -758,6 +758,16 @@ return nullptr; } +static MemoryRegion *findRegion(uint64_t Addr) { + for (auto &Pair : Script->MemoryRegions) { + MemoryRegion *M = Pair.second; + if (M->Origin <= Addr && Addr < M->Origin + M->Length) + return M; + } + return nullptr; +} + + // This function assigns offsets to input sections and an output section // for a single sections command (e.g. ".text { *(.text); }"). void LinkerScript::assignOffsets(OutputSection *Sec) { @@ -767,14 +777,30 @@ setDot(Sec->AddrExpr, Sec->Location, false); Ctx->MemRegion = Sec->MemRegion; - Ctx->LMARegion = Sec->LMARegion; + + // If this section has an LMARegion set, overwrite the previous + // LMARegion in the context + if (Sec->LMARegion) + Ctx->LMARegion = Sec->LMARegion; + if (Ctx->MemRegion) Dot = Ctx->MemRegion->CurPos; switchTo(Sec); - if (Sec->LMAExpr) - Ctx->LMAOffset = Sec->LMAExpr().getValue() - Dot; + // If the LMARegion is identical to the MemRegion, the offset should + // be 0 (might happen for implicitly set LMARegions) + if (Sec->MemRegion && Sec->MemRegion == Ctx->LMARegion) { + Ctx->LMAOffset = 0; + } + + // If a section has an LMAExpr set, we need to find the memory region + // the address falls into to reserve some space for it + if (Sec->LMAExpr) { + uint64_t LMAAddr = Sec->LMAExpr().getValue(); + Ctx->LMAOffset = LMAAddr - Dot; + Ctx->LMARegion = findRegion(LMAAddr); + } if (MemoryRegion *MR = Sec->LMARegion) Ctx->LMAOffset = MR->CurPos - Dot; Index: test/ELF/linkerscript/at10.test =================================================================== --- /dev/null +++ test/ELF/linkerscript/at10.test @@ -0,0 +1,33 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/at8.s -o %t.o +# RUN: ld.lld %t.o --script %s -o %t +# RUN: llvm-readelf -sections -program-headers %t | FileCheck %s + +MEMORY { + FLASH : ORIGIN = 0x08000000, LENGTH = 0x100 + RAM : ORIGIN = 0x20000000, LENGTH = 0x200 +} + +SECTIONS { + .text : { *(.text) } > FLASH + .sec1 : AT(0x08000000) { *(.sec1) } > RAM + .sec2 : { *(.sec2) } > RAM + .sec3 : { *(.sec3) } > FLASH +} + +# Make sure we increase the implicit LMA region of .sec2. +# Otherwise, .sec3 will receive a huge load address because of +# unsigned underflow in the calculation of the offset to its +# virtual address. + +# CHECK: Name Type Address Off +# CHECK: .text PROGBITS 0000000008000000 001000 +# CHECK: .sec1 PROGBITS 0000000020000000 001000 +# CHECK: .sec2 PROGBITS 0000000020000008 001008 +# CHECK: .sec3 PROGBITS 0000000008000010 001010 + +# CHECK: Program Headers: +# CHECK: Type Offset VirtAddr PhysAddr +# CHECK-NEXT: LOAD 0x001000 0x0000000020000000 0x0000000008000000 +# CHECK-NEXT: LOAD 0x001010 0x0000000008000010 0x0000000008000010 +# CHECK-NOT: LOAD Index: test/ELF/linkerscript/at9.test =================================================================== --- /dev/null +++ test/ELF/linkerscript/at9.test @@ -0,0 +1,33 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/at8.s -o %t.o +# RUN: ld.lld %t.o --script %s -o %t +# RUN: llvm-readelf -sections -program-headers %t | FileCheck %s + +MEMORY { + FLASH : ORIGIN = 0x08000000, LENGTH = 0x100 + RAM : ORIGIN = 0x20000000, LENGTH = 0x200 +} + +SECTIONS { + .text : { *(.text) } > FLASH + .sec1 : { *(.sec1) } > RAM AT > FLASH + .sec2 : { *(.sec2) } > RAM + .sec3 : { *(.sec3) } > FLASH +} + +# Make sure we increase the implicit LMA region of .sec2. +# Otherwise, .sec3 will receive a huge load address because of +# unsigned underflow in the calculation of the offset to its +# virtual address. + +# CHECK: Name Type Address Off +# CHECK: .text PROGBITS 0000000008000000 001000 +# CHECK: .sec1 PROGBITS 0000000020000000 001000 +# CHECK: .sec2 PROGBITS 0000000020000008 001008 +# CHECK: .sec3 PROGBITS 0000000008000010 001010 + +# CHECK: Program Headers: +# CHECK: Type Offset VirtAddr PhysAddr +# CHECK-NEXT: LOAD 0x001000 0x0000000020000000 0x0000000008000000 +# CHECK-NEXT: LOAD 0x001010 0x0000000008000010 0x0000000008000010 +# CHECK-NOT: LOAD