diff options
| -rw-r--r-- | lld/ELF/OutputSections.cpp | 2 | ||||
| -rw-r--r-- | lld/ELF/SymbolTable.cpp | 2 | ||||
| -rw-r--r-- | lld/ELF/SymbolTable.h | 2 | ||||
| -rw-r--r-- | lld/ELF/Symbols.cpp | 9 | ||||
| -rw-r--r-- | lld/ELF/Symbols.h | 5 | ||||
| -rw-r--r-- | lld/ELF/Writer.cpp | 42 | ||||
| -rw-r--r-- | lld/test/ELF/relocation-relative-absolute.s | 12 | ||||
| -rw-r--r-- | lld/test/ELF/relocation-relative-synthetic.s | 11 | ||||
| -rw-r--r-- | lld/test/ELF/relocation-relative-weak.s | 14 |
9 files changed, 78 insertions, 21 deletions
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index 922de777520..94d3f68b1a8 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -1496,7 +1496,7 @@ const OutputSectionBase<ELFT> * SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) { switch (Sym->kind()) { case SymbolBody::DefinedSyntheticKind: - return &cast<DefinedSynthetic<ELFT>>(Sym)->Section; + return cast<DefinedSynthetic<ELFT>>(Sym)->Section; case SymbolBody::DefinedRegularKind: { auto &D = cast<DefinedRegular<ELFT>>(*Sym); if (D.Section) diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index 53a2929563c..b0bd525009e 100644 --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -388,7 +388,7 @@ Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, uint8_t Binding, template <typename ELFT> Symbol *SymbolTable<ELFT>::addSynthetic(StringRef N, - OutputSectionBase<ELFT> &Section, + OutputSectionBase<ELFT> *Section, uintX_t Value) { Symbol *S; bool WasInserted; diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h index 16de475fffb..0a942faa09c 100644 --- a/lld/ELF/SymbolTable.h +++ b/lld/ELF/SymbolTable.h @@ -64,7 +64,7 @@ public: Symbol *addRegular(StringRef Name, const Elf_Sym &Sym, InputSectionBase<ELFT> *Section); Symbol *addRegular(StringRef Name, uint8_t Binding, uint8_t StOther); - Symbol *addSynthetic(StringRef N, OutputSectionBase<ELFT> &Section, + Symbol *addSynthetic(StringRef N, OutputSectionBase<ELFT> *Section, uintX_t Value); void addShared(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym, const typename ELFT::Verdef *Verdef); diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index 4e94229f3e3..2768f1865a2 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -36,9 +36,12 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body, switch (Body.kind()) { case SymbolBody::DefinedSyntheticKind: { auto &D = cast<DefinedSynthetic<ELFT>>(Body); + const OutputSectionBase<ELFT> *Sec = D.Section; + if (!Sec) + return D.Value; if (D.Value == DefinedSynthetic<ELFT>::SectionEnd) - return D.Section.getVA() + D.Section.getSize(); - return D.Section.getVA() + D.Value; + return Sec->getVA() + Sec->getSize(); + return Sec->getVA() + D.Value; } case SymbolBody::DefinedRegularKind: { auto &D = cast<DefinedRegular<ELFT>>(Body); @@ -208,7 +211,7 @@ Undefined::Undefined(uint32_t NameOffset, uint8_t StOther, uint8_t Type) template <typename ELFT> DefinedSynthetic<ELFT>::DefinedSynthetic(StringRef N, uintX_t Value, - OutputSectionBase<ELFT> &Section) + OutputSectionBase<ELFT> *Section) : Defined(SymbolBody::DefinedSyntheticKind, N, STV_HIDDEN, 0 /* Type */), Value(Value), Section(Section) {} diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index 16ca122a635..b66abb479f2 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -237,11 +237,12 @@ InputSectionBase<ELFT> *DefinedRegular<ELFT>::NullInputSection; // The difference from the regular symbol is that DefinedSynthetic symbols // don't belong to any input files or sections. Thus, its constructor // takes an output section to calculate output VA, etc. +// If Section is null, this symbol is relative to the image base. template <class ELFT> class DefinedSynthetic : public Defined { public: typedef typename ELFT::uint uintX_t; DefinedSynthetic(StringRef N, uintX_t Value, - OutputSectionBase<ELFT> &Section); + OutputSectionBase<ELFT> *Section); static bool classof(const SymbolBody *S) { return S->kind() == SymbolBody::DefinedSyntheticKind; @@ -252,7 +253,7 @@ public: static const uintX_t SectionEnd = uintX_t(-1); uintX_t Value; - const OutputSectionBase<ELFT> &Section; + const OutputSectionBase<ELFT> *Section; }; class Undefined : public SymbolBody { diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 00004e777a0..093fac8dfcb 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -454,6 +454,20 @@ static bool isRelRelative(RelExpr E, uint32_t Type, const SymbolBody &Body) { if (!AbsVal && RelE) return true; + // Relative relocation to an absolute value. This is normally unrepresentable, + // but if the relocation refers to a weak undefined symbol, we allow it to + // resolve to the image base. This is a little strange, but it allows us to + // link function calls to such symbols. Normally such a call will be guarded + // with a comparison, which will load a zero from the GOT. + if (AbsVal && RelE) { + if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) + return true; + StringRef S = getELFRelocationTypeName(Config->EMachine, Type); + error("relocation " + S + " cannot refer to absolute symbol " + + Body.getName()); + return true; + } + return Target->usesOnlyLowPageBits(Type); } @@ -1067,7 +1081,7 @@ bool Writer<ELFT>::isDiscarded(InputSectionBase<ELFT> *S) const { template <class ELFT> static Symbol *addOptionalSynthetic(SymbolTable<ELFT> &Table, StringRef Name, - OutputSectionBase<ELFT> &Sec, + OutputSectionBase<ELFT> *Sec, typename ELFT::uint Val) { if (!Table.find(Name)) return nullptr; @@ -1084,10 +1098,10 @@ template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() { if (isOutputDynamic() || !Out<ELFT>::RelaPlt) return; StringRef S = Config->Rela ? "__rela_iplt_start" : "__rel_iplt_start"; - addOptionalSynthetic(Symtab, S, *Out<ELFT>::RelaPlt, 0); + addOptionalSynthetic(Symtab, S, Out<ELFT>::RelaPlt, 0); S = Config->Rela ? "__rela_iplt_end" : "__rel_iplt_end"; - addOptionalSynthetic(Symtab, S, *Out<ELFT>::RelaPlt, + addOptionalSynthetic(Symtab, S, Out<ELFT>::RelaPlt, DefinedSynthetic<ELFT>::SectionEnd); } @@ -1189,18 +1203,18 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() { // so that it points to an absolute address which is relative to GOT. // See "Global Data Symbols" in Chapter 6 in the following document: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - Symtab.addSynthetic("_gp", *Out<ELFT>::Got, MipsGPOffset); + Symtab.addSynthetic("_gp", Out<ELFT>::Got, MipsGPOffset); // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between // start of function and 'gp' pointer into GOT. ElfSym<ELFT>::MipsGpDisp = - addOptionalSynthetic(Symtab, "_gp_disp", *Out<ELFT>::Got, MipsGPOffset) + addOptionalSynthetic(Symtab, "_gp_disp", Out<ELFT>::Got, MipsGPOffset) ->body(); // The __gnu_local_gp is a magic symbol equal to the current value of 'gp' // pointer. This symbol is used in the code generated by .cpload pseudo-op // in case of using -mno-shared option. // https://sourceware.org/ml/binutils/2004-12/msg00094.html - addOptionalSynthetic(Symtab, "__gnu_local_gp", *Out<ELFT>::Got, + addOptionalSynthetic(Symtab, "__gnu_local_gp", Out<ELFT>::Got, MipsGPOffset); } @@ -1327,7 +1341,7 @@ template <class ELFT> void Writer<ELFT>::createSections() { // Even the author of gold doesn't remember why gold behaves that way. // https://sourceware.org/ml/binutils/2002-03/msg00360.html if (isOutputDynamic()) - Symtab.addSynthetic("_DYNAMIC", *Out<ELFT>::Dynamic, 0); + Symtab.addSynthetic("_DYNAMIC", Out<ELFT>::Dynamic, 0); // Define __rel[a]_iplt_{start,end} symbols if needed. addRelIpltSymbols(); @@ -1487,11 +1501,13 @@ template <class ELFT> void Writer<ELFT>::addStartEndSymbols() { auto Define = [&](StringRef Start, StringRef End, OutputSectionBase<ELFT> *OS) { if (OS) { - this->Symtab.addSynthetic(Start, *OS, 0); - this->Symtab.addSynthetic(End, *OS, DefinedSynthetic<ELFT>::SectionEnd); + this->Symtab.addSynthetic(Start, OS, 0); + this->Symtab.addSynthetic(End, OS, DefinedSynthetic<ELFT>::SectionEnd); } else { - this->Symtab.addIgnored(Start); - this->Symtab.addIgnored(End); + addOptionalSynthetic(this->Symtab, Start, + (OutputSectionBase<ELFT> *)nullptr, 0); + addOptionalSynthetic(this->Symtab, End, + (OutputSectionBase<ELFT> *)nullptr, 0); } }; @@ -1518,10 +1534,10 @@ void Writer<ELFT>::addStartStopSymbols(OutputSectionBase<ELFT> *Sec) { StringRef Stop = Saver.save("__stop_" + S); if (SymbolBody *B = Symtab.find(Start)) if (B->isUndefined()) - Symtab.addSynthetic(Start, *Sec, 0); + Symtab.addSynthetic(Start, Sec, 0); if (SymbolBody *B = Symtab.find(Stop)) if (B->isUndefined()) - Symtab.addSynthetic(Stop, *Sec, DefinedSynthetic<ELFT>::SectionEnd); + Symtab.addSynthetic(Stop, Sec, DefinedSynthetic<ELFT>::SectionEnd); } template <class ELFT> static bool needsPtLoad(OutputSectionBase<ELFT> *Sec) { diff --git a/lld/test/ELF/relocation-relative-absolute.s b/lld/test/ELF/relocation-relative-absolute.s new file mode 100644 index 00000000000..5253191331c --- /dev/null +++ b/lld/test/ELF/relocation-relative-absolute.s @@ -0,0 +1,12 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: not ld.lld %t.o -o %t -pie 2>&1 | FileCheck %s + +.globl _start +_start: + +# CHECK: relocation R_X86_64_PLT32 cannot refer to absolute symbol answer +call answer@PLT + +.globl answer +answer = 42 diff --git a/lld/test/ELF/relocation-relative-synthetic.s b/lld/test/ELF/relocation-relative-synthetic.s new file mode 100644 index 00000000000..f4d449b844e --- /dev/null +++ b/lld/test/ELF/relocation-relative-synthetic.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 -dyn-relocations %t | FileCheck %s + +# CHECK: Dynamic Relocations { +# CHECK-NEXT: } + +.globl _start +_start: +call __init_array_start@PLT diff --git a/lld/test/ELF/relocation-relative-weak.s b/lld/test/ELF/relocation-relative-weak.s new file mode 100644 index 00000000000..c525012acf6 --- /dev/null +++ b/lld/test/ELF/relocation-relative-weak.s @@ -0,0 +1,14 @@ +# 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 -dyn-relocations %t | FileCheck %s + +# CHECK: Dynamic Relocations { +# CHECK-NEXT: } + +.globl _start +_start: + +.globl w +.weak w +call w@PLT |

