diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 1528dc5853dc..dd8a8c61785a 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -112,7 +112,8 @@ void InputSection::relocate( } 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, diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index 502963014c10..df23350afb77 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -163,6 +163,7 @@ template void RelocationSection::writeTo(uint8_t *Buf) { 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 @@ template void RelocationSection::writeTo(uint8_t *Buf) { : 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 @@ template void RelocationSection::writeTo(uint8_t *Buf) { 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 @@ template void RelocationSection::writeTo(uint8_t *Buf) { 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; @@ -637,7 +644,12 @@ typename ELFFile::uintX_t lld::elf2::getSymVA(const SymbolBody &S) { } case SymbolBody::DefinedCommonKind: return Out::Bss->getVA() + cast>(S).OffsetInBSS; - case SymbolBody::SharedKind: + case SymbolBody::SharedKind: { + auto &SS = cast>(S); + if (SS.NeedsCopy) + return Out::Bss->getVA() + SS.OffsetInBSS; + return 0; + } case SymbolBody::UndefinedKind: return 0; case SymbolBody::LazyKind: @@ -990,9 +1002,13 @@ void SymbolTableSection::writeGlobalSymbols(uint8_t *Buf) { 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; } diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index 30f8ec6a5bdb..61ffdfab8f34 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -271,6 +271,7 @@ typename Undefined::Elf_Sym Undefined::Optional; 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 @@ public: : 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 diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index 4f2b0a16ea05..1f1b344cb2de 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -68,6 +68,7 @@ public: 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 *createTarget() { 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 @@ void X86TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, } 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 @@ void X86_64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr, 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 @@ unsigned X86_64TargetInfo::getPLTRefReloc(unsigned Type) const { } bool X86_64TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const { + if (relocNeedsCopy(Type, S)) + return false; + switch (Type) { default: return false; diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index ff5943dea3d5..7114f1d35491 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -22,6 +22,7 @@ class TargetInfo { 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 @@ public: 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 @@ protected: // 0x200000, but it looks like every OS uses 4k pages for executables. uint64_t VAStart = 0x10000; + unsigned CopyReloc; unsigned PCRelReloc; unsigned GotRefReloc; unsigned GotReloc; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index acf5cc938717..016696886d12 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -200,6 +200,11 @@ void Writer::scanRelocs( bool NeedsGot = false; bool NeedsPlt = false; if (Body) { + if (auto *E = dyn_cast>(Body)) { + if (E->NeedsCopy) + continue; + E->NeedsCopy = Target->relocNeedsCopy(Type, *Body); + } NeedsPlt = Target->relocNeedsPlt(Type, *Body); if (NeedsPlt) { if (Body->isInPlt()) @@ -395,6 +400,24 @@ static void addCommonSymbols(std::vector *> &Syms) { 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 +521,7 @@ template void Writer::createSections() { 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 +530,10 @@ template void Writer::createSections() { 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 +543,7 @@ template void Writer::createSections() { 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. diff --git a/lld/test/elf2/Inputs/relocation-copy.s b/lld/test/elf2/Inputs/relocation-copy.s new file mode 100644 index 000000000000..0cd0c4cb5ea6 --- /dev/null +++ b/lld/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 diff --git a/lld/test/elf2/relocation-copy.s b/lld/test/elf2/relocation-copy.s new file mode 100644 index 000000000000..3e8f6ca1b401 --- /dev/null +++ b/lld/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