Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -185,6 +185,9 @@ std::vector *> getInputSections(const InputSectionDescription *); + std::vector *> + findSections(StringRef Name, ConstraintKind Constraint); + void discard(OutputSectionCommand &Cmd); std::vector *> @@ -198,6 +201,7 @@ size_t getPhdrIndex(StringRef PhdrName); uintX_t Dot; + std::vector *> EmptySections; }; // Variable template is a C++14 feature, so we can't template Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -164,7 +164,9 @@ } } -static bool checkConstraint(uint64_t Flags, ConstraintKind Kind) { +static bool satisfiesConstraint(uint64_t Flags, ConstraintKind Kind) { + if (Kind == ConstraintKind::NoConstraint) + return true; bool RO = (Kind == ConstraintKind::ReadOnly); bool RW = (Kind == ConstraintKind::ReadWrite); bool Writable = Flags & SHF_WRITE; @@ -177,7 +179,7 @@ if (Kind == ConstraintKind::NoConstraint) return true; return llvm::all_of(Sections, [=](InputSectionBase *Sec) { - return checkConstraint(Sec->getSectionHdr()->sh_flags, Kind); + return satisfiesConstraint(Sec->getSectionHdr()->sh_flags, Kind); }); } @@ -238,8 +240,12 @@ } std::vector *> V = createInputSectionList(*Cmd); - if (V.empty()) + if (V.empty()) { + EmptySections.push_back( + new OutputSectionBase(Cmd->Name, SHT_NULL, SHF_ALLOC)); + Out::Pool.emplace_back(EmptySections.back()); continue; + } for (InputSectionBase *Sec : V) { OutputSectionBase *OutSec; @@ -293,6 +299,39 @@ Body->Value = Cmd->Expression(Sec->getVA() + Off); } +// Empty section is a section defined in linker script without +// any input section or other kind of data associated with it. +// Empty sections may occur when same linker script is used to +// link multiple applications, which may or may not contain +// EH frames, TLS data, e.t.c. Those sections are not written +// to output file and section-defined symbols should be made +// absolute, otherwise we'll have invalid entries in the symbol table. +template +void addEmptySectionSymbols(OutputSectionCommand *Cmd, + OutputSectionBase *Sec) { + for (std::unique_ptr &Base : Cmd->Commands) { + DefinedRegular *Regular; + auto *AssignCmd = dyn_cast(Base.get()); + if (!AssignCmd || !AssignCmd->Sym) + continue; + + Regular = dyn_cast>(AssignCmd->Sym); + if (!Regular) { + auto *Synthetic = cast>(AssignCmd->Sym); + Symbol *S = Synthetic->symbol(); + auto GotIndex = Synthetic->GotIndex; + auto DynsymIndex = Synthetic->DynsymIndex; + + replaceBody>(S, Cmd->Name, + static_cast(S->Visibility)); + Regular = cast>(AssignCmd->Sym); + Regular->GotIndex = GotIndex; + Regular->DynsymIndex = DynsymIndex; + } + Regular->Value = AssignCmd->Expression(Sec->getVA()); + } +} + // Linker script may define start and end symbols for special section types, // like .got, .eh_frame_hdr, .eh_frame and others. Those sections are not a list // of regular input input sections, therefore our way of defining symbols for @@ -319,6 +358,12 @@ template void assignOffsets(OutputSectionCommand *Cmd, OutputSectionBase *Sec) { + // Add symbols for empty output section. + if (Sec->getType() == SHT_NULL) { + addEmptySectionSymbols(Cmd, Sec); + return; + } + auto *OutSec = dyn_cast>(Sec); if (!OutSec) { Sec->assignOffsets(); @@ -368,14 +413,20 @@ } template -static std::vector *> -findSections(OutputSectionCommand &Cmd, - ArrayRef *> Sections) { +std::vector *> +LinkerScript::findSections(StringRef Name, ConstraintKind Constraint) { std::vector *> Ret; - for (OutputSectionBase *Sec : Sections) - if (Sec->getName() == Cmd.Name && - checkConstraint(Sec->getFlags(), Cmd.Constraint)) + for (OutputSectionBase *Sec : *OutputSections) + if (Sec->getName() == Name && + satisfiesConstraint(Sec->getFlags(), Constraint)) Ret.push_back(Sec); + + if (Ret.empty()) + for (OutputSectionBase *Sec : EmptySections) + if (Sec->getName() == Name) { + Ret.push_back(Sec); + break; + } return Ret; } @@ -413,7 +464,7 @@ auto *Cmd = cast(Base.get()); for (OutputSectionBase *Sec : - findSections(*Cmd, *OutputSections)) { + findSections(Cmd->Name, Cmd->Constraint)) { if (Cmd->AddrExpr) Dot = Cmd->AddrExpr(Dot); @@ -556,27 +607,27 @@ template uint64_t LinkerScript::getOutputSectionAddress(StringRef Name) { - for (OutputSectionBase *Sec : *OutputSections) - if (Sec->getName() == Name) - return Sec->getVA(); + const auto &Sections = findSections(Name, ConstraintKind::NoConstraint); + if (!Sections.empty()) + return Sections.front()->getVA(); error("undefined section " + Name); return 0; } template uint64_t LinkerScript::getOutputSectionSize(StringRef Name) { - for (OutputSectionBase *Sec : *OutputSections) - if (Sec->getName() == Name) - return Sec->getSize(); + const auto &Sections = findSections(Name, ConstraintKind::NoConstraint); + if (!Sections.empty()) + return Sections.front()->getSize(); error("undefined section " + Name); return 0; } template uint64_t LinkerScript::getOutputSectionAlign(StringRef Name) { - for (OutputSectionBase *Sec : *OutputSections) - if (Sec->getName() == Name) - return Sec->getAlignment(); + const auto &Sections = findSections(Name, ConstraintKind::NoConstraint); + if (!Sections.empty()) + return Sections.front()->getAlignment(); error("undefined section " + Name); return 0; } Index: test/ELF/linkerscript/symbols-synthetic.s =================================================================== --- test/ELF/linkerscript/symbols-synthetic.s +++ test/ELF/linkerscript/symbols-synthetic.s @@ -53,6 +53,21 @@ # RUN: }" > %t.script # RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t +# Check symbols inside empty section. Also check its size and address. +# RUN: echo "SECTIONS { \ +# RUN: .aaa : { \ +# RUN: PROVIDE_HIDDEN(_begin_sec = .); \ +# RUN: *(.bbb) \ +# RUN: *(.ccc) \ +# RUN: PROVIDE_HIDDEN(_end_sec = .); \ +# RUN: PROVIDE_HIDDEN(_end_sec_abs = ABSOLUTE(.)); } \ +# RUN: addr_of_aaa = ADDR(.aaa); \ +# RUN: size_of_aaa = SIZEOF(.aaa); \ +# RUN: align_of_aaa = ALIGNOF(.aaa); \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=EMPTY %s + # SIMPLE: 0000000000000160 .foo 00000000 .hidden _end_sec # SIMPLE-NEXT: 0000000000000158 .foo 00000000 _begin_sec # SIMPLE-NEXT: 0000000000000160 *ABS* 00000000 _end_sec_abs @@ -69,8 +84,17 @@ # SIMPLE-NEXT: 0000000000001010 *ABS* 00000000 __eh_frame_hdr_start2 # SIMPLE-NEXT: 0000000000001018 .eh_frame_hdr 00000000 __eh_frame_hdr_end # SIMPLE-NEXT: 0000000000001020 *ABS* 00000000 __eh_frame_hdr_end2 + # ERROR: section '.eh_frame_hdr' supports only start and end symbols +# EMPTY: 0000000000000120 *ABS* 00000000 .hidden _begin_sec +# EMPTY-NEXT: 0000000000000120 *ABS* 00000000 .hidden _end_sec +# EMPTY-NEXT: 0000000000000120 *ABS* 00000000 .hidden _end_sec_abs +# EMPTY-NEXT: 0000000000000160 .text 00000000 _start +# EMPTY-NEXT: 0000000000000120 *ABS* 00000000 addr_of_aaa +# EMPTY-NEXT: 0000000000000000 *ABS* 00000000 size_of_aaa +# EMPTY-NEXT: 0000000000000001 *ABS* 00000000 align_of_aaa + .global _start _start: nop