Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/llvm/llvm-project.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/bolt
diff options
context:
space:
mode:
authorVladislav Khmelevsky <Vladislav.Khmelevskyi@huawei.com>2022-02-16 18:13:44 +0300
committerVladislav Khmelevsky <och95@yandex.ru>2022-02-16 18:40:54 +0300
commit729d29e167a553ee1190c310b6a510db8d8731ac (patch)
tree4f9c941e19985927d7c238fe800b4095a6031a26 /bolt
parentc9032f1a69ed2a5368a5ef783ff4a5c641e86565 (diff)
[BOLT] Update dynamic relocations from section relocations
This patch changes patchELFAllocatableRelaSections from going through old relocations sections and update the relocation offsets to emitting the relocations stored in binary sections. This is needed in case we would like to remove and add dynamic relocations during BOLT work and it is used by golang support pass. Note: Currently we emit relocations in the old sections, so the total number of them should be equal or less of old number. Testing: No special tests are neeeded, since this patch does not fix anything or add new functionality (it only prepares to add). Every PIC-compiled test binary will use this code and thus become a test. But just in case the aarch64 dynamic relocations tests were added. Vladislav Khmelevsky, Advanced Software Technology Lab, Huawei Reviewed By: maksfb Differential Revision: https://reviews.llvm.org/D117612
Diffstat (limited to 'bolt')
-rw-r--r--bolt/include/bolt/Core/BinarySection.h10
-rw-r--r--bolt/include/bolt/Core/Relocation.h7
-rw-r--r--bolt/include/bolt/Rewrite/RewriteInstance.h23
-rw-r--r--bolt/lib/Core/Relocation.cpp18
-rw-r--r--bolt/lib/Rewrite/RewriteInstance.cpp207
-rw-r--r--bolt/test/runtime/AArch64/Inputs/runtime_relocs.c13
-rw-r--r--bolt/test/runtime/AArch64/Inputs/tls_ld.yaml155
-rw-r--r--bolt/test/runtime/AArch64/Inputs/tls_trad.yaml162
-rw-r--r--bolt/test/runtime/AArch64/runtime_relocs.c64
9 files changed, 619 insertions, 40 deletions
diff --git a/bolt/include/bolt/Core/BinarySection.h b/bolt/include/bolt/Core/BinarySection.h
index bef74cc619e6..c91d3d7e6c9d 100644
--- a/bolt/include/bolt/Core/BinarySection.h
+++ b/bolt/include/bolt/Core/BinarySection.h
@@ -296,6 +296,16 @@ public:
return make_range(Relocations.begin(), Relocations.end());
}
+ /// Iterate over all dynamic relocations for this section.
+ iterator_range<RelocationSetType::iterator> dynamicRelocations() {
+ return make_range(DynamicRelocations.begin(), DynamicRelocations.end());
+ }
+
+ /// Iterate over all dynamic relocations for this section.
+ iterator_range<RelocationSetType::const_iterator> 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
index 9e13234494ff..a6773c031b29 100644
--- a/bolt/include/bolt/Core/Relocation.h
+++ b/bolt/include/bolt/Core/Relocation.h
@@ -89,6 +89,9 @@ struct Relocation {
/// 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 @@ struct Relocation {
/// 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
index d4b1b6e5f603..e0cb8b1fd631 100644
--- a/bolt/include/bolt/Rewrite/RewriteInstance.h
+++ b/bolt/include/bolt/Rewrite/RewriteInstance.h
@@ -22,6 +22,7 @@
#include "llvm/Support/Error.h"
#include <map>
#include <set>
+#include <unordered_map>
namespace llvm {
@@ -124,7 +125,7 @@ private:
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 @@ private:
/// \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 @@ private:
const std::vector<uint32_t> &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 @@ private:
/// Location and size of dynamic relocations.
Optional<uint64_t> DynamicRelocationsAddress;
uint64_t DynamicRelocationsSize{0};
+ uint64_t DynamicRelativeRelocationsCount{0};
/// PLT relocations are special kind of dynamic relocations stored separately.
Optional<uint64_t> PLTRelocationsAddress;
uint64_t PLTRelocationsSize{0};
+ /// True if relocation of specified type came from .rela.plt
+ DenseMap<uint64_t, bool> 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<const MCSymbol *, uint32_t> SymbolIndex;
+
/// Store all non-zero symbols in this map for a quick address lookup.
std::map<uint64_t, llvm::object::SymbolRef> FileSymRefs;
diff --git a/bolt/lib/Core/Relocation.cpp b/bolt/lib/Core/Relocation.cpp
index 1cc45ce393c1..2488d6b6f959 100644
--- a/bolt/lib/Core/Relocation.cpp
+++ b/bolt/lib/Core/Relocation.cpp
@@ -533,11 +533,7 @@ bool Relocation::isGOT(uint64_t Type) {
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 @@ bool Relocation::isTLS(uint64_t Type) {
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 @@ uint64_t Relocation::getPC64() {
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
index eafe0faf0ed6..b07f849b6fe9 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -1683,6 +1683,40 @@ int64_t getRelocationAddend(const ELFObjectFileBase *Obj,
auto *ELF64BE = cast<ELF64BEObjectFile>(Obj);
return getRelocationAddend(ELF64BE, Rel);
}
+
+template <typename ELFT>
+uint32_t getRelocationSymbol(const ELFObjectFile<ELFT> *Obj,
+ const RelocationRef &RelRef) {
+ using ELFShdrTy = typename ELFT::Shdr;
+ uint32_t Symbol = 0;
+ const ELFFile<ELFT> &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<ELF32LEObjectFile>(Obj))
+ return getRelocationSymbol(ELF32LE, Rel);
+ if (auto *ELF64LE = dyn_cast<ELF64LEObjectFile>(Obj))
+ return getRelocationSymbol(ELF64LE, Rel);
+ if (auto *ELF32BE = dyn_cast<ELF32BEObjectFile>(Obj))
+ return getRelocationSymbol(ELF32BE, Rel);
+ auto *ELF64BE = cast<ELF64BEObjectFile>(Obj);
+ return getRelocationSymbol(ELF64BE, Rel);
+}
} // anonymous namespace
bool RewriteInstance::analyzeRelocation(
@@ -1812,7 +1846,8 @@ void RewriteInstance::processDynamicRelocations() {
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 @@ void RewriteInstance::processDynamicRelocations() {
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::processLKSMPLocks() {
}
}
-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 @@ void RewriteInstance::readDynamicRelocations(const SectionRef &Section) {
});
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 @@ void RewriteInstance::readDynamicRelocations(const SectionRef &Section) {
<< " : + 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 @@ void
RewriteInstance::patchELFAllocatableRelaSections(ELFObjectFile<ELFT> *File) {
using Elf_Rela = typename ELFT::Rela;
raw_fd_ostream &OS = Out->os();
+ const ELFFile<ELFT> &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<const char *>(&NewRelA), sizeof(NewRelA),
- reinterpret_cast<const char *>(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<BinarySection &> 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<const char *>(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<ELFT>::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 <typename ELFT>
@@ -4737,7 +4860,8 @@ void RewriteInstance::patchELFGOT(ELFObjectFile<ELFT> *File) {
}
}
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 @@ void RewriteInstance::patchELFDynamic(ELFObjectFile<ELFT> *File) {
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 @@ void RewriteInstance::readELFDynamic(ELFObjectFile<ELFT> *File) {
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 @@ uint64_t RewriteInstance::getNewFunctionAddress(uint64_t OldAddress) {
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<ToolOutputFile>(opts::OutputFilename, EC,
@@ -5090,14 +5235,14 @@ void RewriteInstance::rewriteFile() {
// 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
index 000000000000..f60bd2729738
--- /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
index 000000000000..063b81680f87
--- /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
index 000000000000..b4e3ab71e15e
--- /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
index 000000000000..28a57919c319
--- /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);
+}