Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -1328,7 +1328,7 @@ OutSec = Out::Bss; break; case SymbolBody::SharedKind: { - if (cast>(Body)->NeedsCopy) + if (cast>(Body)->needsCopy()) OutSec = Out::Bss; break; } Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -130,7 +130,8 @@ SymbolBody(Kind K, StringRef Name, bool IsWeak, uint8_t Visibility, bool IsTls, bool IsFunc) : SymbolKind(K), IsWeak(IsWeak), Visibility(Visibility), - MustBeInDynSym(false), IsTls(IsTls), IsFunc(IsFunc), Name(Name) { + MustBeInDynSym(false), NeedsCopyOrPltAddr(false), IsTls(IsTls), + IsFunc(IsFunc), Name(Name) { IsUsedInRegularObj = K != SharedKind && K != LazyKind; } @@ -148,9 +149,14 @@ // If true, the symbol is added to .dynsym symbol table. unsigned MustBeInDynSym : 1; + // True if the linker has to generate a copy relocation for this shared + // symbol or if the symbol should point to its plt entry. + unsigned NeedsCopyOrPltAddr : 1; + protected: unsigned IsTls : 1; unsigned IsFunc : 1; + StringRef Name; Symbol *Backref = nullptr; }; @@ -280,10 +286,10 @@ SharedFile *File; - // True if the linker has to generate a copy relocation for this shared - // symbol. OffsetInBss is significant only when NeedsCopy is true. - bool NeedsCopy = false; + // OffsetInBss is significant only when needsCopy() is true. uintX_t OffsetInBss = 0; + + bool needsCopy() const { return this->NeedsCopyOrPltAddr && !this->IsFunc; } }; // This class represents a symbol defined in an archive file. It is Index: ELF/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -56,9 +56,12 @@ return Out::Bss->getVA() + cast(this)->OffsetInBss; case SharedKind: { auto *SS = cast>(this); - if (SS->NeedsCopy) + if (!SS->NeedsCopyOrPltAddr) + return 0; + if (SS->IsFunc) + return getPltVA(); + else return Out::Bss->getVA() + SS->OffsetInBss; - return 0; } case UndefinedElfKind: case UndefinedKind: Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -54,8 +54,8 @@ virtual bool isSizeRel(uint32_t Type) const; virtual bool needsDynRelative(unsigned Type) const { return false; } - virtual bool needsGot(uint32_t Type, const SymbolBody &S) const; - virtual bool needsPlt(uint32_t Type, const SymbolBody &S) const; + virtual bool needsGot(uint32_t Type, SymbolBody &S) const; + virtual bool needsPlt(uint32_t Type, SymbolBody &S) const; virtual void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA, uint64_t ZA = 0, uint8_t *PairedLoc = nullptr) const = 0; Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -90,8 +90,8 @@ int32_t Index, unsigned RelOff) const override; bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override; bool needsDynRelative(unsigned Type) const override; - bool needsGot(uint32_t Type, const SymbolBody &S) const override; - bool needsPlt(uint32_t Type, const SymbolBody &S) const override; + bool needsGot(uint32_t Type, SymbolBody &S) const override; + bool needsPlt(uint32_t Type, SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA, uint64_t ZA = 0, uint8_t *PairedLoc = nullptr) const override; @@ -121,8 +121,8 @@ void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override; - bool needsGot(uint32_t Type, const SymbolBody &S) const override; - bool needsPlt(uint32_t Type, const SymbolBody &S) const override; + bool needsGot(uint32_t Type, SymbolBody &S) const override; + bool needsPlt(uint32_t Type, SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA, uint64_t ZA = 0, uint8_t *PairedLoc = nullptr) const override; @@ -157,8 +157,8 @@ PPC64TargetInfo(); void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; - bool needsGot(uint32_t Type, const SymbolBody &S) const override; - bool needsPlt(uint32_t Type, const SymbolBody &S) const override; + bool needsGot(uint32_t Type, SymbolBody &S) const override; + bool needsPlt(uint32_t Type, SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA, uint64_t ZA = 0, uint8_t *PairedLoc = nullptr) const override; @@ -176,8 +176,8 @@ unsigned getTlsGotRel(unsigned Type = -1) const override; bool isTlsDynRel(unsigned Type, const SymbolBody &S) const override; bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override; - bool needsGot(uint32_t Type, const SymbolBody &S) const override; - bool needsPlt(uint32_t Type, const SymbolBody &S) const override; + bool needsGot(uint32_t Type, SymbolBody &S) const override; + bool needsPlt(uint32_t Type, SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA, uint64_t ZA = 0, uint8_t *PairedLoc = nullptr) const override; @@ -197,8 +197,8 @@ unsigned getDynRel(unsigned Type) const override; void writeGotHeader(uint8_t *Buf) const override; bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override; - bool needsGot(uint32_t Type, const SymbolBody &S) const override; - bool needsPlt(uint32_t Type, const SymbolBody &S) const override; + bool needsGot(uint32_t Type, SymbolBody &S) const override; + bool needsPlt(uint32_t Type, SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA, uint64_t ZA = 0, uint8_t *PairedLoc = nullptr) const override; @@ -263,13 +263,9 @@ bool TargetInfo::isRelRelative(uint32_t Type) const { return true; } bool TargetInfo::isSizeRel(uint32_t Type) const { return false; } -bool TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const { - return false; -} +bool TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const { return false; } -bool TargetInfo::needsPlt(uint32_t Type, const SymbolBody &S) const { - return false; -} +bool TargetInfo::needsPlt(uint32_t Type, SymbolBody &S) const { return false; } unsigned TargetInfo::relaxTls(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA, @@ -376,7 +372,7 @@ return false; } -bool X86TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const { +bool X86TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const { if (S.isTls() && Type == R_386_TLS_GD) return Target->canRelaxTls(Type, &S) && canBePreempted(&S, true); if (Type == R_386_TLS_GOTIE || Type == R_386_TLS_IE) @@ -384,7 +380,7 @@ return Type == R_386_GOT32 || needsPlt(Type, S); } -bool X86TargetInfo::needsPlt(uint32_t Type, const SymbolBody &S) const { +bool X86TargetInfo::needsPlt(uint32_t Type, SymbolBody &S) const { return isGnuIFunc(S) || (Type == R_386_PLT32 && canBePreempted(&S, true)) || (Type == R_386_PC32 && S.isShared()); @@ -646,7 +642,7 @@ return false; } -bool X86_64TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const { +bool X86_64TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const { if (Type == R_X86_64_TLSGD) return Target->canRelaxTls(Type, &S) && canBePreempted(&S, true); if (Type == R_X86_64_GOTTPOFF) @@ -658,7 +654,7 @@ return Type == R_X86_64_GOTTPOFF || Type == R_X86_64_TLSGD; } -bool X86_64TargetInfo::needsPlt(uint32_t Type, const SymbolBody &S) const { +bool X86_64TargetInfo::needsPlt(uint32_t Type, SymbolBody &S) const { if (needsCopyRel(Type, S)) return false; if (isGnuIFunc(S)) @@ -684,17 +680,19 @@ // For the static linking part, we just return true and everything else // will use the the PLT entry as the address. // - // The remaining (unimplemented) problem is making sure pointer equality - // still works. We need the help of the dynamic linker for that. We - // let it know that we have a direct reference to a so symbol by creating - // an undefined symbol with a non zero st_value. Seeing that, the - // dynamic linker resolves the symbol to the value of the symbol we created. - // This is true even for got entries, so pointer equality is maintained. - // To avoid an infinite loop, the only entry that points to the - // real function is a dedicated got entry used by the plt. That is - // identified by special relocation types (R_X86_64_JUMP_SLOT, + // The remaining problem is making sure pointer equality still works. We + // need the help of the dynamic linker for that. We let it know that we have + // a direct reference to a so symbol by creating an undefined symbol with a + // non zero st_value. Seeing that, the dynamic linker resolves the symbol to + // the value of the symbol we created. This is true even for got entries, so + // pointer equality is maintained. To avoid an infinite loop, the only entry + // that points to the real function is a dedicated got entry used by the + // plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT, // R_386_JMP_SLOT, etc). - return S.isShared(); + if (!S.isShared()) + return false; + S.NeedsCopyOrPltAddr = true; + return true; case R_X86_64_PLT32: return canBePreempted(&S, true); } @@ -989,7 +987,7 @@ write32be(Buf + 28, 0x4e800420); // bctr } -bool PPC64TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const { +bool PPC64TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const { if (needsPlt(Type, S)) return true; @@ -1005,7 +1003,7 @@ } } -bool PPC64TargetInfo::needsPlt(uint32_t Type, const SymbolBody &S) const { +bool PPC64TargetInfo::needsPlt(uint32_t Type, SymbolBody &S) const { // These are function calls that need to be redirected through a PLT stub. return Type == R_PPC64_REL24 && canBePreempted(&S, false); } @@ -1240,7 +1238,7 @@ } } -bool AArch64TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const { +bool AArch64TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const { switch (Type) { case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: @@ -1252,7 +1250,7 @@ } } -bool AArch64TargetInfo::needsPlt(uint32_t Type, const SymbolBody &S) const { +bool AArch64TargetInfo::needsPlt(uint32_t Type, SymbolBody &S) const { if (isGnuIFunc(S)) return true; switch (Type) { @@ -1439,12 +1437,12 @@ } template -bool MipsTargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const { +bool MipsTargetInfo::needsGot(uint32_t Type, SymbolBody &S) const { return Type == R_MIPS_GOT16 || Type == R_MIPS_CALL16; } template -bool MipsTargetInfo::needsPlt(uint32_t Type, const SymbolBody &S) const { +bool MipsTargetInfo::needsPlt(uint32_t Type, SymbolBody &S) const { return false; } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -302,10 +302,10 @@ // If a symbol in a DSO is referenced directly instead of through GOT, // we need to create a copy relocation for the symbol. if (auto *B = dyn_cast_or_null>(Body)) { - if (B->NeedsCopy) + if (B->needsCopy()) continue; if (Target->needsCopyRel(Type, *B)) { - B->NeedsCopy = true; + B->NeedsCopyOrPltAddr = true; Out::RelaDyn->addReloc( {Target->CopyRel, DynamicReloc::Off_Bss, B}); continue; @@ -968,7 +968,7 @@ if (auto *C = dyn_cast(Body)) CommonSymbols.push_back(C); if (auto *SC = dyn_cast>(Body)) - if (SC->NeedsCopy) + if (SC->needsCopy()) CopyRelSymbols.push_back(SC); if (!includeInSymtab(*Body)) Index: test/ELF/Inputs/undef-with-plt-addr.s =================================================================== --- /dev/null +++ test/ELF/Inputs/undef-with-plt-addr.s @@ -0,0 +1,4 @@ + .globl set_data + .type set_data,@function +set_data: + retq Index: test/ELF/symbol-override.s =================================================================== --- test/ELF/symbol-override.s +++ test/ELF/symbol-override.s @@ -43,4 +43,4 @@ .text .globl _start _start: -callq do +callq do@plt Index: test/ELF/undef-with-plt-addr.s =================================================================== --- /dev/null +++ test/ELF/undef-with-plt-addr.s @@ -0,0 +1,23 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/undef-with-plt-addr.s -o %t2.o +// RUN: ld.lld %t2.o -o %t2.so -shared +// RUN: ld.lld %t.o %t2.so -o %t3 +// RUN: llvm-readobj -t -s %t3 | FileCheck %s + +.globl _start +_start: +movabsq $set_data, %rax + +// Test that set_data has an address in the .plt + +// CHECK: Name: .plt +// CHECK-NEXT: Type: SHT_PROGBITS +// CHECK-NEXT: Flags [ +// CHECK-NEXT: SHF_ALLOC +// CHECK-NEXT: SHF_EXECINSTR +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x11010 + +// CHECK: Name: set_data +// CHECK-NEXT: Value: 0x11020