Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -54,6 +54,7 @@ void sortSections(); void finalizeSections(); void addPredefinedSections(); + void addPredefinedSymbols(); std::vector createPhdrs(); void removeEmptyPTLoad(); @@ -200,6 +201,9 @@ parallelForEach(OutputSections, [](OutputSection *Sec) { Sec->maybeCompress(); }); + // Generate assignments for predefined symbols before assigning addresses. + addPredefinedSymbols(); + Script->assignAddresses(); Script->allocateHeaders(Phdrs); @@ -920,6 +924,80 @@ sortCtorsDtors(findSection(".dtors")); } +// This function generates assignments for predefined symbols and inserts them +// into the commands sequence to be processed at the appropriate time. This +// ensures that the value is going to be correct by the time any references to +// these symbols are processed and is equivalent to defining these symbols +// explicitly in the linker script. +template void Writer::addPredefinedSymbols() { + PhdrEntry *Last = nullptr; + PhdrEntry *LastRO = nullptr; + PhdrEntry *LastRW = nullptr; + for (PhdrEntry *P : Phdrs) { + if (P->p_type != PT_LOAD) + continue; + Last = P; + if (P->p_flags & PF_W) + LastRW = P; + else + LastRO = P; + } + + auto Make = [](DefinedRegular *S) { + auto *Cmd = make( + S->getName(), [=] { return Script->getSymbolValue("", "."); }, ""); + Cmd->Sym = S; + return Cmd; + }; + + auto IsSection = [](OutputSection *Sec) { + return [=](BaseCommand *Base) { return Base == Sec; }; + }; + + auto IsNoBits = [](BaseCommand *Base) { + if (auto *Sec = dyn_cast(Base)) + return Sec->Type == SHT_NOBITS; + return false; + }; + + if (Last) { + // _end is the first location after the uninitialized data region. + auto E = Script->Opt.Commands.end(); + auto I = Script->Opt.Commands.begin(); + I = std::find_if(I, E, IsSection(Last->Last)); + if (I != E) { + if (ElfSym::End1) + Script->Opt.Commands.insert(++I, Make(ElfSym::End1)); + if (ElfSym::End2) + Script->Opt.Commands.insert(++I, Make(ElfSym::End2)); + } + } + if (LastRO) { + // _etext is the first location after the last read-only loadable segment. + auto E = Script->Opt.Commands.end(); + auto I = Script->Opt.Commands.begin(); + I = std::find_if(I, E, IsSection(LastRO->Last)); + if (I != E) { + if (ElfSym::Etext1) + Script->Opt.Commands.insert(++I, Make(ElfSym::Etext1)); + if (ElfSym::Etext2) + Script->Opt.Commands.insert(++I, Make(ElfSym::Etext2)); + } + } + if (LastRW) { + // _edata points to the end of the last non SHT_NOBITS section. + auto E = Script->Opt.Commands.end(); + auto I = Script->Opt.Commands.begin(); + I = std::find_if(std::find_if(I, E, IsSection(LastRW->First)), E, IsNoBits); + if (I != E) { + if (ElfSym::Edata2) + I = Script->Opt.Commands.insert(I, Make(ElfSym::Edata2)); + if (ElfSym::Edata1) + I = Script->Opt.Commands.insert(I, Make(ElfSym::Edata1)); + } + } +} + // We want to find how similar two ranks are. // The more branches in getSectionRank that match, the more similar they are. // Since each branch corresponds to a bit flag, we can just use @@ -1718,42 +1796,6 @@ // to each section. This function fixes some predefined // symbol values that depend on section address and size. template void Writer::fixPredefinedSymbols() { - // _etext is the first location after the last read-only loadable segment. - // _edata is the first location after the last read-write loadable segment. - // _end is the first location after the uninitialized data region. - PhdrEntry *Last = nullptr; - PhdrEntry *LastRO = nullptr; - PhdrEntry *LastRW = nullptr; - for (PhdrEntry *P : Phdrs) { - if (P->p_type != PT_LOAD) - continue; - Last = P; - if (P->p_flags & PF_W) - LastRW = P; - else - LastRO = P; - } - - auto Set = [](DefinedRegular *S, OutputSection *Cmd, uint64_t Value) { - if (S) { - S->Section = Cmd; - S->Value = Value; - } - }; - - if (Last) { - Set(ElfSym::End1, Last->First, Last->p_memsz); - Set(ElfSym::End2, Last->First, Last->p_memsz); - } - if (LastRO) { - Set(ElfSym::Etext1, LastRO->First, LastRO->p_filesz); - Set(ElfSym::Etext2, LastRO->First, LastRO->p_filesz); - } - if (LastRW) { - Set(ElfSym::Edata1, LastRW->First, LastRW->p_filesz); - Set(ElfSym::Edata2, LastRW->First, LastRW->p_filesz); - } - if (ElfSym::Bss) ElfSym::Bss->Section = findSection(".bss"); Index: test/ELF/edata-etext.s =================================================================== --- test/ELF/edata-etext.s +++ test/ELF/edata-etext.s @@ -19,7 +19,7 @@ # CHECK: SYMBOL TABLE: # CHECK-NEXT: 0000000000000000 *UND* 00000000 # CHECK-NEXT: 0000000000202002 .data 00000000 _edata -# CHECK-NEXT: 000000000020200a .data 00000000 _end +# CHECK-NEXT: 000000000020200a .bss 00000000 _end # CHECK-NEXT: 0000000000201001 .text 00000000 _etext # CHECK-NEXT: 0000000000201000 .text 00000000 _start Index: test/ELF/linkerscript/symbol-reserved.s =================================================================== --- test/ELF/linkerscript/symbol-reserved.s +++ test/ELF/linkerscript/symbol-reserved.s @@ -27,6 +27,12 @@ # RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=ALIGN-SUB %s # ALIGN-SUB: 0000000000000006 *ABS* 00000000 .hidden newsym +# RUN: echo "PROVIDE_HIDDEN(newsym = ALIGN(_end, CONSTANT(MAXPAGESIZE)) + 5);" > %t.script +# RUN: ld.lld -o %t1 %t %t.script +# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=RELATIVE %s +# RELATIVE: 0000000000202005 .text 00000000 .hidden newsym +# RELATIVE: 0000000000201007 .text 00000000 _end + # RUN: echo "PROVIDE_HIDDEN(newsym = ALIGN(_end, CONSTANT(MAXPAGESIZE)) + 5);" > %t.script # RUN: ld.lld -o %t1 --script %p/Inputs/symbol-reserved.script %t %t.script # RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=RELATIVE-ADD %s