Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -205,7 +205,7 @@ std::function LMAOffset; }; - llvm::DenseMap NameToOutputSection; + llvm::DenseMap> NameToOutputSection; void addSymbol(SymbolAssignment *Cmd); void assignSymbol(SymbolAssignment *Cmd, bool InSec); @@ -242,8 +242,9 @@ uint64_t Dot; public: - OutputSection *createOutputSection(StringRef Name, StringRef Location); - OutputSection *getOrCreateOutputSection(StringRef Name); + void declareOutputSection(StringRef Name); + OutputSection *defineOutputSection(StringRef Name, StringRef Location); + OutputSection *getOutputSection(StringRef Name); bool hasPhdrsCommands() { return !PhdrsCommands.empty(); } uint64_t getDot() { return Dot; } Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -79,27 +79,45 @@ return getValue() - getSecAddr(); } -OutputSection *LinkerScript::createOutputSection(StringRef Name, +OutputSection *LinkerScript::defineOutputSection(StringRef Name, StringRef Location) { - OutputSection *&SecRef = NameToOutputSection[Name]; - OutputSection *Sec; - if (SecRef && SecRef->Location.empty()) { - // There was a forward reference. - Sec = SecRef; - } else { - Sec = make(Name, SHT_PROGBITS, 0); - if (!SecRef) - SecRef = Sec; + std::vector &V = NameToOutputSection[Name]; + // If we have no output sections with Name or all sections are already defined, + // we should create new section definition. This is used to handle + // multiple output section definitions when constraints are used, for example: + // bar : ONLY_IF_RO { *(...) } + // bar : ONLY_IF_RW { *(...) } + if (V.empty() || V.back()->isDefined()) { + OutputSection *Sec = make(Name, SHT_PROGBITS, 0); + Sec->Location = Location; + V.push_back(Sec); + return Sec; } + + // When we have forward declaration we should define it and return. + OutputSection *Sec = V.back(); Sec->Location = Location; return Sec; } -OutputSection *LinkerScript::getOrCreateOutputSection(StringRef Name) { - OutputSection *&CmdRef = NameToOutputSection[Name]; - if (!CmdRef) - CmdRef = make(Name, SHT_PROGBITS, 0); - return CmdRef; +// Returns first live section by Name. Normally only one section should be live. +// Otherwise commands like SIZEOF(section) will use first alive output section +// for calculation. Ideally we would like to report an error then, but GNU +// linkers allow that and we just follow for simplicity. +OutputSection *LinkerScript::getOutputSection(StringRef Name) { + std::vector &V = NameToOutputSection[Name]; + for (OutputSection *Sec : V) + if (Sec->Live) + return Sec; + return V.front(); +} + +// Used for creating forward references to output section. +void LinkerScript::declareOutputSection(StringRef Name) { + std::vector &V = NameToOutputSection[Name]; + if (!V.empty()) + return; + V.push_back(make(Name, SHT_PROGBITS, 0)); } void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) { @@ -429,7 +447,7 @@ static OutputSection *createSection(InputSectionBase *IS, StringRef OutsecName) { - OutputSection *Sec = Script->createOutputSection(OutsecName, ""); + OutputSection *Sec = Script->defineOutputSection(OutsecName, ""); Sec->addSection(cast(IS)); return Sec; } Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -52,6 +52,10 @@ uint64_t getLMA() const { return Addr + LMAOffset; } template void writeHeaderTo(typename ELFT::Shdr *SHdr); + // Linker script might create forward declarations for output sections. + // This method returns true if section known to have definition. + bool isDefined() { return !Location.empty(); } + unsigned SectionIndex; unsigned SortRank; Index: ELF/ScriptParser.cpp =================================================================== --- ELF/ScriptParser.cpp +++ ELF/ScriptParser.cpp @@ -664,7 +664,7 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) { OutputSection *Cmd = - Script->createOutputSection(OutSec, getCurrentLocation()); + Script->defineOutputSection(OutSec, getCurrentLocation()); if (peek() != ":") readSectionAddressType(Cmd); @@ -971,8 +971,9 @@ } if (Tok == "ADDR") { StringRef Name = readParenLiteral(); - OutputSection *Sec = Script->getOrCreateOutputSection(Name); + Script->declareOutputSection(Name); return [=]() -> ExprValue { + OutputSection *Sec = Script->getOutputSection(Name); checkIfExists(Sec, Location); return {Sec, false, 0, Location}; }; @@ -995,10 +996,11 @@ } if (Tok == "ALIGNOF") { StringRef Name = readParenLiteral(); - OutputSection *Cmd = Script->getOrCreateOutputSection(Name); + Script->declareOutputSection(Name); return [=] { - checkIfExists(Cmd, Location); - return Cmd->Alignment; + OutputSection *Sec = Script->getOutputSection(Name); + checkIfExists(Sec, Location); + return Sec->Alignment; }; } if (Tok == "ASSERT") @@ -1045,10 +1047,11 @@ } if (Tok == "LOADADDR") { StringRef Name = readParenLiteral(); - OutputSection *Cmd = Script->getOrCreateOutputSection(Name); + Script->declareOutputSection(Name); return [=] { - checkIfExists(Cmd, Location); - return Cmd->getLMA(); + OutputSection *Sec = Script->getOutputSection(Name); + checkIfExists(Sec, Location); + return Sec->getLMA(); }; } if (Tok == "ORIGIN") { @@ -1067,11 +1070,14 @@ } if (Tok == "SIZEOF") { StringRef Name = readParenLiteral(); - OutputSection *Cmd = Script->getOrCreateOutputSection(Name); + Script->declareOutputSection(Name); // Linker script does not create an output section if its content is empty. // We want to allow SIZEOF(.foo) where .foo is a section which happened to // be empty. - return [=] { return Cmd->Size; }; + return [=] { + OutputSection *Sec = Script->getOutputSection(Name); + return Sec->Size; + }; } if (Tok == "SIZEOF_HEADERS") return [=] { return elf::getHeaderSize(); }; Index: test/ELF/linkerscript/sections-constraint6.s =================================================================== --- test/ELF/linkerscript/sections-constraint6.s +++ test/ELF/linkerscript/sections-constraint6.s @@ -0,0 +1,37 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "SECTIONS { . = 0x10000; \ +# RUN: symSize1 = SIZEOF(bar); symAddr1 = ADDR(bar); \ +# RUN: bar : ONLY_IF_RO { *(unknown) } \ +# RUN: bar : ONLY_IF_RW { *(foo_aw) } \ +# RUN: symSize2 = SIZEOF(bar); symAddr2 = ADDR(bar); \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t -T %t.script %t.o +# RUN: llvm-readobj -s -t %t | FileCheck %s + +## Check values of symbols are (1) not zeroes and (2) corresponds to +## size and address of bar that contains foo_aw input section. +# CHECK: Sections [ +# CHECK: Name: bar +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x10001 +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 8 +# CHECK: Name: symSize1 +# CHECK-NEXT: Value: 0x8 +# CHECK: Name: symAddr1 +# CHECK-NEXT: Value: 0x10001 +# CHECK: Name: symSize2 +# CHECK-NEXT: Value: 0x8 +# CHECK: Name: symAddr2 +# CHECK-NEXT: Value: 0x10001 + +.section foo_a,"a" +.byte 0 + +.section foo_aw,"aw" +.quad 0