Skip to content

Commit cf2bb1d

Browse files
author
Vasily Leonenko
committed
[BOLT] Support instrumentation hook via DT_INIT_ARRAY
This commit follows implementation of instrumentation hook via DT_FINI_ARRAY (#67348) and extends it for instrumentation initialization hooking. Initialization has has differences compared to finalization: - Executables always use ELF entry point address. Update code checks it and updates init_array entry if ELF is shared library (have no interp entry) and have no DT_INIT entry. Also this commit introduces "instrumentation-no-use-entry-point" option to avoid that avoids usage of ELF entry point and force usage of DT_INIT or DT_INIT_ARRAY, e.g. in case of libc instrumentation. - Shared library init_array entries relocations usually has R_AARCH64_ABS64 type on AArch64 binaries. We check relocation type and adjust methods for reading init_array relocations in discovery and update methods.
1 parent d4b41b9 commit cf2bb1d

File tree

4 files changed

+144
-4
lines changed

4 files changed

+144
-4
lines changed

bolt/include/bolt/Core/BinaryContext.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,15 @@ class BinaryContext {
807807
/// the execution of the binary is completed.
808808
std::optional<uint64_t> FiniFunctionAddress;
809809

810+
/// DT_INIT.
811+
std::optional<uint64_t> InitAddress;
812+
813+
/// DT_INIT_ARRAY. Only used when DT_INIT is not set.
814+
std::optional<uint64_t> InitArrayAddress;
815+
816+
/// DT_INIT_ARRAYSZ. Only used when DT_INIT is not set.
817+
std::optional<uint64_t> InitArraySize;
818+
810819
/// DT_FINI.
811820
std::optional<uint64_t> FiniAddress;
812821

bolt/include/bolt/Rewrite/RewriteInstance.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,20 @@ class RewriteInstance {
9393
/// section allocations if found.
9494
void discoverBOLTReserved();
9595

96+
/// Check whether we should use DT_INIT or DT_INIT_ARRAY for instrumentation.
97+
/// DT_INIT is preferred; DT_INIT_ARRAY is only used when no DT_INIT entry was
98+
/// found.
99+
Error discoverRtInitAddress();
100+
96101
/// Check whether we should use DT_FINI or DT_FINI_ARRAY for instrumentation.
97102
/// DT_FINI is preferred; DT_FINI_ARRAY is only used when no DT_FINI entry was
98103
/// found.
99104
Error discoverRtFiniAddress();
100105

106+
/// If DT_INIT_ARRAY is used for instrumentation, update the relocation of its
107+
/// first entry to point to the instrumentation library's init address.
108+
void updateRtInitReloc();
109+
101110
/// If DT_FINI_ARRAY is used for instrumentation, update the relocation of its
102111
/// first entry to point to the instrumentation library's fini address.
103112
void updateRtFiniReloc();

bolt/lib/Passes/Instrumentation.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ cl::opt<std::string> InstrumentationFilename(
3434
"/tmp/prof.fdata)"),
3535
cl::init("/tmp/prof.fdata"), cl::Optional, cl::cat(BoltInstrCategory));
3636

37+
cl::opt<bool> InstrumentNoUseEntryPoint(
38+
"instrumentation-no-use-entry-point",
39+
cl::desc("Do not use ELF entry point for instrumentation "
40+
"initialization (e.g. for libc) (default: false)"),
41+
cl::init(false), cl::Optional, cl::cat(BoltInstrCategory));
42+
3743
cl::opt<std::string> InstrumentationBinpath(
3844
"instrumentation-binpath",
3945
cl::desc("path to instrumented binary in case if /proc/self/map_files "

bolt/lib/Rewrite/RewriteInstance.cpp

Lines changed: 120 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ namespace opts {
8080
extern cl::list<std::string> HotTextMoveSections;
8181
extern cl::opt<bool> Hugify;
8282
extern cl::opt<bool> Instrument;
83+
extern cl::opt<bool> InstrumentNoUseEntryPoint;
8384
extern cl::opt<bool> KeepNops;
8485
extern cl::opt<bool> Lite;
8586
extern cl::list<std::string> ReorderData;
@@ -737,9 +738,12 @@ Error RewriteInstance::run() {
737738
adjustCommandLineOptions();
738739
discoverFileObjects();
739740

740-
if (opts::Instrument && !BC->IsStaticExecutable)
741+
if (opts::Instrument && !BC->IsStaticExecutable) {
742+
if (Error E = discoverRtInitAddress())
743+
return E;
741744
if (Error E = discoverRtFiniAddress())
742745
return E;
746+
}
743747

744748
preprocessProfileData();
745749

@@ -781,8 +785,10 @@ Error RewriteInstance::run() {
781785

782786
updateMetadata();
783787

784-
if (opts::Instrument && !BC->IsStaticExecutable)
788+
if (opts::Instrument && !BC->IsStaticExecutable) {
789+
updateRtInitReloc();
785790
updateRtFiniReloc();
791+
}
786792

787793
if (opts::OutputFilename == "/dev/null") {
788794
BC->outs() << "BOLT-INFO: skipping writing final binary to disk\n";
@@ -1407,6 +1413,55 @@ void RewriteInstance::discoverBOLTReserved() {
14071413
NextAvailableAddress = BC->BOLTReserved.start();
14081414
}
14091415

1416+
Error RewriteInstance::discoverRtInitAddress() {
1417+
if (BC->HasInterpHeader && !opts::InstrumentNoUseEntryPoint)
1418+
return Error::success();
1419+
1420+
// Use DT_INIT if it's available.
1421+
if (BC->InitAddress) {
1422+
BC->StartFunctionAddress = BC->InitAddress;
1423+
return Error::success();
1424+
}
1425+
1426+
if (!BC->InitArrayAddress || !BC->InitArraySize) {
1427+
return createStringError(std::errc::not_supported,
1428+
"Instrumentation of shared library needs either "
1429+
"DT_INIT or DT_INIT_ARRAY");
1430+
}
1431+
1432+
if (*BC->InitArraySize < BC->AsmInfo->getCodePointerSize()) {
1433+
return createStringError(std::errc::not_supported,
1434+
"Need at least 1 DT_FINI_ARRAY slot");
1435+
}
1436+
1437+
ErrorOr<BinarySection &> InitArraySection =
1438+
BC->getSectionForAddress(*BC->InitArrayAddress);
1439+
if (auto EC = InitArraySection.getError())
1440+
return errorCodeToError(EC);
1441+
1442+
if (const Relocation *Reloc = InitArraySection->getDynamicRelocationAt(0)) {
1443+
if (Reloc->isRelative()) {
1444+
BC->StartFunctionAddress = Reloc->Addend;
1445+
} else {
1446+
MCSymbol *Sym = Reloc->Symbol;
1447+
assert(Sym && "Failed to locate symbol for 0 entry of .init_array");
1448+
const BinaryFunction *BF = BC->getFunctionForSymbol(Sym);
1449+
assert(BF &&
1450+
"Failed to locate binary function for 0 entry of .init_array");
1451+
BC->StartFunctionAddress = BF->getAddress() + Reloc->Addend;
1452+
}
1453+
return Error::success();
1454+
}
1455+
1456+
if (const Relocation *Reloc = InitArraySection->getRelocationAt(0)) {
1457+
BC->StartFunctionAddress = Reloc->Value;
1458+
return Error::success();
1459+
}
1460+
1461+
return createStringError(std::errc::not_supported,
1462+
"No relocation for first DT_INIT_ARRAY slot");
1463+
}
1464+
14101465
Error RewriteInstance::discoverRtFiniAddress() {
14111466
// Use DT_FINI if it's available.
14121467
if (BC->FiniAddress) {
@@ -1444,6 +1499,58 @@ Error RewriteInstance::discoverRtFiniAddress() {
14441499
"No relocation for first DT_FINI_ARRAY slot");
14451500
}
14461501

1502+
void RewriteInstance::updateRtInitReloc() {
1503+
if (BC->HasInterpHeader && !opts::InstrumentNoUseEntryPoint)
1504+
return;
1505+
1506+
// Updating DT_INIT is handled by patchELFDynamic.
1507+
if (BC->InitAddress)
1508+
return;
1509+
1510+
const RuntimeLibrary *RT = BC->getRuntimeLibrary();
1511+
if (!RT || !RT->getRuntimeStartAddress())
1512+
return;
1513+
1514+
if (!BC->InitArrayAddress)
1515+
return;
1516+
1517+
assert(BC->InitArrayAddress && BC->InitArraySize &&
1518+
"inconsistent .init_array state");
1519+
1520+
ErrorOr<BinarySection &> InitArraySection =
1521+
BC->getSectionForAddress(*BC->InitArrayAddress);
1522+
assert(InitArraySection && ".init_array removed");
1523+
1524+
if (std::optional<Relocation> Reloc =
1525+
InitArraySection->takeDynamicRelocationAt(0)) {
1526+
if (Reloc->isRelative()) {
1527+
assert(Reloc->Addend == BC->StartFunctionAddress &&
1528+
"inconsistent .init_array dynamic relocation");
1529+
Reloc->Addend = RT->getRuntimeStartAddress();
1530+
InitArraySection->addDynamicRelocation(*Reloc);
1531+
} else {
1532+
MCSymbol *Sym = Reloc->Symbol;
1533+
assert(Sym && "Failed to locate symbol for 0 entry of .init_array");
1534+
const BinaryFunction *BF = BC->getFunctionForSymbol(Sym);
1535+
assert(BF &&
1536+
"Failed to locate binary function for 0 entry of .init_array");
1537+
assert(BF->getAddress() + Reloc->Addend == BC->StartFunctionAddress &&
1538+
"inconsistent .init_array dynamic relocation");
1539+
InitArraySection->addDynamicRelocation(Relocation{
1540+
/*Offset*/ 0, /*Symbol*/ nullptr, /*Type*/ Relocation::getAbs64(),
1541+
/*Addend*/ RT->getRuntimeStartAddress(), /*Value*/ 0});
1542+
}
1543+
}
1544+
// Update the static relocation by adding a pending relocation which will get
1545+
// patched when flushPendingRelocations is called in rewriteFile. Note that
1546+
// flushPendingRelocations will calculate the value to patch as
1547+
// "Symbol + Addend". Since we don't have a symbol, just set the addend to the
1548+
// desired value.
1549+
InitArraySection->addPendingRelocation(Relocation{
1550+
/*Offset*/ 0, /*Symbol*/ nullptr, /*Type*/ Relocation::getAbs64(),
1551+
/*Addend*/ RT->getRuntimeStartAddress(), /*Value*/ 0});
1552+
}
1553+
14471554
void RewriteInstance::updateRtFiniReloc() {
14481555
// Updating DT_FINI is handled by patchELFDynamic.
14491556
if (BC->FiniAddress)
@@ -4838,7 +4945,8 @@ void RewriteInstance::patchELFSectionHeaderTable(ELFObjectFile<ELFT> *File) {
48384945
ELFEhdrTy NewEhdr = Obj.getHeader();
48394946

48404947
if (BC->HasRelocations) {
4841-
if (RuntimeLibrary *RtLibrary = BC->getRuntimeLibrary())
4948+
RuntimeLibrary *RtLibrary = BC->getRuntimeLibrary();
4949+
if (RtLibrary && !opts::InstrumentNoUseEntryPoint)
48424950
NewEhdr.e_entry = RtLibrary->getRuntimeStartAddress();
48434951
else
48444952
NewEhdr.e_entry = getNewFunctionAddress(NewEhdr.e_entry);
@@ -5684,7 +5792,8 @@ void RewriteInstance::patchELFDynamic(ELFObjectFile<ELFT> *File) {
56845792
if (uint64_t Addr = RtLibrary->getRuntimeFiniAddress())
56855793
NewDE.d_un.d_ptr = Addr;
56865794
}
5687-
if (RtLibrary && Dyn.getTag() == ELF::DT_INIT && !BC->HasInterpHeader) {
5795+
if (RtLibrary && Dyn.getTag() == ELF::DT_INIT &&
5796+
(!BC->HasInterpHeader || opts::InstrumentNoUseEntryPoint)) {
56885797
if (auto Addr = RtLibrary->getRuntimeStartAddress()) {
56895798
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: Set DT_INIT to 0x"
56905799
<< Twine::utohexstr(Addr) << '\n');
@@ -5760,6 +5869,13 @@ Error RewriteInstance::readELFDynamic(ELFObjectFile<ELFT> *File) {
57605869
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: Set start function address\n");
57615870
BC->StartFunctionAddress = Dyn.getPtr();
57625871
}
5872+
BC->InitAddress = Dyn.getPtr();
5873+
break;
5874+
case ELF::DT_INIT_ARRAY:
5875+
BC->InitArrayAddress = Dyn.getPtr();
5876+
break;
5877+
case ELF::DT_INIT_ARRAYSZ:
5878+
BC->InitArraySize = Dyn.getPtr();
57635879
break;
57645880
case ELF::DT_FINI:
57655881
BC->FiniAddress = Dyn.getPtr();

0 commit comments

Comments
 (0)