Index: ELF/Relocations.h =================================================================== --- ELF/Relocations.h +++ ELF/Relocations.h @@ -12,6 +12,7 @@ #include "lld/Core/LLVM.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" #include #include @@ -114,6 +115,9 @@ SymbolBody *Sym; }; +template +void reportUndefined(SymbolBody &Sym, InputSectionBase &S, uint64_t Offset); + template void scanRelocations(InputSectionBase &); class ThunkSection; @@ -150,6 +154,17 @@ static inline int64_t getAddend(const typename ELFT::Rela &Rel) { return Rel.r_addend; } + +struct SymbolReference { + InputSectionBase &Sec; + uint64_t Offset; +}; + +// Collect references to __ehdr_start in case we need to report an undefined +// symbol error when the loadable segment containing headers is missing. +struct SymbolReferences { + static SmallVector *EhdrStart; +}; } } Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -63,6 +63,8 @@ using namespace lld; using namespace lld::elf; +SmallVector *SymbolReferences::EhdrStart; + // Construct a message in the following format. // // >>> defined in /home/alice/src/foo.o @@ -671,8 +673,8 @@ } template -static void reportUndefined(SymbolBody &Sym, InputSectionBase &S, - uint64_t Offset) { +void elf::reportUndefined(SymbolBody &Sym, InputSectionBase &S, + uint64_t Offset) { if (Config->UnresolvedSymbols == UnresolvedPolicy::IgnoreAll) return; @@ -838,6 +840,9 @@ if (!Body.isLocal() && Body.isUndefined() && !Body.symbol()->isWeak()) reportUndefined(Body, Sec, Rel.r_offset); + if (SymbolReferences::EhdrStart && ElfSym::EhdrStart == &Body) + SymbolReferences::EhdrStart->push_back({Sec, Rel.r_offset}); + RelExpr Expr = Target->getRelExpr(Type, Body, Sec.Data.begin() + Rel.r_offset); Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -305,6 +305,9 @@ // __bss_start static DefinedRegular *Bss; + // __ehdr_start + static DefinedRegular *EhdrStart; + // etext and _etext static DefinedRegular *Etext1; static DefinedRegular *Etext2; Index: ELF/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -29,6 +29,7 @@ using namespace lld::elf; DefinedRegular *ElfSym::Bss; +DefinedRegular *ElfSym::EhdrStart; DefinedRegular *ElfSym::Etext1; DefinedRegular *ElfSym::Etext2; DefinedRegular *ElfSym::Edata1; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -210,8 +210,12 @@ combineEhFrameSections(); // We need to create some reserved symbols such as _end. Create them. - if (!Config->Relocatable) + if (!Config->Relocatable) { addReservedSymbols(); + if (ElfSym::EhdrStart) + elf::SymbolReferences::EhdrStart = + make>(); + } // Create output sections. Script->OutputSections = &OutputSections; @@ -260,6 +264,19 @@ // we know the size of the sections. removeEmptyPTLoad(); + if (ElfSym::EhdrStart) { + auto PhdrI = + std::find_if(Phdrs.begin(), Phdrs.end(), [](const PhdrEntry &E) { + return E.p_type == PT_LOAD && E.First == Out::ElfHeader && + (E.p_offset & -E.p_align) == 0; + }); + if (PhdrI == Phdrs.end()) { + for (auto &R : *elf::SymbolReferences::EhdrStart) { + reportUndefined(*ElfSym::EhdrStart, R.Sec, R.Offset); + } + } + } + if (!Config->OFormatBinary) assignFileOffsets(); else @@ -861,13 +878,14 @@ if (!In::DynSymTab) Symtab::X->addIgnored("__tls_get_addr"); + // __ehdr_start is the location of ELF file headers. + ElfSym::EhdrStart = + addOptionalRegular("__ehdr_start", Out::ElfHeader, 0, STV_HIDDEN); + // If linker script do layout we do not need to create any standart symbols. if (Script->Opt.HasSections) return; - // __ehdr_start is the location of ELF file headers. - addOptionalRegular("__ehdr_start", Out::ElfHeader, 0, STV_HIDDEN); - auto Add = [](StringRef S) { return addOptionalRegular(S, Out::ElfHeader, 0, STV_DEFAULT); }; @@ -1087,6 +1105,14 @@ } } +template +static void checkUndefined(InputSectionBase &Sec, ArrayRef Rels, + SymbolBody *S) { + for (auto &I : Rels) + if (&Sec.getFile()->getRelocTargetSym(I) == S) + reportUndefined(*S, Sec, I.r_offset); +} + // Create output section objects and add them to OutputSections. template void Writer::finalizeSections() { Out::DebugInfo = findSection(".debug_info"); Index: test/ELF/linkerscript/ehdr_start.s =================================================================== --- test/ELF/linkerscript/ehdr_start.s +++ test/ELF/linkerscript/ehdr_start.s @@ -1,10 +1,47 @@ # REQUIRES: x86 - # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o -# RUN: echo "SECTIONS { }" > %t.script -# RUN: not ld.lld %t.o -script %t.script -o %t 2>&1 | FileCheck %s -# CHECK: error: undefined symbol: __ehdr_start -# CHECK: >>> referenced by {{.*}}:(.text+0x0) + +# RUN: echo "SECTIONS { }" > %t1.script +# RUN: not ld.lld %t.o -script %t1.script -o %t1 2>&1 | FileCheck %s --check-prefix=ERROR +# ERROR: error: undefined symbol: __ehdr_start +# ERROR: >>> referenced by {{.*}}:(.text+0x0) + +# RUN: echo "SECTIONS { \ +# RUN: . = SIZEOF_HEADERS; \ +# RUN: .text : { *(.text*) } \ +# RUN: }" > %t.script +# RUN: ld.lld %t.o -script %t.script -o %t 2>&1 +# RUN: llvm-readobj -symbols %t | FileCheck %s --check-prefix=HEADERS + +# HEADERS: Name: __ehdr_start (1) +# HEADERS-NEXT: Value: 0x0 +# HEADERS-NEXT: Size: 0 +# HEADERS-NEXT: Binding: Local (0x0) +# HEADERS-NEXT: Type: None (0x0) +# HEADERS-NEXT: Other [ (0x2) +# HEADERS-NEXT: STV_HIDDEN (0x2) +# HEADERS-NEXT: ] +# HEADERS-NEXT: Section: .text (0x1) + +# RUN: echo "SECTIONS { \ +# RUN: . = SIZEOF_HEADERS; \ +# RUN: .text : { *(.text*) } : text \ +# RUN: } \ +# RUN: PHDRS { \ +# RUN: text PT_LOAD FILEHDR PHDRS; \ +# RUN: }" > %t.script +# RUN: ld.lld %t.o -script %t.script -o %t 2>&1 +# RUN: llvm-readobj -symbols %t | FileCheck %s --check-prefix=PHDRS + +# PHDRS: Name: __ehdr_start (1) +# PHDRS-NEXT: Value: 0x0 +# PHDRS-NEXT: Size: 0 +# PHDRS-NEXT: Binding: Local (0x0) +# PHDRS-NEXT: Type: None (0x0) +# PHDRS-NEXT: Other [ (0x2) +# PHDRS-NEXT: STV_HIDDEN (0x2) +# PHDRS-NEXT: ] +# PHDRS-NEXT: Section: .text (0x1) .text .global _start, __ehdr_start