[PR] Handle relocations in constant islands

Summary:
In non-PIC binaries compiler could save absolute addresses in constant
isalnd which we should handle properly. This patch adds relocations
handling in constant islands.

Vladislav Khmelevsky,
Advanced Software Technology Lab, Huawei

(cherry picked from FBD31416848)
This commit is contained in:
Vladislav Khmelevsky 2021-10-04 19:05:18 +03:00 committed by Maksim Panchenko
parent 8ab49cb4aa
commit 5f953277a9
4 changed files with 77 additions and 15 deletions

View File

@ -549,17 +549,45 @@ void BinaryEmitter::emitConstantIslands(BinaryFunction &BF, bool EmitColdPart,
if (FunctionOffset == EndOffset) if (FunctionOffset == EndOffset)
continue; // Size is zero, nothing to emit continue; // Size is zero, nothing to emit
auto emitCI = [&](uint64_t &FunctionOffset, uint64_t EndOffset) {
if (FunctionOffset >= EndOffset)
return;
for (auto It = Islands.Relocations.lower_bound(FunctionOffset);
It != Islands.Relocations.end(); ++It) {
if (It->first >= EndOffset)
break;
const Relocation &Relocation = It->second;
if (FunctionOffset < Relocation.Offset) {
Streamer.emitBytes(
FunctionContents.slice(FunctionOffset, Relocation.Offset));
FunctionOffset = Relocation.Offset;
}
LLVM_DEBUG(
dbgs() << "BOLT-DEBUG: emitting constant island relocation"
<< " for " << BF << " at offset 0x"
<< Twine::utohexstr(Relocation.Offset) << " with size "
<< Relocation::getSizeForType(Relocation.Type) << '\n');
FunctionOffset += Relocation.emit(&Streamer);
}
assert(FunctionOffset <= EndOffset && "overflow error");
if (FunctionOffset < EndOffset) {
Streamer.emitBytes(FunctionContents.slice(FunctionOffset, EndOffset));
FunctionOffset = EndOffset;
}
};
// Emit labels, relocs and data // Emit labels, relocs and data
while (IS != Islands.Offsets.end() && IS->first < EndOffset) { while (IS != Islands.Offsets.end() && IS->first < EndOffset) {
auto NextLabelOffset = auto NextLabelOffset =
IS == Islands.Offsets.end() ? EndOffset : IS->first; IS == Islands.Offsets.end() ? EndOffset : IS->first;
auto NextRelOffset = EndOffset; auto NextStop = std::min(NextLabelOffset, EndOffset);
auto NextStop = std::min(NextLabelOffset, NextRelOffset);
assert(NextStop <= EndOffset && "internal overflow error"); assert(NextStop <= EndOffset && "internal overflow error");
if (FunctionOffset < NextStop) { emitCI(FunctionOffset, NextStop);
Streamer.emitBytes(FunctionContents.slice(FunctionOffset, NextStop));
FunctionOffset = NextStop;
}
if (IS != Islands.Offsets.end() && FunctionOffset == IS->first) { if (IS != Islands.Offsets.end() && FunctionOffset == IS->first) {
// This is a slightly complex code to decide which label to emit. We // This is a slightly complex code to decide which label to emit. We
// have 4 cases to handle: regular symbol, cold symbol, regular or cold // have 4 cases to handle: regular symbol, cold symbol, regular or cold
@ -598,9 +626,7 @@ void BinaryEmitter::emitConstantIslands(BinaryFunction &BF, bool EmitColdPart,
} }
} }
assert(FunctionOffset <= EndOffset && "overflow error"); assert(FunctionOffset <= EndOffset && "overflow error");
if (FunctionOffset < EndOffset) { emitCI(FunctionOffset, EndOffset);
Streamer.emitBytes(FunctionContents.slice(FunctionOffset, EndOffset));
}
} }
assert(IS == Islands.Offsets.end() && "some symbols were not emitted!"); assert(IS == Islands.Offsets.end() && "some symbols were not emitted!");

View File

@ -148,6 +148,9 @@ public:
std::set<uint64_t> DataOffsets; std::set<uint64_t> DataOffsets;
std::set<uint64_t> CodeOffsets; std::set<uint64_t> CodeOffsets;
/// List of relocations associated with data in the constant island
std::map<uint64_t, Relocation> Relocations;
/// Offsets in function that are data values in a constant island identified /// Offsets in function that are data values in a constant island identified
/// after disassembling /// after disassembling
std::map<uint64_t, MCSymbol *> Offsets; std::map<uint64_t, MCSymbol *> Offsets;
@ -1287,7 +1290,9 @@ public:
} }
void addRelocationAArch64(uint64_t Offset, MCSymbol *Symbol, uint64_t RelType, void addRelocationAArch64(uint64_t Offset, MCSymbol *Symbol, uint64_t RelType,
uint64_t Addend, uint64_t Value) { uint64_t Addend, uint64_t Value, bool IsCI) {
std::map<uint64_t, Relocation> &Rels =
(IsCI) ? Islands.Relocations : Relocations;
switch (RelType) { switch (RelType) {
case ELF::R_AARCH64_ABS64: case ELF::R_AARCH64_ABS64:
case ELF::R_AARCH64_ADD_ABS_LO12_NC: case ELF::R_AARCH64_ADD_ABS_LO12_NC:
@ -1314,7 +1319,7 @@ public:
case ELF::R_AARCH64_MOVW_UABS_G2: case ELF::R_AARCH64_MOVW_UABS_G2:
case ELF::R_AARCH64_MOVW_UABS_G2_NC: case ELF::R_AARCH64_MOVW_UABS_G2_NC:
case ELF::R_AARCH64_MOVW_UABS_G3: case ELF::R_AARCH64_MOVW_UABS_G3:
Relocations[Offset] = Relocation{Offset, Symbol, RelType, Addend, Value}; Rels[Offset] = Relocation{Offset, Symbol, RelType, Addend, Value};
return; return;
case ELF::R_AARCH64_CALL26: case ELF::R_AARCH64_CALL26:
case ELF::R_AARCH64_JUMP26: case ELF::R_AARCH64_JUMP26:
@ -1361,8 +1366,10 @@ public:
assert(Address >= getAddress() && Address < getAddress() + getMaxSize() && assert(Address >= getAddress() && Address < getAddress() + getMaxSize() &&
"address is outside of the function"); "address is outside of the function");
uint64_t Offset = Address - getAddress(); uint64_t Offset = Address - getAddress();
if (BC.isAArch64()) if (BC.isAArch64()) {
return addRelocationAArch64(Offset, Symbol, RelType, Addend, Value); return addRelocationAArch64(Offset, Symbol, RelType, Addend, Value,
isInConstantIsland(Address));
}
return addRelocationX86(Offset, Symbol, RelType, Addend, Value); return addRelocationX86(Offset, Symbol, RelType, Addend, Value);
} }

View File

@ -13,9 +13,9 @@
.data .data
.align 8 .align 8
.global Gvar .global Gvar
Gvar: .dword 0x0 Gvar: .xword 0x0
.global Gvar2 .global Gvar2
Gvar2: .dword 0x42 Gvar2: .xword 0x42
.text .text
.align 4 .align 4

View File

@ -0,0 +1,29 @@
# This test checks that the address stored in constant island
# is updated after llvm-bolt
# REQUIRES: system-linux
# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \
# RUN: %s -o %t.o
# RUN: %clang %cflags -no-pie %t.o -o %t.exe -Wl,-q
# RUN: llvm-bolt %t.exe -o %t.bolt -use-old-text=0 -lite=0 -trap-old-code
# RUN: %t.bolt
.text
.align 4
.global test
.type test, %function
test:
mov x0, #0
ret
.size test, .-test
.global main
.type main, %function
main:
adr x0, CI
ldr x0, [x0]
br x0
.size main, .-main
CI:
.xword test