Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -90,7 +90,8 @@ } else if (Target->relocPointsToGot(Type)) { SymVA = Out::Got->getVA(); Type = Target->getPCRelReloc(); - } else if (isa>(Body)) { + } else if (!Target->relocNeedsCopy(Type, Body) && + isa>(Body)) { continue; } Target->relocateOne(Buf + RI.r_offset, BufEnd, Type, BaseAddr + RI.r_offset, Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -163,6 +163,7 @@ Body = Body->repl(); uint32_t Type = RI.getType(Config->Mips64EL); + bool NeedsCopy = Body && Target->relocNeedsCopy(Type, *Body); bool NeedsGot = Body && Target->relocNeedsGot(Type, *Body); bool CanBePreempted = canBePreempted(Body, NeedsGot); bool LazyReloc = Body && Target->supportsLazyRelocations() && @@ -175,7 +176,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); @@ -186,6 +188,9 @@ P->r_offset = Out::GotPlt->getEntryAddr(*Body); else P->r_offset = Out::Got->getEntryAddr(*Body); + } else if (NeedsCopy) { + P->r_offset = Out::Bss->getVA() + + dyn_cast>(Body)->OffsetInBSS; } else { P->r_offset = RI.r_offset + C.OutSec->getVA() + C.OutSecOff; } @@ -195,7 +200,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 +623,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 Out::Bss->getVA() + SS.OffsetInBSS; + return 0; + } case SymbolBody::UndefinedKind: return 0; case SymbolBody::LazyKind: @@ -986,9 +998,13 @@ case SymbolBody::DefinedCommonKind: OutSec = Out::Bss; break; + case SymbolBody::SharedKind: { + if (cast>(Body)->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 @@ -271,6 +271,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) { @@ -281,6 +282,10 @@ : Defined(Base::SharedKind, Name, Sym), File(F) {} SharedFile *File; + + // Can have offset if requires copy relocation. + uintX_t OffsetInBSS = 0; + bool NeedsCopy = false; }; // 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,7 @@ 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, 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 +58,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, 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, 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,15 @@ write32le(Buf + 12, -Index * PltEntrySize - PltZeroEntrySize - 16); } +bool X86_64TargetInfo::relocNeedsCopy(uint32_t Type, + const SymbolBody &S) const { + if (Type == R_X86_64_32S || Type == R_X86_64_32 || Type == R_X86_64_PC32 || + Type == R_X86_64_64) + if (auto *SS = dyn_cast>(&S)) + return SS->Sym.getType() == STT_OBJECT; + return false; +} + bool X86_64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { return Type == R_X86_64_GOTPCREL || relocNeedsPlt(Type, S); } @@ -258,6 +273,9 @@ } bool X86_64TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const { + if (relocNeedsCopy(Type, S)) + return false; + switch (Type) { default: return false; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -200,6 +200,13 @@ bool NeedsGot = false; bool NeedsPlt = false; if (Body) { + bool NeedsCopy = false; + if (auto *E = dyn_cast>(Body)) { + NeedsCopy = Target->relocNeedsCopy(Type, *Body); + if (NeedsCopy && E->NeedsCopy) + continue; + E->NeedsCopy = NeedsCopy; + } NeedsPlt = Target->relocNeedsPlt(Type, *Body); if (NeedsPlt) { if (Body->isInPlt()) @@ -395,6 +402,24 @@ 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; + // We don't know the exact alignment requirement for the data copied by a + // copy relocation, so align that to 16 byte boundaries that should be large + // enough unconditionally. + Off = RoundUpToAlignment(Off, 16); + C->OffsetInBSS = Off; + Off += Sym.st_size; + } + Out::Bss->setSize(Off); +} + static StringRef getOutputName(StringRef S) { if (S.startswith(".text.")) return ".text"; @@ -498,6 +523,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 +532,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 +545,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,52 @@ +// 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: Name: .bss +// CHECK-NEXT: Type: SHT_NOBITS (0x8) +// CHECK-NEXT: Flags [ (0x3) +// CHECK-NEXT: SHF_ALLOC (0x2) +// CHECK-NEXT: SHF_WRITE (0x1) +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x120A0 +// CHECK-NEXT: Offset: 0x20A0 +// CHECK-NEXT: Size: 20 +// CHECK-NEXT: Link: 0 +// CHECK-NEXT: Info: 0 +// CHECK-NEXT: AddressAlignment: 4 +// CHECK-NEXT: EntrySize: 0 + +// 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: } + +// 73888 = 0x120A0 +// 16 is alignment here +// 73892 = 0x120A0 + 16 +// CODE: Disassembly of section .text: +// CODE-NEXT: main: +// CODE-NEXT: 11000: c7 04 25 a0 20 01 00 05 00 00 00 movl $5, 73888 +// CODE-NEXT: 1100b: c7 04 25 b0 20 01 00 07 00 00 00 movl $7, 73904