[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
This commit is contained in:
Vladislav Khmelevsky 2022-02-16 18:13:44 +03:00 committed by Vladislav Khmelevsky
parent c9032f1a69
commit 729d29e167
9 changed files with 619 additions and 40 deletions

View File

@ -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(); }

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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();

View File

@ -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;
}

View File

@ -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
...

View File

@ -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
...

View File

@ -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);
}