@@ -294,6 +294,28 @@ cl::bits<GadgetScannerKind> GadgetScannersToRun(
294294 clEnumValN(GS_ALL, " all" , " All implemented scanners" )),
295295 cl::ZeroOrMore, cl::CommaSeparated, cl::cat(BinaryAnalysisCategory));
296296
297+ // Primary targets for hooking runtime library initialization hooking
298+ // with fallback to next item in case if current item is not available
299+ // in the input binary.
300+ enum RuntimeLibInitHookTarget : char {
301+ RLIH_ENTRY_POINT = 0 , // / Use ELF Header Entry Point
302+ RLIH_INIT = 1 , // / Use ELF DT_INIT entry
303+ RLIH_INIT_ARRAY = 2 , // / Use ELF 1st entry of .init_array
304+ };
305+
306+ cl::opt<RuntimeLibInitHookTarget> RuntimeLibInitHook (
307+ " runtime-lib-init-hook" ,
308+ cl::desc (" Primary target for hooking runtime library initialization, used "
309+ " in fallback order of availabiliy in input binary (entry_point -> "
310+ " init -> init_array) (default: entry_point)" ),
311+ cl::init(RLIH_ENTRY_POINT),
312+ cl::values(clEnumValN(RLIH_ENTRY_POINT, " entry_point" ,
313+ " use ELF Header Entry Point" ),
314+ clEnumValN(RLIH_INIT, " init" , " use ELF DT_INIT entry" ),
315+ clEnumValN(RLIH_INIT_ARRAY, " init_array" ,
316+ " use ELF 1st entry of .init_array" )),
317+ cl::ZeroOrMore, cl::cat(BoltOptCategory));
318+
297319} // namespace opts
298320
299321// FIXME: implement a better way to mark sections for replacement.
@@ -741,9 +763,12 @@ Error RewriteInstance::run() {
741763 adjustCommandLineOptions ();
742764 discoverFileObjects ();
743765
744- if (opts::Instrument && !BC->IsStaticExecutable )
766+ if (opts::Instrument && !BC->IsStaticExecutable ) {
767+ if (Error E = discoverRtInitAddress ())
768+ return E;
745769 if (Error E = discoverRtFiniAddress ())
746770 return E;
771+ }
747772
748773 preprocessProfileData ();
749774
@@ -785,8 +810,11 @@ Error RewriteInstance::run() {
785810
786811 updateMetadata ();
787812
788- if (opts::Instrument && !BC->IsStaticExecutable )
813+ if (opts::Instrument && !BC->IsStaticExecutable ) {
814+ if (Error E = updateRtInitReloc ())
815+ return E;
789816 updateRtFiniReloc ();
817+ }
790818
791819 if (opts::OutputFilename == " /dev/null" ) {
792820 BC->outs () << " BOLT-INFO: skipping writing final binary to disk\n " ;
@@ -1411,6 +1439,60 @@ void RewriteInstance::discoverBOLTReserved() {
14111439 NextAvailableAddress = BC->BOLTReserved .start ();
14121440}
14131441
1442+ Error RewriteInstance::discoverRtInitAddress () {
1443+ if (BC->HasInterpHeader && opts::RuntimeLibInitHook == opts::RLIH_ENTRY_POINT)
1444+ return Error::success ();
1445+
1446+ // Use DT_INIT if it's available.
1447+ if (BC->InitAddress && opts::RuntimeLibInitHook <= opts::RLIH_INIT) {
1448+ BC->StartFunctionAddress = BC->InitAddress ;
1449+ return Error::success ();
1450+ }
1451+
1452+ if (!BC->InitArrayAddress || !BC->InitArraySize ) {
1453+ return createStringError (std::errc::not_supported,
1454+ " Instrumentation of shared library needs either "
1455+ " DT_INIT or DT_INIT_ARRAY" );
1456+ }
1457+
1458+ if (*BC->InitArraySize < BC->AsmInfo ->getCodePointerSize ()) {
1459+ return createStringError (std::errc::not_supported,
1460+ " Need at least 1 DT_INIT_ARRAY slot" );
1461+ }
1462+
1463+ ErrorOr<BinarySection &> InitArraySection =
1464+ BC->getSectionForAddress (*BC->InitArrayAddress );
1465+ if (auto EC = InitArraySection.getError ())
1466+ return errorCodeToError (EC);
1467+
1468+ if (const Relocation *Reloc = InitArraySection->getDynamicRelocationAt (0 )) {
1469+ if (Reloc->isRelative ()) {
1470+ BC->StartFunctionAddress = Reloc->Addend ;
1471+ } else {
1472+ MCSymbol *Sym = Reloc->Symbol ;
1473+ if (!Sym)
1474+ return createStringError (
1475+ std::errc::not_supported,
1476+ " Failed to locate symbol for 0 entry of .init_array" );
1477+ const BinaryFunction *BF = BC->getFunctionForSymbol (Sym);
1478+ if (!BF)
1479+ return createStringError (
1480+ std::errc::not_supported,
1481+ " Failed to locate binary function for 0 entry of .init_array" );
1482+ BC->StartFunctionAddress = BF->getAddress () + Reloc->Addend ;
1483+ }
1484+ return Error::success ();
1485+ }
1486+
1487+ if (const Relocation *Reloc = InitArraySection->getRelocationAt (0 )) {
1488+ BC->StartFunctionAddress = Reloc->Value ;
1489+ return Error::success ();
1490+ }
1491+
1492+ return createStringError (std::errc::not_supported,
1493+ " No relocation for first DT_INIT_ARRAY slot" );
1494+ }
1495+
14141496Error RewriteInstance::discoverRtFiniAddress () {
14151497 // Use DT_FINI if it's available.
14161498 if (BC->FiniAddress ) {
@@ -1448,6 +1530,68 @@ Error RewriteInstance::discoverRtFiniAddress() {
14481530 " No relocation for first DT_FINI_ARRAY slot" );
14491531}
14501532
1533+ Error RewriteInstance::updateRtInitReloc () {
1534+ if (BC->HasInterpHeader && opts::RuntimeLibInitHook == opts::RLIH_ENTRY_POINT)
1535+ return Error::success ();
1536+
1537+ // Updating DT_INIT is handled by patchELFDynamic.
1538+ if (BC->InitAddress && opts::RuntimeLibInitHook <= opts::RLIH_INIT)
1539+ return Error::success ();
1540+
1541+ const RuntimeLibrary *RT = BC->getRuntimeLibrary ();
1542+ if (!RT || !RT->getRuntimeStartAddress ())
1543+ return Error::success ();
1544+
1545+ if (!BC->InitArrayAddress )
1546+ return Error::success ();
1547+
1548+ if (!BC->InitArrayAddress || !BC->InitArraySize )
1549+ return createStringError (std::errc::not_supported,
1550+ " inconsistent .init_array state" );
1551+
1552+ ErrorOr<BinarySection &> InitArraySection =
1553+ BC->getSectionForAddress (*BC->InitArrayAddress );
1554+ if (!InitArraySection)
1555+ return createStringError (std::errc::not_supported, " .init_array removed" );
1556+
1557+ if (std::optional<Relocation> Reloc =
1558+ InitArraySection->takeDynamicRelocationAt (0 )) {
1559+ if (Reloc->isRelative ()) {
1560+ if (Reloc->Addend != BC->StartFunctionAddress )
1561+ return createStringError (std::errc::not_supported,
1562+ " inconsistent .init_array dynamic relocation" );
1563+ Reloc->Addend = RT->getRuntimeStartAddress ();
1564+ InitArraySection->addDynamicRelocation (*Reloc);
1565+ } else {
1566+ MCSymbol *Sym = Reloc->Symbol ;
1567+ if (!Sym)
1568+ return createStringError (
1569+ std::errc::not_supported,
1570+ " Failed to locate symbol for 0 entry of .init_array" );
1571+ const BinaryFunction *BF = BC->getFunctionForSymbol (Sym);
1572+ if (!BF)
1573+ return createStringError (
1574+ std::errc::not_supported,
1575+ " Failed to locate binary function for 0 entry of .init_array" );
1576+ if (BF->getAddress () + Reloc->Addend != BC->StartFunctionAddress )
1577+ return createStringError (std::errc::not_supported,
1578+ " inconsistent .init_array dynamic relocation" );
1579+ InitArraySection->addDynamicRelocation (Relocation{
1580+ /* Offset*/ 0 , /* Symbol*/ nullptr , /* Type*/ Relocation::getAbs64 (),
1581+ /* Addend*/ RT->getRuntimeStartAddress (), /* Value*/ 0 });
1582+ }
1583+ }
1584+ // Update the static relocation by adding a pending relocation which will get
1585+ // patched when flushPendingRelocations is called in rewriteFile. Note that
1586+ // flushPendingRelocations will calculate the value to patch as
1587+ // "Symbol + Addend". Since we don't have a symbol, just set the addend to the
1588+ // desired value.
1589+ InitArraySection->addPendingRelocation (Relocation{
1590+ /* Offset*/ 0 , /* Symbol*/ nullptr , /* Type*/ Relocation::getAbs64 (),
1591+ /* Addend*/ RT->getRuntimeStartAddress (), /* Value*/ 0 });
1592+ return Error::success ();
1593+ }
1594+
14511595void RewriteInstance::updateRtFiniReloc () {
14521596 // Updating DT_FINI is handled by patchELFDynamic.
14531597 if (BC->FiniAddress )
@@ -4849,7 +4993,8 @@ void RewriteInstance::patchELFSectionHeaderTable(ELFObjectFile<ELFT> *File) {
48494993 ELFEhdrTy NewEhdr = Obj.getHeader ();
48504994
48514995 if (BC->HasRelocations ) {
4852- if (RuntimeLibrary *RtLibrary = BC->getRuntimeLibrary ())
4996+ RuntimeLibrary *RtLibrary = BC->getRuntimeLibrary ();
4997+ if (RtLibrary && opts::RuntimeLibInitHook == opts::RLIH_ENTRY_POINT)
48534998 NewEhdr.e_entry = RtLibrary->getRuntimeStartAddress ();
48544999 else
48555000 NewEhdr.e_entry = getNewFunctionAddress (NewEhdr.e_entry );
@@ -5695,7 +5840,9 @@ void RewriteInstance::patchELFDynamic(ELFObjectFile<ELFT> *File) {
56955840 if (uint64_t Addr = RtLibrary->getRuntimeFiniAddress ())
56965841 NewDE.d_un .d_ptr = Addr;
56975842 }
5698- if (RtLibrary && Dyn.getTag () == ELF::DT_INIT && !BC->HasInterpHeader ) {
5843+ if (RtLibrary && Dyn.getTag () == ELF::DT_INIT &&
5844+ (!BC->HasInterpHeader ||
5845+ opts::RuntimeLibInitHook == opts::RLIH_INIT)) {
56995846 if (auto Addr = RtLibrary->getRuntimeStartAddress ()) {
57005847 LLVM_DEBUG (dbgs () << " BOLT-DEBUG: Set DT_INIT to 0x"
57015848 << Twine::utohexstr (Addr) << ' \n ' );
@@ -5767,10 +5914,13 @@ Error RewriteInstance::readELFDynamic(ELFObjectFile<ELFT> *File) {
57675914 for (const Elf_Dyn &Dyn : DynamicEntries) {
57685915 switch (Dyn.d_tag ) {
57695916 case ELF::DT_INIT:
5770- if (!BC->HasInterpHeader ) {
5771- LLVM_DEBUG (dbgs () << " BOLT-DEBUG: Set start function address\n " );
5772- BC->StartFunctionAddress = Dyn.getPtr ();
5773- }
5917+ BC->InitAddress = Dyn.getPtr ();
5918+ break ;
5919+ case ELF::DT_INIT_ARRAY:
5920+ BC->InitArrayAddress = Dyn.getPtr ();
5921+ break ;
5922+ case ELF::DT_INIT_ARRAYSZ:
5923+ BC->InitArraySize = Dyn.getPtr ();
57745924 break ;
57755925 case ELF::DT_FINI:
57765926 BC->FiniAddress = Dyn.getPtr ();
0 commit comments