@@ -292,6 +292,28 @@ cl::bits<GadgetScannerKind> GadgetScannersToRun(
292292 clEnumValN(GS_ALL, " all" , " All implemented scanners" )),
293293 cl::ZeroOrMore, cl::CommaSeparated, cl::cat(BinaryAnalysisCategory));
294294
295+ // Primary targets for hooking runtime library initialization hooking
296+ // with fallback to next item in case if current item is not available
297+ // in the input binary.
298+ enum RuntimeLibInitHookTarget : char {
299+ RLIH_ENTRY_POINT = 0 , // / Use ELF Header Entry Point
300+ RLIH_INIT = 1 , // / Use ELF DT_INIT entry
301+ RLIH_INIT_ARRAY = 2 , // / Use ELF 1st entry of .init_array
302+ };
303+
304+ cl::opt<RuntimeLibInitHookTarget> RuntimeLibInitHook (
305+ " runtime-lib-init-hook" ,
306+ cl::desc (" Primary target for hooking runtime library initialization, used "
307+ " in fallback order of availabiliy in input binary (entry-point -> "
308+ " init -> init_array) (default: entry_point)" ),
309+ cl::init(RLIH_ENTRY_POINT),
310+ cl::values(clEnumValN(RLIH_ENTRY_POINT, " entry_point" ,
311+ " use ELF Header Entry Point" ),
312+ clEnumValN(RLIH_INIT, " init" , " use ELF DT_INIT entry" ),
313+ clEnumValN(RLIH_INIT_ARRAY, " init_array" ,
314+ " use ELF 1st entry of .init_array" )),
315+ cl::ZeroOrMore, cl::cat(BoltOptCategory));
316+
295317} // namespace opts
296318
297319// FIXME: implement a better way to mark sections for replacement.
@@ -737,9 +759,12 @@ Error RewriteInstance::run() {
737759 adjustCommandLineOptions ();
738760 discoverFileObjects ();
739761
740- if (opts::Instrument && !BC->IsStaticExecutable )
762+ if (opts::Instrument && !BC->IsStaticExecutable ) {
763+ if (Error E = discoverRtInitAddress ())
764+ return E;
741765 if (Error E = discoverRtFiniAddress ())
742766 return E;
767+ }
743768
744769 preprocessProfileData ();
745770
@@ -781,8 +806,11 @@ Error RewriteInstance::run() {
781806
782807 updateMetadata ();
783808
784- if (opts::Instrument && !BC->IsStaticExecutable )
809+ if (opts::Instrument && !BC->IsStaticExecutable ) {
810+ if (Error E = updateRtInitReloc ())
811+ return E;
785812 updateRtFiniReloc ();
813+ }
786814
787815 if (opts::OutputFilename == " /dev/null" ) {
788816 BC->outs () << " BOLT-INFO: skipping writing final binary to disk\n " ;
@@ -1407,6 +1435,60 @@ void RewriteInstance::discoverBOLTReserved() {
14071435 NextAvailableAddress = BC->BOLTReserved .start ();
14081436}
14091437
1438+ Error RewriteInstance::discoverRtInitAddress () {
1439+ if (BC->HasInterpHeader && opts::RuntimeLibInitHook == opts::RLIH_ENTRY_POINT)
1440+ return Error::success ();
1441+
1442+ // Use DT_INIT if it's available.
1443+ if (BC->InitAddress && opts::RuntimeLibInitHook <= opts::RLIH_INIT) {
1444+ BC->StartFunctionAddress = BC->InitAddress ;
1445+ return Error::success ();
1446+ }
1447+
1448+ if (!BC->InitArrayAddress || !BC->InitArraySize ) {
1449+ return createStringError (std::errc::not_supported,
1450+ " Instrumentation of shared library needs either "
1451+ " DT_INIT or DT_INIT_ARRAY" );
1452+ }
1453+
1454+ if (*BC->InitArraySize < BC->AsmInfo ->getCodePointerSize ()) {
1455+ return createStringError (std::errc::not_supported,
1456+ " Need at least 1 DT_INIT_ARRAY slot" );
1457+ }
1458+
1459+ ErrorOr<BinarySection &> InitArraySection =
1460+ BC->getSectionForAddress (*BC->InitArrayAddress );
1461+ if (auto EC = InitArraySection.getError ())
1462+ return errorCodeToError (EC);
1463+
1464+ if (const Relocation *Reloc = InitArraySection->getDynamicRelocationAt (0 )) {
1465+ if (Reloc->isRelative ()) {
1466+ BC->StartFunctionAddress = Reloc->Addend ;
1467+ } else {
1468+ MCSymbol *Sym = Reloc->Symbol ;
1469+ if (!Sym)
1470+ return createStringError (
1471+ std::errc::not_supported,
1472+ " Failed to locate symbol for 0 entry of .init_array" );
1473+ const BinaryFunction *BF = BC->getFunctionForSymbol (Sym);
1474+ if (!BF)
1475+ return createStringError (
1476+ std::errc::not_supported,
1477+ " Failed to locate binary function for 0 entry of .init_array" );
1478+ BC->StartFunctionAddress = BF->getAddress () + Reloc->Addend ;
1479+ }
1480+ return Error::success ();
1481+ }
1482+
1483+ if (const Relocation *Reloc = InitArraySection->getRelocationAt (0 )) {
1484+ BC->StartFunctionAddress = Reloc->Value ;
1485+ return Error::success ();
1486+ }
1487+
1488+ return createStringError (std::errc::not_supported,
1489+ " No relocation for first DT_INIT_ARRAY slot" );
1490+ }
1491+
14101492Error RewriteInstance::discoverRtFiniAddress () {
14111493 // Use DT_FINI if it's available.
14121494 if (BC->FiniAddress ) {
@@ -1444,6 +1526,68 @@ Error RewriteInstance::discoverRtFiniAddress() {
14441526 " No relocation for first DT_FINI_ARRAY slot" );
14451527}
14461528
1529+ Error RewriteInstance::updateRtInitReloc () {
1530+ if (BC->HasInterpHeader && opts::RuntimeLibInitHook == opts::RLIH_ENTRY_POINT)
1531+ return Error::success ();
1532+
1533+ // Updating DT_INIT is handled by patchELFDynamic.
1534+ if (BC->InitAddress && opts::RuntimeLibInitHook <= opts::RLIH_INIT)
1535+ return Error::success ();
1536+
1537+ const RuntimeLibrary *RT = BC->getRuntimeLibrary ();
1538+ if (!RT || !RT->getRuntimeStartAddress ())
1539+ return Error::success ();
1540+
1541+ if (!BC->InitArrayAddress )
1542+ return Error::success ();
1543+
1544+ if (!BC->InitArrayAddress || !BC->InitArraySize )
1545+ return createStringError (std::errc::not_supported,
1546+ " inconsistent .init_array state" );
1547+
1548+ ErrorOr<BinarySection &> InitArraySection =
1549+ BC->getSectionForAddress (*BC->InitArrayAddress );
1550+ if (!InitArraySection)
1551+ return createStringError (std::errc::not_supported, " .init_array removed" );
1552+
1553+ if (std::optional<Relocation> Reloc =
1554+ InitArraySection->takeDynamicRelocationAt (0 )) {
1555+ if (Reloc->isRelative ()) {
1556+ if (Reloc->Addend != BC->StartFunctionAddress )
1557+ return createStringError (std::errc::not_supported,
1558+ " inconsistent .init_array dynamic relocation" );
1559+ Reloc->Addend = RT->getRuntimeStartAddress ();
1560+ InitArraySection->addDynamicRelocation (*Reloc);
1561+ } else {
1562+ MCSymbol *Sym = Reloc->Symbol ;
1563+ if (!Sym)
1564+ return createStringError (
1565+ std::errc::not_supported,
1566+ " Failed to locate symbol for 0 entry of .init_array" );
1567+ const BinaryFunction *BF = BC->getFunctionForSymbol (Sym);
1568+ if (!BF)
1569+ return createStringError (
1570+ std::errc::not_supported,
1571+ " Failed to locate binary function for 0 entry of .init_array" );
1572+ if (BF->getAddress () + Reloc->Addend != BC->StartFunctionAddress )
1573+ return createStringError (std::errc::not_supported,
1574+ " inconsistent .init_array dynamic relocation" );
1575+ InitArraySection->addDynamicRelocation (Relocation{
1576+ /* Offset*/ 0 , /* Symbol*/ nullptr , /* Type*/ Relocation::getAbs64 (),
1577+ /* Addend*/ RT->getRuntimeStartAddress (), /* Value*/ 0 });
1578+ }
1579+ }
1580+ // Update the static relocation by adding a pending relocation which will get
1581+ // patched when flushPendingRelocations is called in rewriteFile. Note that
1582+ // flushPendingRelocations will calculate the value to patch as
1583+ // "Symbol + Addend". Since we don't have a symbol, just set the addend to the
1584+ // desired value.
1585+ InitArraySection->addPendingRelocation (Relocation{
1586+ /* Offset*/ 0 , /* Symbol*/ nullptr , /* Type*/ Relocation::getAbs64 (),
1587+ /* Addend*/ RT->getRuntimeStartAddress (), /* Value*/ 0 });
1588+ return Error::success ();
1589+ }
1590+
14471591void RewriteInstance::updateRtFiniReloc () {
14481592 // Updating DT_FINI is handled by patchELFDynamic.
14491593 if (BC->FiniAddress )
@@ -4838,7 +4982,8 @@ void RewriteInstance::patchELFSectionHeaderTable(ELFObjectFile<ELFT> *File) {
48384982 ELFEhdrTy NewEhdr = Obj.getHeader ();
48394983
48404984 if (BC->HasRelocations ) {
4841- if (RuntimeLibrary *RtLibrary = BC->getRuntimeLibrary ())
4985+ RuntimeLibrary *RtLibrary = BC->getRuntimeLibrary ();
4986+ if (RtLibrary && opts::RuntimeLibInitHook == opts::RLIH_ENTRY_POINT)
48424987 NewEhdr.e_entry = RtLibrary->getRuntimeStartAddress ();
48434988 else
48444989 NewEhdr.e_entry = getNewFunctionAddress (NewEhdr.e_entry );
@@ -5684,7 +5829,9 @@ void RewriteInstance::patchELFDynamic(ELFObjectFile<ELFT> *File) {
56845829 if (uint64_t Addr = RtLibrary->getRuntimeFiniAddress ())
56855830 NewDE.d_un .d_ptr = Addr;
56865831 }
5687- if (RtLibrary && Dyn.getTag () == ELF::DT_INIT && !BC->HasInterpHeader ) {
5832+ if (RtLibrary && Dyn.getTag () == ELF::DT_INIT &&
5833+ (!BC->HasInterpHeader ||
5834+ opts::RuntimeLibInitHook == opts::RLIH_INIT)) {
56885835 if (auto Addr = RtLibrary->getRuntimeStartAddress ()) {
56895836 LLVM_DEBUG (dbgs () << " BOLT-DEBUG: Set DT_INIT to 0x"
56905837 << Twine::utohexstr (Addr) << ' \n ' );
@@ -5760,6 +5907,13 @@ Error RewriteInstance::readELFDynamic(ELFObjectFile<ELFT> *File) {
57605907 LLVM_DEBUG (dbgs () << " BOLT-DEBUG: Set start function address\n " );
57615908 BC->StartFunctionAddress = Dyn.getPtr ();
57625909 }
5910+ BC->InitAddress = Dyn.getPtr ();
5911+ break ;
5912+ case ELF::DT_INIT_ARRAY:
5913+ BC->InitArrayAddress = Dyn.getPtr ();
5914+ break ;
5915+ case ELF::DT_INIT_ARRAYSZ:
5916+ BC->InitArraySize = Dyn.getPtr ();
57635917 break ;
57645918 case ELF::DT_FINI:
57655919 BC->FiniAddress = Dyn.getPtr ();
0 commit comments