Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -102,6 +102,7 @@ bool NonAlloc = false; bool Noload = false; bool ExpressionsUseSymbols = false; + bool InOverlay = false; template void finalize(); template void writeTo(uint8_t *Buf); Index: ELF/ScriptParser.cpp =================================================================== --- ELF/ScriptParser.cpp +++ ELF/ScriptParser.cpp @@ -79,7 +79,9 @@ uint32_t readFill(); uint32_t parseFill(StringRef Tok); void readSectionAddressType(OutputSection *Cmd); + OutputSection *readOverlaySectionDescription(StringRef OutSec); OutputSection *readOutputSectionDescription(StringRef OutSec); + std::vector readOverlay(); std::vector readOutputSectionPhdrs(); InputSectionDescription *readInputSectionDescription(StringRef Tok); StringMatcher readFilePatterns(); @@ -427,6 +429,45 @@ expect(")"); } +std::vector ScriptParser::readOverlay() { + // VA and LMA expressions are optional, though for simplicity of + // implementation we assume they are not. That is what OVERLAY was designed + // for first of all: to allow sections with overlapping VAs at different LMAs. + Expr AddrExpr = readExpr(); + expect(":"); + expect("AT"); + Expr LMAExpr = readParenExpr(); + expect("{"); + + std::vector V; + while (!errorCount() && !consume("}")) { + OutputSection *Prev = V.empty() ? nullptr : cast(V.back()); + OutputSection *OS = readOverlaySectionDescription(next()); + + // VA is the same for all sections. The LMAs are consecutive in memory + // starting from the base load address specified. + OS->AddrExpr = AddrExpr; + if (Prev) + OS->LMAExpr = [=] { return Prev->getLMA() + Prev->Size; }; + else + OS->LMAExpr = LMAExpr; + V.push_back(OS); + } + + // According to the specification, at the end of the overlay, the location + // counter should be equal to the overlay base address plus size of the + // largest section seen in the overlay. + // Here we want to create the Dot assignment command to achieve that. + Expr MoveDotExpr = [=] { + uint64_t MaxSize = 0; + for (BaseCommand *Cmd : V) + MaxSize = std::max(MaxSize, cast(Cmd)->Size); + return AddrExpr().getValue() + MaxSize; + }; + V.push_back(make(".", MoveDotExpr, getCurrentLocation())); + return V; +} + void ScriptParser::readSections() { Script->HasSectionsCommand = true; @@ -439,6 +480,12 @@ std::vector V; while (!errorCount() && !consume("}")) { StringRef Tok = next(); + if (Tok == "OVERLAY") { + for (BaseCommand *Cmd : readOverlay()) + V.push_back(Cmd); + continue; + } + BaseCommand *Cmd = readProvideOrAssignment(Tok); if (!Cmd) { if (Tok == "ASSERT") @@ -672,6 +719,17 @@ }; } +OutputSection *ScriptParser::readOverlaySectionDescription(StringRef OutSec) { + OutputSection *Cmd = + Script->createOutputSection(OutSec, getCurrentLocation()); + Cmd->InOverlay = true; + expect("{"); + while (!errorCount() && !consume("}")) + Cmd->SectionCommands.push_back(readInputSectionRules(next())); + Cmd->Phdrs = readOutputSectionPhdrs(); + return Cmd; +} + OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) { OutputSection *Cmd = Script->createOutputSection(OutSec, getCurrentLocation()); Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -2044,9 +2044,12 @@ }; } // namespace +enum class OverlapKind : uint8_t { File, VirtualAddress, LoadAddress }; + // Check whether sections overlap for a specific address range (file offsets, // load and virtual adresses). -static void checkOverlap(StringRef Name, std::vector &Sections) { +static void checkOverlap(OverlapKind Kind, + std::vector &Sections) { std::sort(Sections.begin(), Sections.end(), [=](const SectionOffset &A, const SectionOffset &B) { return A.Offset < B.Offset; @@ -2054,15 +2057,24 @@ // Finding overlap is easy given a vector is sorted by start position. // If an element starts before the end of the previous element, they overlap. + StringRef OverlapName[] = {"file", "virtual address", "load address"}; for (size_t I = 1, End = Sections.size(); I < End; ++I) { SectionOffset A = Sections[I - 1]; SectionOffset B = Sections[I]; - if (B.Offset < A.Offset + A.Sec->Size) - errorOrWarn( - "section " + A.Sec->Name + " " + Name + " range overlaps with " + - B.Sec->Name + "\n>>> " + A.Sec->Name + " range is " + - rangeToString(A.Offset, A.Sec->Size) + "\n>>> " + B.Sec->Name + - " range is " + rangeToString(B.Offset, B.Sec->Size)); + if (B.Offset >= A.Offset + A.Sec->Size) + continue; + + // If both sections are in OVERLAY we allow the overlapping of virtual + // addresses, because it is what OVERLAY was designed for. + if (Kind == OverlapKind::VirtualAddress && A.Sec->InOverlay && + B.Sec->InOverlay) + continue; + + errorOrWarn("section " + A.Sec->Name + " " + OverlapName[(uint8_t)Kind] + + " range overlaps with " + B.Sec->Name + "\n>>> " + A.Sec->Name + + " range is " + rangeToString(A.Offset, A.Sec->Size) + "\n>>> " + + B.Sec->Name + " range is " + + rangeToString(B.Offset, B.Sec->Size)); } } @@ -2090,7 +2102,7 @@ if (0 < Sec->Size && Sec->Type != SHT_NOBITS && (!Config->OFormatBinary || (Sec->Flags & SHF_ALLOC))) FileOffs.push_back({Sec, Sec->Offset}); - checkOverlap("file", FileOffs); + checkOverlap(OverlapKind::File, FileOffs); // When linking with -r there is no need to check for overlapping virtual/load // addresses since those addresses will only be assigned when the final @@ -2107,7 +2119,7 @@ for (OutputSection *Sec : OutputSections) if (0 < Sec->Size && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS)) VMAs.push_back({Sec, Sec->Addr}); - checkOverlap("virtual address", VMAs); + checkOverlap(OverlapKind::VirtualAddress, VMAs); // Finally, check that the load addresses don't overlap. This will usually be // the same as the virtual addresses but can be different when using a linker @@ -2116,7 +2128,7 @@ for (OutputSection *Sec : OutputSections) if (0 < Sec->Size && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS)) LMAs.push_back({Sec, Sec->getLMA()}); - checkOverlap("load address", LMAs); + checkOverlap(OverlapKind::LoadAddress, LMAs); } // The entry point address is chosen in the following ways. Index: test/ELF/linkerscript/overlay-reject.test =================================================================== --- test/ELF/linkerscript/overlay-reject.test +++ test/ELF/linkerscript/overlay-reject.test @@ -0,0 +1,13 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o +# RUN: not ld.lld %t.o --script %s -o %t 2>&1 | FileCheck %s + +# CHECK: {{.*}}.test:{{.*}}: { expected, but got 0x3000 +# CHECK-NEXT: >>> .out.aaa 0x3000 : { *(.aaa) } +# CHECK-NEXT: >>> ^ + +SECTIONS { + OVERLAY 0x1000 : AT ( 0x2000 ) { + .out.aaa 0x3000 : { *(.aaa) } + } +} Index: test/ELF/linkerscript/overlay-reject2.test =================================================================== --- test/ELF/linkerscript/overlay-reject2.test +++ test/ELF/linkerscript/overlay-reject2.test @@ -0,0 +1,17 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o +# RUN: not ld.lld %t.o --script %s -o %t 2>&1 | FileCheck %s + +# CHECK: {{.*}}.test:{{.*}}: { expected, but got AX +# CHECK-NEXT: >>> .out.aaa { *(.aaa) } > AX AT>FLASH +# CHECK-NEXT: >>> ^ + +MEMORY { + AX (ax) : ORIGIN = 0x3000, LENGTH = 0x4000 +} + +SECTIONS { + OVERLAY 0x1000 : AT ( 0x2000 ) { + .out.aaa { *(.aaa) } > AX AT>FLASH + } +} Index: test/ELF/linkerscript/overlay.test =================================================================== --- test/ELF/linkerscript/overlay.test +++ test/ELF/linkerscript/overlay.test @@ -0,0 +1,30 @@ +# REQUIRES: x86 +# RUN: echo 'nop; .section .small, "a"; .long 0; .section .big, "a"; .quad 1;' \ +# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.o +# RUN: ld.lld %t.o --script %s -o %t + +SECTIONS { + OVERLAY 0x1000 : AT ( 0x4000 ) { + .out.big { *(.big) } + .out.small { *(.small) } + } +} + +## Here we check that can handle OVERLAY which will produce sections +## .out.big and .out.small with the same starting VAs, but different LMAs. +## Section .big is larger than .small, we check that placing of section +## .text does not cause overlapping error and that +## .text's VA is 0x1000 + max(sizeof(.out.big), sizeof(.out.small)). + +# RUN: llvm-readobj -sections -program-headers -elf-output-style=GNU %t | FileCheck %s + +# CHECK: Section Headers: +# CHECK: Name Type Address Off Size +# CHECK: .out.big PROGBITS 0000000000001000 001000 000008 +# CHECK: .out.small PROGBITS 0000000000001000 002000 000004 +# CHECK: .text PROGBITS 0000000000001008 002008 000001 + +# CHECK: Program Headers: +# CHECK: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +# CHECK-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000004000 0x000008 0x000008 R E 0x1000 +# CHECK-NEXT: LOAD 0x002000 0x0000000000001000 0x0000000000004008 0x000009 0x000009 R E 0x1000