Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -306,8 +306,13 @@ if (shouldDefine(OutCmd)) addSymbol(OutCmd); - if (V.empty()) + if (V.empty()) { + OutputSectionBase *Empty = new OutputSectionBase( + Cmd->Name, SHT_NULL, SHF_ALLOC | SHF_EXCLUDE); + OutputSections->push_back(Empty); + Out::Pool.emplace_back(Empty); continue; + } for (InputSectionBase *Sec : V) { addSection(Factory, Sec, Cmd->Name); @@ -328,6 +333,23 @@ addSection(Factory, S, getOutputSectionName(S)); } +// Convert synthetic symbol to absolute. Used for symbols defined in +// empty sections. Those sections do not exist in final ELF image +template static void makeAbsolute(SymbolBody *Body) { + auto *Synthetic = cast>(Body); + Symbol *S = Synthetic->symbol(); + const OutputSectionBase *Section = Synthetic->Section; + uint32_t GotIndex = Synthetic->GotIndex; + unsigned DynsymIndex = Synthetic->DynsymIndex; + + replaceBody>(S, Body->getName(), + static_cast(S->Visibility)); + auto *Regular = cast>(Body); + Regular->GotIndex = GotIndex; + Regular->DynsymIndex = DynsymIndex; + Regular->Value += Section->getVA(); +} + // Sets value of a section-defined symbol. Two kinds of // symbols are processed: synthetic symbols, whose value // is an offset from beginning of section and regular @@ -342,6 +364,8 @@ if (auto *Body = dyn_cast>(Cmd->Sym)) { Body->Section = Sec; Body->Value = Cmd->Expression(Sec->getVA() + Off) - Sec->getVA(); + if (Sec->getFlags() & SHF_EXCLUDE) + makeAbsolute(Body); return; } auto *Body = cast>(Cmd->Sym); @@ -412,6 +436,10 @@ } } +template static void removeIf(Range &R, Pred P) { + R.erase(std::remove_if(R.begin(), R.end(), P), R.end()); +} + template static std::vector *> findSections(OutputSectionCommand &Cmd, @@ -420,6 +448,13 @@ for (OutputSectionBase *Sec : Sections) if (Sec->getName() == Cmd.Name) Ret.push_back(Sec); + + // If we get more than one section then try removing empty ones. + if (Ret.size() > 1) + removeIf(Ret, [](OutputSectionBase *Sec) { + return Sec->getFlags() & SHF_EXCLUDE; + }); + return Ret; } @@ -517,6 +552,11 @@ assignOffsets(Cmd); } + // Remove all empty sections from output vector. + removeIf(*OutputSections, [](OutputSectionBase *Sec) { + return Sec->getFlags() & SHF_EXCLUDE; + }); + uintX_t MinVA = std::numeric_limits::max(); for (OutputSectionBase *Sec : *OutputSections) { if (Sec->getFlags() & SHF_ALLOC) @@ -566,6 +606,10 @@ if (!(Sec->getFlags() & SHF_ALLOC)) break; + // Skip empty sections. They shouldn't be written to final image. + if (Sec->getFlags() & SHF_EXCLUDE) + continue; + std::vector PhdrIds = getPhdrIndices(Sec->getName()); if (!PhdrIds.empty()) { // Assign headers specified by linker script Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -778,6 +778,9 @@ unsigned I = 1; for (OutputSectionBase *Sec : OutputSections) { + if (Sec->getFlags() & SHF_EXCLUDE) + continue; + Sec->SectionIndex = I++; Sec->setSHName(Out::ShStrTab->addString(Sec->getName())); } @@ -974,6 +977,10 @@ if (!(Sec->getFlags() & SHF_ALLOC)) break; + // Skip empty sections. They shouldn't be written to final image. + if (Sec->getFlags() & SHF_EXCLUDE) + continue; + // If we meet TLS section then we create TLS header // and put all TLS sections inside for futher use when // assign addresses. Index: test/ELF/linkerscript/symbols-synthetic.s =================================================================== --- test/ELF/linkerscript/symbols-synthetic.s +++ test/ELF/linkerscript/symbols-synthetic.s @@ -40,6 +40,21 @@ # RUN: }" > %t.script # RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t +# Check symbols inside empty section. Also check section 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 @@ -57,6 +72,16 @@ # 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