diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index 7acb89ad0718..ee5293cfee37 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -352,19 +352,19 @@ public: // DefinedRegular symbols. template <class ELFT> struct ElfSym { // The content for __ehdr_start symbol. - static DefinedRegular<ELFT> *EhdrStart; + static DefinedSynthetic *EhdrStart; // The content for _etext and etext symbols. - static DefinedRegular<ELFT> *Etext; - static DefinedRegular<ELFT> *Etext2; + static DefinedSynthetic *Etext; + static DefinedSynthetic *Etext2; // The content for _edata and edata symbols. - static DefinedRegular<ELFT> *Edata; - static DefinedRegular<ELFT> *Edata2; + static DefinedSynthetic *Edata; + static DefinedSynthetic *Edata2; // The content for _end and end symbols. - static DefinedRegular<ELFT> *End; - static DefinedRegular<ELFT> *End2; + static DefinedSynthetic *End; + static DefinedSynthetic *End2; // The content for _gp_disp/__gnu_local_gp symbols for MIPS target. static DefinedRegular<ELFT> *MipsGpDisp; @@ -372,13 +372,13 @@ template <class ELFT> struct ElfSym { static DefinedRegular<ELFT> *MipsGp; }; -template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::EhdrStart; -template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Etext; -template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Etext2; -template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Edata; -template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Edata2; -template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::End; -template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::End2; +template <class ELFT> DefinedSynthetic *ElfSym<ELFT>::EhdrStart; +template <class ELFT> DefinedSynthetic *ElfSym<ELFT>::Etext; +template <class ELFT> DefinedSynthetic *ElfSym<ELFT>::Etext2; +template <class ELFT> DefinedSynthetic *ElfSym<ELFT>::Edata; +template <class ELFT> DefinedSynthetic *ElfSym<ELFT>::Edata2; +template <class ELFT> DefinedSynthetic *ElfSym<ELFT>::End; +template <class ELFT> DefinedSynthetic *ElfSym<ELFT>::End2; template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::MipsGpDisp; template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::MipsLocalGp; template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::MipsGp; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 0715bf04d6de..cee6eb729fdb 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -68,7 +68,7 @@ private: void setPhdrs(); void fixHeaders(); void fixSectionAlignments(); - void fixAbsoluteSymbols(); + void fixPredefinedSymbols(); void openFile(); void writeHeader(); void writeSections(); @@ -208,7 +208,7 @@ template <class ELFT> void Writer<ELFT>::run() { assignFileOffsetsBinary(); setPhdrs(); - fixAbsoluteSymbols(); + fixPredefinedSymbols(); } // It does not make sense try to open the file if we have error already. @@ -648,12 +648,14 @@ void PhdrEntry::add(OutputSectionBase *Sec) { } template <class ELFT> -static void addOptionalSynthetic(StringRef Name, OutputSectionBase *Sec, - typename ELFT::uint Val, - uint8_t StOther = STV_HIDDEN) { +static DefinedSynthetic * +addOptionalSynthetic(StringRef Name, OutputSectionBase *Sec, + typename ELFT::uint Val, uint8_t StOther = STV_HIDDEN) { if (SymbolBody *S = Symtab<ELFT>::X->find(Name)) if (!S->isInCurrentDSO()) - Symtab<ELFT>::X->addSynthetic(Name, Sec, Val, StOther); + return cast<DefinedSynthetic>( + Symtab<ELFT>::X->addSynthetic(Name, Sec, Val, StOther)->body()); + return nullptr; } template <class ELFT> @@ -750,14 +752,16 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() { if (ScriptConfig->HasSections) return; - ElfSym<ELFT>::EhdrStart = Symtab<ELFT>::X->addIgnored("__ehdr_start"); + // __ehdr_start is the location of program headers. + ElfSym<ELFT>::EhdrStart = + addOptionalSynthetic<ELFT>("__ehdr_start", Out<ELFT>::ProgramHeaders, 0); - auto Define = [this](StringRef S, DefinedRegular<ELFT> *&Sym1, - DefinedRegular<ELFT> *&Sym2) { - Sym1 = Symtab<ELFT>::X->addIgnored(S, STV_DEFAULT); + auto Define = [this](StringRef S, DefinedSynthetic *&Sym1, + DefinedSynthetic *&Sym2) { + Sym1 = addOptionalSynthetic<ELFT>(S, nullptr, 0, STV_DEFAULT); assert(S.startswith("_")); S = S.substr(1); - Sym2 = Symtab<ELFT>::X->addIgnored(S, STV_DEFAULT); + Sym2 = addOptionalSynthetic<ELFT>(S, nullptr, 0, STV_DEFAULT); }; Define("_end", ElfSym<ELFT>::End, ElfSym<ELFT>::End2); @@ -1056,6 +1060,11 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { sortSections(); + // This is a bit of a hack. A value of 0 means undef, so we set it + // to 1 t make __ehdr_start defined. The section number is not + // particularly relevant. + Out<ELFT>::ProgramHeaders->SectionIndex = 1; + unsigned I = 1; for (OutputSectionBase *Sec : OutputSections) { Sec->SectionIndex = I++; @@ -1548,34 +1557,44 @@ static uint16_t getELFType() { } // This function is called after we have assigned address and size -// to each section. This function fixes some predefined absolute +// to each section. This function fixes some predefined // symbol values that depend on section address and size. -template <class ELFT> void Writer<ELFT>::fixAbsoluteSymbols() { - // __ehdr_start is the location of program headers. - if (ElfSym<ELFT>::EhdrStart) - ElfSym<ELFT>::EhdrStart->Value = Out<ELFT>::ProgramHeaders->Addr; - - auto Set = [](DefinedRegular<ELFT> *S1, DefinedRegular<ELFT> *S2, uintX_t V) { - if (S1) - S1->Value = V; - if (S2) - S2->Value = V; +template <class ELFT> void Writer<ELFT>::fixPredefinedSymbols() { + auto Set = [](DefinedSynthetic *S1, DefinedSynthetic *S2, + OutputSectionBase *Sec, uint64_t Value) { + if (S1) { + S1->Section = Sec; + S1->Value = Value; + } + if (S2) { + S2->Section = Sec; + S2->Value = Value; + } }; // _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; - Set(ElfSym<ELFT>::End, ElfSym<ELFT>::End2, P.p_vaddr + P.p_memsz); - - uintX_t Val = P.p_vaddr + P.p_filesz; + Last = &P; if (P.p_flags & PF_W) - Set(ElfSym<ELFT>::Edata, ElfSym<ELFT>::Edata2, Val); + LastRW = &P; else - Set(ElfSym<ELFT>::Etext, ElfSym<ELFT>::Etext2, Val); + LastRO = &P; } + if (Last) + Set(ElfSym<ELFT>::End, ElfSym<ELFT>::End2, Last->First, Last->p_memsz); + if (LastRO) + Set(ElfSym<ELFT>::Etext, ElfSym<ELFT>::Etext2, LastRO->First, + LastRO->p_filesz); + if (LastRW) + Set(ElfSym<ELFT>::Edata, ElfSym<ELFT>::Edata2, LastRW->First, + LastRW->p_filesz); // Setup MIPS _gp_disp/__gnu_local_gp symbols which should // be equal to the _gp symbol's value. diff --git a/lld/test/ELF/edata-etext.s b/lld/test/ELF/edata-etext.s index 7723adf94e23..3b0ba49ad1af 100644 --- a/lld/test/ELF/edata-etext.s +++ b/lld/test/ELF/edata-etext.s @@ -18,9 +18,9 @@ # CHECK-NEXT: 3 .bss 00000006 0000000000202004 BSS # CHECK: SYMBOL TABLE: # CHECK-NEXT: 0000000000000000 *UND* 00000000 -# CHECK-NEXT: 0000000000202002 *ABS* 00000000 _edata -# CHECK-NEXT: 000000000020200a *ABS* 00000000 _end -# CHECK-NEXT: 0000000000201001 *ABS* 00000000 _etext +# CHECK-NEXT: 0000000000202002 .data 00000000 _edata +# CHECK-NEXT: 000000000020200a .data 00000000 _end +# CHECK-NEXT: 0000000000201001 .text 00000000 _etext # CHECK-NEXT: 0000000000201000 .text 00000000 _start # RUN: ld.lld -r %t.o -o %t2 diff --git a/lld/test/ELF/ehdr_start.s b/lld/test/ELF/ehdr_start.s index 9172feca5e9c..67d23cf7164e 100644 --- a/lld/test/ELF/ehdr_start.s +++ b/lld/test/ELF/ehdr_start.s @@ -3,7 +3,7 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o # RUN: ld.lld %t.o -o %t # RUN: llvm-objdump -t %t | FileCheck %s -# CHECK: 0000000000200040 *ABS* 00000000 .hidden __ehdr_start +# CHECK: 0000000000200040 .text 00000000 .hidden __ehdr_start .text .global _start, __ehdr_start diff --git a/lld/test/ELF/end-abs.s b/lld/test/ELF/end-abs.s new file mode 100644 index 000000000000..2199ce23ad04 --- /dev/null +++ b/lld/test/ELF/end-abs.s @@ -0,0 +1,11 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t -pie +# RUN: llvm-readobj -r %t | FileCheck %s + +# CHECK: Relocations [ +# CHECK-NEXT: ] + +.global _start +_start: +.long _end - .