diff --git a/bolt/include/bolt/Core/BinarySection.h b/bolt/include/bolt/Core/BinarySection.h --- a/bolt/include/bolt/Core/BinarySection.h +++ b/bolt/include/bolt/Core/BinarySection.h @@ -296,6 +296,16 @@ return make_range(Relocations.begin(), Relocations.end()); } + /// Iterate over all dynamic relocations for this section. + iterator_range dynamicRelocations() { + return make_range(DynamicRelocations.begin(), DynamicRelocations.end()); + } + + /// Iterate over all dynamic relocations for this section. + iterator_range dynamicRelocations() const { + return make_range(DynamicRelocations.begin(), DynamicRelocations.end()); + } + /// Does this section have any non-pending relocations? bool hasRelocations() const { return !Relocations.empty(); } diff --git a/bolt/include/bolt/Core/Relocation.h b/bolt/include/bolt/Core/Relocation.h --- a/bolt/include/bolt/Core/Relocation.h +++ b/bolt/include/bolt/Core/Relocation.h @@ -89,6 +89,9 @@ /// Return true if relocation type is for thread local storage. static bool isTLS(uint64_t Type); + /// Return code for a NONE relocation + static uint64_t getNone(); + /// Return code for a PC-relative 4-byte relocation static uint64_t getPC32(); @@ -98,6 +101,10 @@ /// Return true if this relocation is PC-relative. Return false otherwise. bool isPCRelative() const { return isPCRelative(Type); } + /// Return true if this relocation is R_*_RELATIVE type. Return false + /// otherwise. + bool isRelative() const { return isRelative(Type); } + /// Emit relocation at a current \p Streamer' position. The caller is /// responsible for setting the position correctly. size_t emit(MCStreamer *Streamer) const; diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h --- a/bolt/include/bolt/Rewrite/RewriteInstance.h +++ b/bolt/include/bolt/Rewrite/RewriteInstance.h @@ -22,6 +22,7 @@ #include "llvm/Support/Error.h" #include #include +#include namespace llvm { @@ -124,7 +125,7 @@ void processLKSMPLocks(); /// Read relocations from a given section. - void readDynamicRelocations(const object::SectionRef &Section); + void readDynamicRelocations(const object::SectionRef &Section, bool IsJmpRel); /// Read relocations from a given section. void readRelocations(const object::SectionRef &Section); @@ -201,6 +202,10 @@ /// \p OldAddress address in the original binary. uint64_t getNewFunctionAddress(uint64_t OldAddress); + /// Return address of a function or moved data in the new binary + /// corresponding to \p OldAddress address in the original binary. + uint64_t getNewFunctionOrDataAddress(uint64_t OldAddress); + /// Return value for the symbol \p Name in the output. uint64_t getNewValueForSymbol(const StringRef Name); @@ -299,6 +304,14 @@ const std::vector &NewSectionIndex, WriteFuncTy Write, StrTabFuncTy AddToStrTab); + /// Get output index in dynamic symbol table. + uint32_t getOutputDynamicSymbolIndex(const MCSymbol *Symbol) { + auto It = SymbolIndex.find(Symbol); + if (It != SymbolIndex.end()) + return It->second; + return 0; + } + /// Add a notes section containing the BOLT revision and command line options. void addBoltInfoSection(); @@ -426,11 +439,19 @@ /// Location and size of dynamic relocations. Optional DynamicRelocationsAddress; uint64_t DynamicRelocationsSize{0}; + uint64_t DynamicRelativeRelocationsCount{0}; /// PLT relocations are special kind of dynamic relocations stored separately. Optional PLTRelocationsAddress; uint64_t PLTRelocationsSize{0}; + /// True if relocation of specified type came from .rela.plt + DenseMap IsJmpRelocation; + + /// Index of specified symbol in the dynamic symbol table. NOTE Currently it + /// is filled and used only with the relocations-related symbols. + std::unordered_map SymbolIndex; + /// Store all non-zero symbols in this map for a quick address lookup. std::map FileSymRefs; diff --git a/bolt/lib/Core/Relocation.cpp b/bolt/lib/Core/Relocation.cpp --- a/bolt/lib/Core/Relocation.cpp +++ b/bolt/lib/Core/Relocation.cpp @@ -533,11 +533,7 @@ return isGOTX86(Type); } -bool Relocation::isNone(uint64_t Type) { - if (Arch == Triple::aarch64) - return Type == ELF::R_AARCH64_NONE; - return Type == ELF::R_X86_64_NONE; -} +bool Relocation::isNone(uint64_t Type) { return Type == getNone(); } bool Relocation::isRelative(uint64_t Type) { if (Arch == Triple::aarch64) @@ -557,10 +553,10 @@ return isTLSX86(Type); } -bool Relocation::isPCRelative(uint64_t Type) { +uint64_t Relocation::getNone() { if (Arch == Triple::aarch64) - return isPCRelativeAArch64(Type); - return isPCRelativeX86(Type); + return ELF::R_AARCH64_NONE; + return ELF::R_X86_64_NONE; } uint64_t Relocation::getPC32() { @@ -575,6 +571,12 @@ return ELF::R_X86_64_PC64; } +bool Relocation::isPCRelative(uint64_t Type) { + if (Arch == Triple::aarch64) + return isPCRelativeAArch64(Type); + return isPCRelativeX86(Type); +} + size_t Relocation::emit(MCStreamer *Streamer) const { const size_t Size = getSizeForType(Type); MCContext &Ctx = Streamer->getContext(); diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -1683,6 +1683,40 @@ auto *ELF64BE = cast(Obj); return getRelocationAddend(ELF64BE, Rel); } + +template +uint32_t getRelocationSymbol(const ELFObjectFile *Obj, + const RelocationRef &RelRef) { + using ELFShdrTy = typename ELFT::Shdr; + uint32_t Symbol = 0; + const ELFFile &EF = Obj->getELFFile(); + DataRefImpl Rel = RelRef.getRawDataRefImpl(); + const ELFShdrTy *RelocationSection = cantFail(EF.getSection(Rel.d.a)); + switch (RelocationSection->sh_type) { + default: + llvm_unreachable("unexpected relocation section type"); + case ELF::SHT_REL: + Symbol = Obj->getRel(Rel)->getSymbol(EF.isMips64EL()); + break; + case ELF::SHT_RELA: + Symbol = Obj->getRela(Rel)->getSymbol(EF.isMips64EL()); + break; + } + + return Symbol; +} + +uint32_t getRelocationSymbol(const ELFObjectFileBase *Obj, + const RelocationRef &Rel) { + if (auto *ELF32LE = dyn_cast(Obj)) + return getRelocationSymbol(ELF32LE, Rel); + if (auto *ELF64LE = dyn_cast(Obj)) + return getRelocationSymbol(ELF64LE, Rel); + if (auto *ELF32BE = dyn_cast(Obj)) + return getRelocationSymbol(ELF32BE, Rel); + auto *ELF64BE = cast(Obj); + return getRelocationSymbol(ELF64BE, Rel); +} } // anonymous namespace bool RewriteInstance::analyzeRelocation( @@ -1812,7 +1846,8 @@ if (PLTRelSectionOrErr->getSize() != PLTRelocationsSize) report_error("section size mismatch for DT_PLTRELSZ", errc::executable_format_error); - readDynamicRelocations(PLTRelSectionOrErr->getSectionRef()); + readDynamicRelocations(PLTRelSectionOrErr->getSectionRef(), + /*IsJmpRel*/ true); } // The rest of dynamic relocations - DT_RELA. @@ -1825,7 +1860,8 @@ if (DynamicRelSectionOrErr->getSize() != DynamicRelocationsSize) report_error("section size mismatch for DT_RELASZ", errc::executable_format_error); - readDynamicRelocations(DynamicRelSectionOrErr->getSectionRef()); + readDynamicRelocations(DynamicRelSectionOrErr->getSectionRef(), + /*IsJmpRel*/ false); } } @@ -2049,7 +2085,8 @@ } } -void RewriteInstance::readDynamicRelocations(const SectionRef &Section) { +void RewriteInstance::readDynamicRelocations(const SectionRef &Section, + bool IsJmpRel) { assert(BinarySection(*BC, Section).isAllocatable() && "allocatable expected"); LLVM_DEBUG({ @@ -2059,7 +2096,7 @@ }); for (const RelocationRef &Rel : Section.relocations()) { - uint64_t RType = Rel.getType(); + const uint64_t RType = Rel.getType(); if (Relocation::isNone(RType)) continue; @@ -2087,7 +2124,13 @@ << " : + 0x" << Twine::utohexstr(Addend) << '\n' ); - BC->addDynamicRelocation(Rel.getOffset(), Symbol, Rel.getType(), Addend); + if (IsJmpRel) + IsJmpRelocation[RType] = true; + + if (Symbol) + SymbolIndex[Symbol] = getRelocationSymbol(InputFile, Rel); + + BC->addDynamicRelocation(Rel.getOffset(), Symbol, RType, Addend); } } @@ -4700,28 +4743,108 @@ RewriteInstance::patchELFAllocatableRelaSections(ELFObjectFile *File) { using Elf_Rela = typename ELFT::Rela; raw_fd_ostream &OS = Out->os(); + const ELFFile &EF = File->getELFFile(); - for (BinarySection &RelaSection : BC->allocatableRelaSections()) { - for (const RelocationRef &Rel : RelaSection.getSectionRef().relocations()) { - uint64_t RType = Rel.getType(); - if (!Relocation::isRelative(RType) && !Relocation::isIRelative(RType)) - continue; - DataRefImpl DRI = Rel.getRawDataRefImpl(); - const Elf_Rela *RelA = File->getRela(DRI); - auto Address = RelA->r_addend; - uint64_t NewAddress = getNewFunctionAddress(Address); - if (!NewAddress) - continue; - LLVM_DEBUG(dbgs() << "BOLT-DEBUG: patching (I)RELATIVE " - << RelaSection.getName() << " entry 0x" - << Twine::utohexstr(Address) << " with 0x" - << Twine::utohexstr(NewAddress) << '\n'); - Elf_Rela NewRelA = *RelA; - NewRelA.r_addend = NewAddress; - OS.pwrite(reinterpret_cast(&NewRelA), sizeof(NewRelA), - reinterpret_cast(RelA) - File->getData().data()); + uint64_t RelDynOffset = 0, RelDynEndOffset = 0; + uint64_t RelPltOffset = 0, RelPltEndOffset = 0; + + auto setSectionFileOffsets = [&](uint64_t Address, uint64_t &Start, + uint64_t &End) { + ErrorOr Section = BC->getSectionForAddress(Address); + Start = Section->getInputFileOffset(); + End = Start + Section->getSize(); + }; + + if (!DynamicRelocationsAddress && !PLTRelocationsAddress) + return; + + if (DynamicRelocationsAddress) + setSectionFileOffsets(*DynamicRelocationsAddress, RelDynOffset, + RelDynEndOffset); + + if (PLTRelocationsAddress) + setSectionFileOffsets(*PLTRelocationsAddress, RelPltOffset, + RelPltEndOffset); + + DynamicRelativeRelocationsCount = 0; + + auto writeRela = [&OS](const Elf_Rela *RelA, uint64_t &Offset) { + OS.pwrite(reinterpret_cast(RelA), sizeof(*RelA), Offset); + Offset += sizeof(*RelA); + }; + + auto writeRelocations = [&](bool PatchRelative) { + for (BinarySection &Section : BC->allocatableSections()) { + for (const Relocation &Rel : Section.dynamicRelocations()) { + const bool IsRelative = Rel.isRelative(); + if (PatchRelative != IsRelative) + continue; + + if (IsRelative) + ++DynamicRelativeRelocationsCount; + + Elf_Rela NewRelA; + uint64_t SectionAddress = Section.getOutputAddress(); + SectionAddress = + SectionAddress == 0 ? Section.getAddress() : SectionAddress; + MCSymbol *Symbol = Rel.Symbol; + uint32_t SymbolIdx = 0; + uint64_t Addend = Rel.Addend; + + if (Rel.Symbol) { + SymbolIdx = getOutputDynamicSymbolIndex(Symbol); + } else { + // Usually this case is used for R_*_(I)RELATIVE relocations + const uint64_t Address = getNewFunctionOrDataAddress(Addend); + if (Address) + Addend = Address; + } + + NewRelA.setSymbolAndType(SymbolIdx, Rel.Type, EF.isMips64EL()); + NewRelA.r_offset = SectionAddress + Rel.Offset; + NewRelA.r_addend = Addend; + + const bool IsJmpRel = + !!(IsJmpRelocation.find(Rel.Type) != IsJmpRelocation.end()); + uint64_t &Offset = IsJmpRel ? RelPltOffset : RelDynOffset; + const uint64_t &EndOffset = + IsJmpRel ? RelPltEndOffset : RelDynEndOffset; + if (!Offset || !EndOffset) { + errs() << "BOLT-ERROR: Invalid offsets for dynamic relocation\n"; + exit(1); + } + + if (Offset + sizeof(NewRelA) > EndOffset) { + errs() << "BOLT-ERROR: Offset overflow for dynamic relocation\n"; + exit(1); + } + + writeRela(&NewRelA, Offset); + } } - } + }; + + // The dynamic linker expects R_*_RELATIVE relocations to be emitted first + writeRelocations(/* PatchRelative */ true); + writeRelocations(/* PatchRelative */ false); + + auto fillNone = [&](uint64_t &Offset, uint64_t EndOffset) { + if (!Offset) + return; + + typename ELFObjectFile::Elf_Rela RelA; + RelA.setSymbolAndType(0, Relocation::getNone(), EF.isMips64EL()); + RelA.r_offset = 0; + RelA.r_addend = 0; + while (Offset < EndOffset) + writeRela(&RelA, Offset); + + assert(Offset == EndOffset && "Unexpected section overflow"); + }; + + // Fill the rest of the sections with R_*_NONE relocations + fillNone(RelDynOffset, RelDynEndOffset); + fillNone(RelPltOffset, RelPltEndOffset); } template @@ -4737,7 +4860,8 @@ } } if (!GOTSection.getObject()) { - errs() << "BOLT-INFO: no .got section found\n"; + if (!BC->IsStaticExecutable) + errs() << "BOLT-INFO: no .got section found\n"; return; } @@ -4796,6 +4920,9 @@ default: ShouldPatch = false; break; + case ELF::DT_RELACOUNT: + NewDE.d_un.d_val = DynamicRelativeRelocationsCount; + break; case ELF::DT_INIT: case ELF::DT_FINI: { if (BC->HasRelocations) { @@ -4898,14 +5025,21 @@ case ELF::DT_PLTRELSZ: PLTRelocationsSize = Dyn.getVal(); break; + case ELF::DT_RELACOUNT: + DynamicRelativeRelocationsCount = Dyn.getVal(); + break; } } - if (!DynamicRelocationsAddress) + if (!DynamicRelocationsAddress || !DynamicRelocationsSize) { + DynamicRelocationsAddress.reset(); DynamicRelocationsSize = 0; + } - if (!PLTRelocationsAddress) + if (!PLTRelocationsAddress || !PLTRelocationsSize) { + PLTRelocationsAddress.reset(); PLTRelocationsSize = 0; + } } uint64_t RewriteInstance::getNewFunctionAddress(uint64_t OldAddress) { @@ -4918,6 +5052,17 @@ return Function->getOutputAddress(); } +uint64_t RewriteInstance::getNewFunctionOrDataAddress(uint64_t OldAddress) { + if (uint64_t Function = getNewFunctionAddress(OldAddress)) + return Function; + + const BinaryData *BD = BC->getBinaryDataAtAddress(OldAddress); + if (BD && BD->isMoved()) + return BD->getOutputAddress(); + + return 0; +} + void RewriteInstance::rewriteFile() { std::error_code EC; Out = std::make_unique(opts::OutputFilename, EC, @@ -5090,14 +5235,14 @@ // Copy non-allocatable sections once allocatable part is finished. rewriteNoteSections(); - // Patch dynamic section/segment. - patchELFDynamic(); - if (BC->HasRelocations) { patchELFAllocatableRelaSections(); patchELFGOT(); } + // Patch dynamic section/segment. + patchELFDynamic(); + // Update ELF book-keeping info. patchELFSectionHeaderTable(); diff --git a/bolt/test/runtime/AArch64/Inputs/runtime_relocs.c b/bolt/test/runtime/AArch64/Inputs/runtime_relocs.c new file mode 100644 --- /dev/null +++ b/bolt/test/runtime/AArch64/Inputs/runtime_relocs.c @@ -0,0 +1,13 @@ +int a = 1; +__attribute__((used)) int *b = &a; // R_*_ABS64 + +static int c; +__attribute__((used)) static int *d = &c; // R_*_RELATIVE + +__thread int t1 = 0; + +int inc(int var) { + ++a; // R_*_GLOB_DAT + ++t1; // R_*_TLSDESC + return var + 1; +} diff --git a/bolt/test/runtime/AArch64/Inputs/tls_ld.yaml b/bolt/test/runtime/AArch64/Inputs/tls_ld.yaml new file mode 100644 --- /dev/null +++ b/bolt/test/runtime/AArch64/Inputs/tls_ld.yaml @@ -0,0 +1,155 @@ +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_AARCH64 + Entry: 0x590 +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_X, PF_R, PF_W ] + FirstSec: .dynsym + LastSec: .got + Align: 0x10000 + - Type: PT_DYNAMIC + Flags: [ PF_W, PF_R ] + FirstSec: .dynamic + LastSec: .dynamic + VAddr: 0x10DF0 + Align: 0x8 + - Type: PT_TLS + Flags: [ PF_R ] + FirstSec: .tbss + LastSec: .tbss + VAddr: 0x10DE0 + Align: 0x4 + - Type: PT_GNU_EH_FRAME + Flags: [ PF_R ] + FirstSec: .eh_frame_hdr + LastSec: .eh_frame_hdr + VAddr: 0x6B8 + Align: 0x4 +Sections: + - Name: .dynsym + Type: SHT_DYNSYM + Flags: [ SHF_ALLOC ] + Address: 0x250 + Link: .dynstr + AddressAlign: 0x8 + - Name: .dynstr + Type: SHT_STRTAB + Flags: [ SHF_ALLOC ] + Address: 0x340 + AddressAlign: 0x1 + - Name: .plt + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x540 + AddressAlign: 0x10 + EntSize: 0x10 + Content: F07BBFA99000009011FE47F910E23F9120021FD61F2003D51F2003D51F2003D5900000B0110240F91002009120021FD6900000B0110640F91022009120021FD6900000B0110A40F91042009120021FD6 + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x590 + AddressAlign: 0x8 + Content: 8000009000F047F9400000B4F9FFFF17C0035FD61F2003D5800000B000800091810000B0218000913F0000EBC00000548100009021E447F9610000B4F00301AA00021FD6C0035FD6800000B000800091810000B021800091210000CB22FC7FD3410C818BFF0781EB21FC4193C00000548200009042E047F9620000B4F00302AA00021FD6C0035FD6FD7BBEA9FD030091F30B00F9930000B060824039400100358000009000DC47F9800000B4800000B0000C40F9C7FFFF97D8FFFF972000805260820039F30B40F9FD7BC2A8C0035FD6DEFFFF171F2003D5FD7BBEA9FD030091F30B00F9F303002A8000009000403F91BCFFFF971F2003D5E10300AA60060011F30B40F9220040B942040011220000B9FD7BC2A8C0035FD6 + - Name: .rela.text + Type: SHT_RELA + Flags: [ SHF_INFO_LINK ] + Link: .symtab + AddressAlign: 0x8 + Info: .text + Relocations: + - Offset: 0x5C4 + Symbol: t1 + Type: R_AARCH64_TLSDESC_LD64_LO12 + - Name: .eh_frame_hdr + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Address: 0x6B8 + AddressAlign: 0x4 + Content: 011B033B3400000005000000F0FEFFFF4C00000020FFFFFF6000000060FFFFFF74000000A8FFFFFF98000000B0FFFFFFB0000000 + - Name: .eh_frame + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Address: 0x6F0 + AddressAlign: 0x8 + Content: 1000000000000000017A520004781E011B0C1F0010000000180000009CFEFFFF3000000000000000100000002C000000B8FEFFFF40000000000000002000000040000000E4FEFFFF4800000000410E209D049E034293024EDEDDD30E00000000140000006400000008FFFFFF040000000000000000000000200000007C000000F8FEFFFF4000000000410E209D049E034293024CDEDDD30E0000000000000000 + - Name: .tbss + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ] + Address: 0x10DE0 + AddressAlign: 0x4 + Offset: 0xDE0 + Size: 0x4 + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_WRITE, SHF_ALLOC ] + Address: 0x10DF0 + Link: .dynstr + AddressAlign: 0x8 + Entries: + - Tag: DT_STRTAB + Value: 0x340 + - Tag: DT_SYMTAB + Value: 0x250 + - Tag: DT_PLTRELSZ + Value: 0x18 + - Tag: DT_PLTREL + Value: 0x7 + - Tag: DT_JMPREL + Value: 0x418 + - Tag: DT_NULL + Value: 0x0 + - Name: .got + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + Address: 0x10FB0 + AddressAlign: 0x8 + EntSize: 0x8 + Content: F00D010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + - Name: .rela.plt + Type: SHT_RELA + Flags: [ SHF_ALLOC, SHF_INFO_LINK ] + Address: 0x418 + Link: .dynsym + AddressAlign: 0x8 + Info: .got + Relocations: + - Offset: 0x10fb0 + Symbol: t1 + Type: R_AARCH64_TLSDESC + - Type: SectionHeaderTable + Sections: + - Name: .dynsym + - Name: .dynstr + - Name: .rela.plt + - Name: .plt + - Name: .text + - Name: .rela.text + - Name: .eh_frame_hdr + - Name: .eh_frame + - Name: .tbss + - Name: .dynamic + - Name: .got + - Name: .symtab + - Name: .strtab + - Name: .shstrtab +Symbols: + - Name: .text + Type: STT_SECTION + Section: .text + Value: 0x590 + - Name: t1 + Type: STT_TLS + Section: .tbss + Binding: STB_GLOBAL + Size: 0x4 +DynamicSymbols: + - Name: t1 + Type: STT_TLS + Section: .tbss + Binding: STB_GLOBAL + Size: 0x4 +... diff --git a/bolt/test/runtime/AArch64/Inputs/tls_trad.yaml b/bolt/test/runtime/AArch64/Inputs/tls_trad.yaml new file mode 100644 --- /dev/null +++ b/bolt/test/runtime/AArch64/Inputs/tls_trad.yaml @@ -0,0 +1,162 @@ +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_AARCH64 + Entry: 0x590 +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_X, PF_R, PF_W ] + FirstSec: .dynsym + LastSec: .got + Align: 0x10000 + - Type: PT_DYNAMIC + Flags: [ PF_W, PF_R ] + FirstSec: .dynamic + LastSec: .dynamic + VAddr: 0x10DF0 + Align: 0x8 + - Type: PT_TLS + Flags: [ PF_R ] + FirstSec: .tbss + LastSec: .tbss + VAddr: 0x10DE0 + Align: 0x4 + - Type: PT_GNU_EH_FRAME + Flags: [ PF_R ] + FirstSec: .eh_frame_hdr + LastSec: .eh_frame_hdr + VAddr: 0x6B8 + Align: 0x4 +Sections: + - Name: .dynsym + Type: SHT_DYNSYM + Flags: [ SHF_ALLOC ] + Address: 0x250 + Link: .dynstr + AddressAlign: 0x8 + - Name: .dynstr + Type: SHT_STRTAB + Flags: [ SHF_ALLOC ] + Address: 0x340 + AddressAlign: 0x1 + - Name: .rela.dyn + Type: SHT_RELA + Flags: [ SHF_ALLOC ] + Address: 0x400 + Link: .dynsym + AddressAlign: 0x8 + Relocations: + - Offset: 0x10FD0 + Symbol: t1 + Type: R_AARCH64_TLS_DTPMOD64 + - Offset: 0x10FD8 + Symbol: t1 + Type: R_AARCH64_TLS_DTPREL64 + - Name: .plt + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x540 + AddressAlign: 0x10 + EntSize: 0x10 + Content: F07BBFA99000009011FE47F910E23F9120021FD61F2003D51F2003D51F2003D5900000B0110240F91002009120021FD6900000B0110640F91022009120021FD6900000B0110A40F91042009120021FD6 + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x590 + AddressAlign: 0x8 + Content: 8000009000F047F9400000B4F9FFFF17C0035FD61F2003D5800000B000800091810000B0218000913F0000EBC00000548100009021E447F9610000B4F00301AA00021FD6C0035FD6800000B000800091810000B021800091210000CB22FC7FD3410C818BFF0781EB21FC4193C00000548200009042E047F9620000B4F00302AA00021FD6C0035FD6FD7BBEA9FD030091F30B00F9930000B060824039400100358000009000DC47F9800000B4800000B0000C40F9C7FFFF97D8FFFF972000805260820039F30B40F9FD7BC2A8C0035FD6DEFFFF171F2003D5FD7BBEA9FD030091F30B00F9F303002A8000009000403F91BCFFFF971F2003D5E10300AA60060011F30B40F9220040B942040011220000B9FD7BC2A8C0035FD6 + - Name: .eh_frame_hdr + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Address: 0x6B8 + AddressAlign: 0x4 + Content: 011B033B3400000005000000F0FEFFFF4C00000020FFFFFF6000000060FFFFFF74000000A8FFFFFF98000000B0FFFFFFB0000000 + - Name: .eh_frame + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Address: 0x6F0 + AddressAlign: 0x8 + Content: 1000000000000000017A520004781E011B0C1F0010000000180000009CFEFFFF3000000000000000100000002C000000B8FEFFFF40000000000000002000000040000000E4FEFFFF4800000000410E209D049E034293024EDEDDD30E00000000140000006400000008FFFFFF040000000000000000000000200000007C000000F8FEFFFF4000000000410E209D049E034293024CDEDDD30E0000000000000000 + - Name: .tbss + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ] + Address: 0x10DE0 + AddressAlign: 0x4 + Offset: 0xDE0 + Size: 0x4 + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_WRITE, SHF_ALLOC ] + Address: 0x10DF0 + Link: .dynstr + AddressAlign: 0x8 + Entries: + - Tag: DT_STRTAB + Value: 0x340 + - Tag: DT_SYMTAB + Value: 0x250 + - Tag: DT_RELA + Value: 0x400 + - Tag: DT_RELASZ + Value: 0x30 + - Tag: DT_RELAENT + Value: 0x18 + - Tag: DT_RELACOUNT + Value: 0x3 + - Tag: DT_NULL + Value: 0x0 + - Name: .got + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + Address: 0x10FB0 + AddressAlign: 0x8 + EntSize: 0x8 + Content: F00D010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + - Name: .rela.text + Type: SHT_RELA + Flags: [ SHF_INFO_LINK ] + Link: .symtab + AddressAlign: 0x8 + Info: .text + Relocations: + - Offset: 0x678 + Symbol: t1 + Type: R_AARCH64_TLSGD_ADR_PAGE21 + - Offset: 0x67C + Symbol: t1 + Type: R_AARCH64_TLSGD_ADD_LO12_NC + - Type: SectionHeaderTable + Sections: + - Name: .dynsym + - Name: .dynstr + - Name: .rela.dyn + - Name: .plt + - Name: .text + - Name: .rela.text + - Name: .eh_frame_hdr + - Name: .eh_frame + - Name: .tbss + - Name: .dynamic + - Name: .got + - Name: .symtab + - Name: .strtab + - Name: .shstrtab +Symbols: + - Name: .text + Type: STT_SECTION + Section: .text + Value: 0x590 + - Name: t1 + Type: STT_TLS + Section: .tbss + Binding: STB_GLOBAL + Size: 0x4 +DynamicSymbols: + - Name: t1 + Type: STT_TLS + Section: .tbss + Binding: STB_GLOBAL + Size: 0x4 +... diff --git a/bolt/test/runtime/AArch64/runtime_relocs.c b/bolt/test/runtime/AArch64/runtime_relocs.c new file mode 100644 --- /dev/null +++ b/bolt/test/runtime/AArch64/runtime_relocs.c @@ -0,0 +1,64 @@ +// This test checks dynamic relocations support for aarch64. + +// RUN: %clang %cflags -pie -fPIC %S/Inputs/runtime_relocs.c \ +// RUN: -shared -fuse-ld=lld -o %t.so -Wl,-q -Wl,-soname=rel.so +// RUN: %clang %cflags -no-pie %s -fuse-ld=lld \ +// RUN: -o %t.exe -Wl,-q %t.so +// RUN: llvm-bolt %t.so -o %t.bolt.so -use-old-text=0 -lite=0 +// RUN: llvm-bolt %t.exe -o %t.bolt.exe -use-old-text=0 -lite=0 +// RUN: LD_PRELOAD=%t.bolt.so %t.bolt.exe + +// Check relocations in library: +// +// RUN: llvm-readelf -r %t.bolt.so | FileCheck %s -check-prefix=CHECKLIB +// +// CHECKLIB: 0000000600000401 R_AARCH64_GLOB_DAT {{.*}} a + 0 +// CHECKLIB: 0000000700000407 R_AARCH64_TLSDESC {{.*}} t1 + 0 +// CHECKLIB: 0000000600000101 R_AARCH64_ABS64 {{.*}} a + 0 + +// Check relocations in executable: +// +// RUN: llvm-readelf -r %t.bolt.exe | FileCheck %s -check-prefix=CHECKEXE +// +// CHECKEXE: 0000000600000406 R_AARCH64_TLS_TPREL64 {{.*}} t1 + 0 +// CHECKEXE: 0000000800000400 R_AARCH64_COPY {{.*}} a + 0 +// CHECKEXE: 0000000700000402 R_AARCH64_JUMP_SLOT {{.*}} inc + 0 + +// Check traditional TLS relocations R_AARCH64_TLS_DTPMOD64 and +// R_AARCH64_TLS_DTPREL64 emitted correctly after bolt. Since these +// relocations are obsolete and clang and lld does not support them, +// the initial binary was built with gcc and ld with -mtls-dialect=trad flag. +// +// RUN: yaml2obj %p/Inputs/tls_trad.yaml &> %t.trad.so +// RUN: llvm-bolt %t.trad.so -o %t.trad.bolt.so -use-old-text=0 -lite=0 +// RUN: llvm-readelf -r %t.trad.so | FileCheck %s -check-prefix=CHECKTRAD +// +// CHECKTRAD: 0000000100000404 R_AARCH64_TLS_DTPMOD64 {{.*}} t1 + 0 +// CHECKTRAD: 0000000100000405 R_AARCH64_TLS_DTPREL64 {{.*}} t1 + 0 + +// The ld linker emits R_AARCH64_TLSDESC to .rela.plt section, check that +// it is emitted correctly. +// +// RUN: yaml2obj %p/Inputs/tls_ld.yaml &> %t.ld.so +// RUN: llvm-bolt %t.ld.so -o %t.ld.bolt.so -use-old-text=0 -lite=0 +// RUN: llvm-readelf -r %t.ld.bolt.so | FileCheck %s -check-prefix=CHECKLD +// +// CHECKLD: 0000000100000407 R_AARCH64_TLSDESC {{.*}} t1 + 0 + +extern int a; // R_*_COPY + +extern __thread int t1; // R_*_TLS_TPREL64 + +int inc(int a); // R_*_JUMP_SLOT + +int dec(int a) { return a - 1; } + +void *resolver() { return dec; } + +int ifuncDec(int a) __attribute__((ifunc("resolver"))); // R_*_IRELATIVE + +int main() { + ++t1; + ifuncDec(a); + inc(a); +}