Skip to content
26 changes: 25 additions & 1 deletion bolt/lib/Rewrite/RewriteInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2439,6 +2439,30 @@ void RewriteInstance::readDynamicRelocations(const SectionRef &Section,
if (Symbol)
SymbolIndex[Symbol] = getRelocationSymbol(InputFile, Rel);

const uint64_t ReferencedAddress = SymbolAddress + Addend;
BinaryFunction *Func =
BC->getBinaryFunctionContainingAddress(ReferencedAddress);

if (Relocation::isRelative(RType) && SymbolAddress == 0) {
if (Func) {
if (!Func->isInConstantIsland(ReferencedAddress)) {
if (const uint64_t ReferenceOffset =
ReferencedAddress - Func->getAddress()) {
Func->addEntryPointAtOffset(ReferenceOffset);
}
} else {
BC->errs() << "BOLT-ERROR: referenced address at 0x"
<< Twine::utohexstr(ReferencedAddress)
<< " is in constant island of function " << *Func << "\n";
exit(1);
}
}
} else if (Relocation::isRelative(RType) && SymbolAddress != 0) {
BC->errs() << "BOLT-ERROR: symbol address non zero for RELATIVE "
"relocation type\n";
exit(1);
}

BC->addDynamicRelocation(Rel.getOffset(), Symbol, RType, Addend);
}
}
Expand Down Expand Up @@ -5599,7 +5623,7 @@ uint64_t RewriteInstance::getNewFunctionOrDataAddress(uint64_t OldAddress) {
for (const BinaryBasicBlock &BB : *BF)
if (BB.isEntryPoint() &&
(BF->getAddress() + BB.getOffset()) == OldAddress)
return BF->getOutputAddress() + BB.getOffset();
return BB.getOutputStartAddress();
}
BC->errs() << "BOLT-ERROR: unable to get new address corresponding to "
"input address 0x"
Expand Down
67 changes: 67 additions & 0 deletions bolt/test/AArch64/computed-goto.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// This test checks that BOLT creates entry points for addresses
// referenced by dynamic relocations.
// The test also checks that BOLT can map addresses inside functions.

// Checks for error and entry points.
# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o
# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q
# RUN: llvm-bolt %t.exe -o %t.bolt 2>&1 | FileCheck %s
# RUN: llvm-bolt %t.exe -o %t.bolt --print-cfg | FileCheck --check-prefix=CHECK-ENTRIES %s

// Checks for dynamic relocations.
# RUN: llvm-readelf -dr %t.bolt > %t.out.txt
# RUN: llvm-objdump -j .rela.dyn -d %t.bolt >> %t.out.txt
# RUN: FileCheck --check-prefix=CHECK-RELOCS %s --input-file=%t.out.txt

// Before bolt could handle mapping addresses within moved functions, it
// would bail out with an error of the form:
// BOLT-ERROR: unable to get new address corresponding to input address 0x10390 in function main. Consider adding this function to --skip-funcs=...
// These addresses arise if computed GOTO is in use.
// Check that bolt does not emit any error.
# CHECK-NOT: BOLT-ERROR

// Check that there are dynamic relocations.
# CHECK-RELOCS: Dynamic section at offset {{.*}} contains {{.*}} entries:
# CHECK-RELOCS: Relocation section '.rela.dyn' at offset {{.*}} contains {{.*}} entries

// Check that dynamic relocations were updated
# CHECK-RELOCS: [[#%x,OFF:]] [[#%x,INFO_DYN:]] R_AARCH64_RELATIVE [[#%x,ADDR:]]
# CHECK-RELOCS-NEXT: [[#OFF + 8]] {{0*}}[[#INFO_DYN]] R_AARCH64_RELATIVE [[#ADDR + 8]]
# CHECK-RELOCS: [[#ADDR]] <unknown>
# CHECK-RELOCS: [[#ADDR + 8]] <unknown>

// Check that BOLT registers extra entry points for dynamic relocations.
# CHECK-ENTRIES: Binary Function "main" after building cfg {
# CHECK-ENTRIES: IsMultiEntry: 1
# CHECK-ENTRIES: .Ltmp0 {{.*}}
# CHECK-ENTRIES-NEXT: Secondary Entry Point: {{.*}}
# CHECK-ENTRIES: .Ltmp1 {{.*}}
# CHECK-ENTRIES-NEXT: Secondary Entry Point: {{.*}}

.globl main
.p2align 2
.type main,@function
main:
.cfi_startproc
adrp x8, .L__const.main.ptrs+8
add x8, x8, :lo12:.L__const.main.ptrs+8
ldr x9, [x8], #8
br x9

.Label0: // Block address taken
ldr x9, [x8], #8
br x9

.Label1: // Block address taken
mov w0, #42
ret

.Lfunc_end0:
.size main, .Lfunc_end0-main
.cfi_endproc
.type .L__const.main.ptrs,@object
.section .data.rel.ro,"aw",@progbits
.p2align 3, 0x0
.L__const.main.ptrs:
.xword .Label0
.xword .Label1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
int main(int argc, char *argv[]) {
static const void *T1[] = { &&L1, &&L2 };
static const void *T2[] = { &&L2, &&L3 };
static const void *T1[] = {&&L1, &&L2};
static const void *T2[] = {&&L2, &&L3};

const void **T = (argc > 1) ? T1 : T2;

Expand Down
16 changes: 0 additions & 16 deletions bolt/test/X86/indirect-goto-pie.test

This file was deleted.

2 changes: 1 addition & 1 deletion bolt/test/X86/indirect-goto.test
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
## Check llvm-bolt processes binaries compiled from sources that use indirect goto.
RUN: %clang %cflags -no-pie %S/Inputs/indirect_goto.c -Wl,-q -o %t
RUN: %clang %cflags -no-pie %S/../Inputs/indirect_goto.c -Wl,-q -o %t
RUN: llvm-bolt %t -o %t.null --relocs=1 --print-cfg --print-only=main \
RUN: --strict \
RUN: 2>&1 | FileCheck %s
Expand Down
19 changes: 19 additions & 0 deletions bolt/test/indirect-goto-relocs.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// This test checks that BOLT creates entry points from sources
// that use indirect goto.

RUN: %clang %cflags -pie %S/Inputs/indirect_goto.c -o %t.exe -Wl,-q
RUN: llvm-bolt %t.exe -o %t.bolt --print-cfg | FileCheck --check-prefix=CHECK-PIE %s

RUN: %clang %cflags -no-pie %S/Inputs/indirect_goto.c -o %t.exe -Wl,-q
RUN: llvm-bolt %t.exe -o %t.bolt --print-cfg | FileCheck --check-prefix=CHECK-NO-PIE %s

// Check that BOLT registers extra entry points for dynamic relocations with PIE.
CHECK-PIE: Binary Function "main" after building cfg {
CHECK-PIE: IsMultiEntry: 1
CHECK-PIE: Secondary Entry Points : {{.*}}

// Check that BOLT does not register extra entry points for dynamic relocations
// without PIE
CHECK-NO-PIE: Binary Function "main" after building cfg {
CHECK-NO-PIE-NOT: IsMultiEntry: 1
CHECK-NO-PIE-NOT: Secondary Entry Points : {{.*}}