forked from OSchip/llvm-project
[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:
parent
8ab49cb4aa
commit
5f953277a9
|
@ -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!");
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
Loading…
Reference in New Issue