Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -81,7 +81,12 @@ SymbolBody &Body = *File.getSymbolBody(SymIndex)->repl(); uintX_t SymVA = getSymVA(Body); - if (Target->relocNeedsPlt(Type, Body)) { + bool NeedsCopy = false; + if (ELFSymbolBody *E = dyn_cast>(&Body)) + NeedsCopy = Target->relocNeedsCopy(Type, E->Sym.getType(), Body); + if (NeedsCopy) { + Type = Target->getCopyReloc(); + } else if (Target->relocNeedsPlt(Type, Body)) { SymVA = Out::Plt->getEntryAddr(Body); Type = Target->getPLTRefReloc(Type); } else if (Target->relocNeedsGot(Type, Body)) { Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -163,7 +163,12 @@ Body = Body->repl(); uint32_t Type = RI.getType(Config->Mips64EL); - bool NeedsGot = Body && Target->relocNeedsGot(Type, *Body); + SharedSymbol *Shared = + Body ? dyn_cast>(Body) : nullptr; + + bool NeedsCopy = + Shared && Target->relocNeedsCopy(Type, Shared->Sym.getType(), *Body); + bool NeedsGot = Body && !NeedsCopy && Target->relocNeedsGot(Type, *Body); bool CanBePreempted = canBePreempted(Body, NeedsGot); bool LazyReloc = Body && Target->supportsLazyRelocations() && Target->relocNeedsPlt(Type, *Body); @@ -175,7 +180,8 @@ : Target->getGotReloc(), Config->Mips64EL); else - P->setSymbolAndType(Body->getDynamicSymbolTableIndex(), Type, + P->setSymbolAndType(Body->getDynamicSymbolTableIndex(), + NeedsCopy ? Target->getCopyReloc() : Type, Config->Mips64EL); } else { P->setSymbolAndType(0, Target->getRelativeReloc(), Config->Mips64EL); @@ -187,7 +193,10 @@ else P->r_offset = Out::Got->getEntryAddr(*Body); } else { - P->r_offset = RI.r_offset + C.OutSec->getVA() + C.OutSecOff; + if (NeedsCopy) + P->r_offset = Out::Bss->getVA() + Shared->OffsetInBSS; + else + P->r_offset = RI.r_offset + C.OutSec->getVA() + C.OutSecOff; } uintX_t OrigAddend = 0; @@ -195,7 +204,9 @@ OrigAddend = static_cast(RI).r_addend; uintX_t Addend; - if (CanBePreempted) + if (NeedsCopy) + Addend = 0; + else if (CanBePreempted) Addend = OrigAddend; else if (Body) Addend = getSymVA(cast>(*Body)) + OrigAddend; @@ -616,7 +627,12 @@ } case SymbolBody::DefinedCommonKind: return Out::Bss->getVA() + cast>(S).OffsetInBSS; - case SymbolBody::SharedKind: + case SymbolBody::SharedKind: { + const auto &SS = cast>(S); + if (!SS.NeedsCopy) + return 0; + return Out::Bss->getVA() + SS.OffsetInBSS; + } case SymbolBody::UndefinedKind: return 0; case SymbolBody::LazyKind: @@ -986,9 +1002,15 @@ case SymbolBody::DefinedCommonKind: OutSec = Out::Bss; break; + case SymbolBody::SharedKind: { + auto *Sym = cast>(Body->repl()); + if (Sym->NeedsCopy) { + OutSec = Out::Bss; + } + break; + } case SymbolBody::UndefinedKind: case SymbolBody::DefinedAbsoluteKind: - case SymbolBody::SharedKind: case SymbolBody::LazyKind: break; } Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -93,6 +93,7 @@ uint32_t GotIndex = -1; uint32_t GotPltIndex = -1; uint32_t PltIndex = -1; + bool InRelaBss = false; bool isInGot() const { return GotIndex != -1U; } bool isInGotPlt() const { return GotPltIndex != -1U; } bool isInPlt() const { return PltIndex != -1U; } @@ -271,6 +272,7 @@ template class SharedSymbol : public Defined { typedef Defined Base; typedef typename Base::Elf_Sym Elf_Sym; + typedef typename llvm::object::ELFFile::uintX_t uintX_t; public: static bool classof(const SymbolBody *S) { @@ -278,9 +280,14 @@ } SharedSymbol(SharedFile *F, StringRef Name, const Elf_Sym &Sym) - : Defined(Base::SharedKind, Name, Sym), File(F) {} + : Defined(Base::SharedKind, Name, Sym), File(F), OffsetInBSS(0), + NeedsCopy(false) {} SharedFile *File; + + // Can have offset if requires copy relocation. + uintX_t OffsetInBSS; + bool NeedsCopy; }; // This class represents a symbol defined in an archive file. It is Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -22,6 +22,7 @@ public: unsigned getPageSize() const { return PageSize; } uint64_t getVAStart() const { return VAStart; } + unsigned getCopyReloc() const { return CopyReloc; } unsigned getPCRelReloc() const { return PCRelReloc; } unsigned getGotReloc() const { return GotReloc; } unsigned getPltReloc() const { return PltReloc; } @@ -37,6 +38,8 @@ virtual void writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index) const = 0; virtual bool isRelRelative(uint32_t Type) const; + virtual bool relocNeedsCopy(uint32_t Type, unsigned char SymType, + const SymbolBody &S) const; virtual bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const = 0; virtual bool relocPointsToGot(uint32_t Type) const; virtual bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const = 0; @@ -56,6 +59,7 @@ // 0x200000, but it looks like every OS uses 4k pages for executables. uint64_t VAStart = 0x10000; + unsigned CopyReloc; unsigned PCRelReloc; unsigned GotRefReloc; unsigned GotReloc; Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -68,6 +68,7 @@ uint64_t PltEntryAddr) const override; void writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index) const override; + bool relocNeedsCopy(uint32_t Type, unsigned char SymType, const SymbolBody &S) const override; bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, @@ -144,6 +145,10 @@ TargetInfo::~TargetInfo() {} +bool TargetInfo::relocNeedsCopy(uint32_t Type, unsigned char SymType, const SymbolBody &S) const { + return false; +} + unsigned TargetInfo::getPLTRefReloc(unsigned Type) const { return PCRelReloc; } bool TargetInfo::relocPointsToGot(uint32_t Type) const { return false; } @@ -200,6 +205,7 @@ } X86_64TargetInfo::X86_64TargetInfo() { + CopyReloc = R_X86_64_COPY; PCRelReloc = R_X86_64_PC32; GotReloc = R_X86_64_GLOB_DAT; GotRefReloc = R_X86_64_PC32; @@ -242,6 +248,12 @@ write32le(Buf + 12, -Index * PltEntrySize - PltZeroEntrySize - 16); } +bool X86_64TargetInfo::relocNeedsCopy(uint32_t Type, unsigned char SymType, + const SymbolBody &S) const { + return (SymType == STT_OBJECT) && + ((Type == R_X86_64_32S && S.isShared()) || relocNeedsPlt(Type, S)); +} + bool X86_64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { return Type == R_X86_64_GOTPCREL || relocNeedsPlt(Type, S); } @@ -325,6 +337,9 @@ error("R_X86_64_32S out of range"); write32le(Loc, SA); break; + case R_X86_64_COPY: + write32le(Loc, SA - P); + break; default: error("unrecognized reloc " + Twine(Type)); } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -200,13 +200,25 @@ bool NeedsGot = false; bool NeedsPlt = false; if (Body) { - NeedsPlt = Target->relocNeedsPlt(Type, *Body); + bool NeedsCopy = false; + if (auto *E = dyn_cast>(Body)) { + NeedsCopy = Target->relocNeedsCopy(Type, E->Sym.getType(), *Body); + E->NeedsCopy = NeedsCopy; + } + if (NeedsCopy) { + if (Body->InRelaBss) + continue; + else + Body->InRelaBss = true; + } + + NeedsPlt = !NeedsCopy && Target->relocNeedsPlt(Type, *Body); if (NeedsPlt) { if (Body->isInPlt()) continue; Out::Plt->addEntry(Body); } - NeedsGot = Target->relocNeedsGot(Type, *Body); + NeedsGot = !NeedsCopy && Target->relocNeedsGot(Type, *Body); if (NeedsGot) { if (NeedsPlt && Target->supportsLazyRelocations()) { Out::GotPlt->addEntry(Body); @@ -395,6 +407,21 @@ Out::Bss->setSize(Off); } +template +static void addSharedCopySymbols(std::vector *> &Syms) { + typedef typename ELFFile::uintX_t uintX_t; + typedef typename ELFFile::Elf_Sym Elf_Sym; + + uintX_t Off = Out::Bss->getSize(); + for (SharedSymbol *C : Syms) { + const Elf_Sym &Sym = C->Sym; + Off = RoundUpToAlignment(Off, Sym.st_size); + C->OffsetInBSS = Off; + Off += Sym.st_size; + } + Out::Bss->setSize(Off); +} + static StringRef getOutputName(StringRef S) { if (S.startswith(".text.")) return ".text"; @@ -498,6 +525,7 @@ scanRelocs(*S); std::vector *> CommonSymbols; + std::vector *> SharedCopySymbols; for (auto &P : Symtab.getSymbols()) { SymbolBody *Body = P.second->Body; if (auto *U = dyn_cast>(Body)) @@ -506,6 +534,10 @@ if (auto *C = dyn_cast>(Body)) CommonSymbols.push_back(C); + if (auto *SC = dyn_cast>(Body)) + if (SC->NeedsCopy) + SharedCopySymbols.push_back(SC); + if (!includeInSymtab(*Body)) continue; if (Out::SymTab) @@ -515,6 +547,7 @@ Out::DynSymTab->addSymbol(Body); } addCommonSymbols(CommonSymbols); + addSharedCopySymbols(SharedCopySymbols); // This order is not the same as the final output order // because we sort the sections using their attributes below. Index: test/elf2/Inputs/relocation-copy.s =================================================================== --- test/elf2/Inputs/relocation-copy.s +++ test/elf2/Inputs/relocation-copy.s @@ -0,0 +1,14 @@ +.text +.type x,@object +.bss +.globl x +.align 4 +x: +.long 0 +.size x, 4 +.type y,@object +.globl y +.align 4 +y: +.long 0 +.size y, 4 Index: test/elf2/relocation-copy.s =================================================================== --- test/elf2/relocation-copy.s +++ test/elf2/relocation-copy.s @@ -0,0 +1,35 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/relocation-copy.s -o %t2.o +// RUN: ld.lld2 -shared %t2.o -o %t.so +// RUN: ld.lld2 -e main %t.o %t.so -o %t3 +// RUN: llvm-readobj --program-headers --dynamic-table -t -s -dyn-symbols -section-data -r --expand-relocs %t3 | FileCheck %s +// RUN: llvm-objdump -r -d %t3 | FileCheck -check-prefix=CODE %s + +.text +.globl main +.align 16, 0x90 +.type main,@function +main: +movl $5, x +movl $7, y + +// CHECK: Relocations [ +// CHECK-NEXT: Section ({{.*}}) .rela.dyn { +// CHECK-NEXT: Relocation { +// CHECK-NEXT: Offset: +// CHECK-NEXT: Type: R_X86_64_COPY +// CHECK-NEXT: Symbol: x +// CHECK-NEXT: Addend: 0x0 +// CHECK-NEXT: } +// CHECK-NEXT: Relocation { +// CHECK-NEXT: Offset: +// CHECK-NEXT: Type: R_X86_64_COPY +// CHECK-NEXT: Symbol: y +// CHECK-NEXT: Addend: 0x0 +// CHECK-NEXT: } + +// CODE: Disassembly of section .text: +// CODE-NEXT: main: +// CODE-NEXT: 11000: c7 04 25 9d 10 00 00 05 00 00 00 movl $5, 4253 +// CODE-NEXT: 1100b: c7 04 25 96 10 00 00 07 00 00 00 movl $7, 4246