From 21bf785e21da5575ab5d061adf81e29a8cb0ccb3 Mon Sep 17 00:00:00 2001 From: Vasily Leonenko Date: Sun, 9 Nov 2025 14:55:06 -0500 Subject: [PATCH 1/6] [BOLT] Support runtime library hook via DT_INIT_ARRAY This commit follows implementation of instrumentation hook via DT_FINI_ARRAY (#67348) and extends it for BOLT runtime libraries (including instrumentation library) 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 "runtime-lib-init-hook" option to select primary initialization hook (entry_point, init, init_array) with fall back to next available hook in input binary. e.g. in case of libc we can explicitly set it to init_array. - 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. --- bolt/docs/CommandLineArgumentReference.md | 9 ++ bolt/include/bolt/Core/BinaryContext.h | 9 ++ bolt/include/bolt/Rewrite/RewriteInstance.h | 9 ++ bolt/lib/Rewrite/RewriteInstance.cpp | 162 +++++++++++++++++++- 4 files changed, 185 insertions(+), 4 deletions(-) diff --git a/bolt/docs/CommandLineArgumentReference.md b/bolt/docs/CommandLineArgumentReference.md index 7c6e01d669b74..8e4e5730b5b45 100644 --- a/bolt/docs/CommandLineArgumentReference.md +++ b/bolt/docs/CommandLineArgumentReference.md @@ -811,6 +811,15 @@ Specify file name of the runtime instrumentation library +- `--runtime-lib-init-hook=` + + Primary target for hooking runtime library initialization, used in + fallback order of availabiliy in input binary (entry_point -> init + -> init_array) (default: entry_point) + - `entry_point`: use ELF Header Entry Point + - `init`: use ELF DT_INIT entry + - `init_array`: use ELF 1st entry of .init_array + - `--sctc-mode=` Mode for simplify conditional tail calls diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h index 2af1d330b7545..8a90febcea3cc 100644 --- a/bolt/include/bolt/Core/BinaryContext.h +++ b/bolt/include/bolt/Core/BinaryContext.h @@ -807,6 +807,15 @@ class BinaryContext { /// the execution of the binary is completed. std::optional FiniFunctionAddress; + /// DT_INIT. + std::optional InitAddress; + + /// DT_INIT_ARRAY. Only used when DT_INIT is not set. + std::optional InitArrayAddress; + + /// DT_INIT_ARRAYSZ. Only used when DT_INIT is not set. + std::optional InitArraySize; + /// DT_FINI. std::optional FiniAddress; diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h index 35abf6b4d4ddd..6b2a0143bbc42 100644 --- a/bolt/include/bolt/Rewrite/RewriteInstance.h +++ b/bolt/include/bolt/Rewrite/RewriteInstance.h @@ -93,11 +93,20 @@ class RewriteInstance { /// section allocations if found. void discoverBOLTReserved(); + /// Check whether we should use DT_INIT or DT_INIT_ARRAY for instrumentation. + /// DT_INIT is preferred; DT_INIT_ARRAY is only used when no DT_INIT entry was + /// found. + Error discoverRtInitAddress(); + /// Check whether we should use DT_FINI or DT_FINI_ARRAY for instrumentation. /// DT_FINI is preferred; DT_FINI_ARRAY is only used when no DT_FINI entry was /// found. Error discoverRtFiniAddress(); + /// If DT_INIT_ARRAY is used for instrumentation, update the relocation of its + /// first entry to point to the instrumentation library's init address. + Error updateRtInitReloc(); + /// If DT_FINI_ARRAY is used for instrumentation, update the relocation of its /// first entry to point to the instrumentation library's fini address. void updateRtFiniReloc(); diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 0e100bec01ca6..d356d5c3f97db 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -294,6 +294,28 @@ cl::bits GadgetScannersToRun( clEnumValN(GS_ALL, "all", "All implemented scanners")), cl::ZeroOrMore, cl::CommaSeparated, cl::cat(BinaryAnalysisCategory)); +// Primary targets for hooking runtime library initialization hooking +// with fallback to next item in case if current item is not available +// in the input binary. +enum RuntimeLibInitHookTarget : char { + RLIH_ENTRY_POINT = 0, /// Use ELF Header Entry Point + RLIH_INIT = 1, /// Use ELF DT_INIT entry + RLIH_INIT_ARRAY = 2, /// Use ELF 1st entry of .init_array +}; + +cl::opt RuntimeLibInitHook( + "runtime-lib-init-hook", + cl::desc("Primary target for hooking runtime library initialization, used " + "in fallback order of availabiliy in input binary (entry_point -> " + "init -> init_array) (default: entry_point)"), + cl::init(RLIH_ENTRY_POINT), + cl::values(clEnumValN(RLIH_ENTRY_POINT, "entry_point", + "use ELF Header Entry Point"), + clEnumValN(RLIH_INIT, "init", "use ELF DT_INIT entry"), + clEnumValN(RLIH_INIT_ARRAY, "init_array", + "use ELF 1st entry of .init_array")), + cl::ZeroOrMore, cl::cat(BoltOptCategory)); + } // namespace opts // FIXME: implement a better way to mark sections for replacement. @@ -741,9 +763,12 @@ Error RewriteInstance::run() { adjustCommandLineOptions(); discoverFileObjects(); - if (opts::Instrument && !BC->IsStaticExecutable) + if (opts::Instrument && !BC->IsStaticExecutable) { + if (Error E = discoverRtInitAddress()) + return E; if (Error E = discoverRtFiniAddress()) return E; + } preprocessProfileData(); @@ -785,8 +810,11 @@ Error RewriteInstance::run() { updateMetadata(); - if (opts::Instrument && !BC->IsStaticExecutable) + if (opts::Instrument && !BC->IsStaticExecutable) { + if (Error E = updateRtInitReloc()) + return E; updateRtFiniReloc(); + } if (opts::OutputFilename == "/dev/null") { BC->outs() << "BOLT-INFO: skipping writing final binary to disk\n"; @@ -1411,6 +1439,60 @@ void RewriteInstance::discoverBOLTReserved() { NextAvailableAddress = BC->BOLTReserved.start(); } +Error RewriteInstance::discoverRtInitAddress() { + if (BC->HasInterpHeader && opts::RuntimeLibInitHook == opts::RLIH_ENTRY_POINT) + return Error::success(); + + // Use DT_INIT if it's available. + if (BC->InitAddress && opts::RuntimeLibInitHook <= opts::RLIH_INIT) { + BC->StartFunctionAddress = BC->InitAddress; + return Error::success(); + } + + if (!BC->InitArrayAddress || !BC->InitArraySize) { + return createStringError(std::errc::not_supported, + "Instrumentation of shared library needs either " + "DT_INIT or DT_INIT_ARRAY"); + } + + if (*BC->InitArraySize < BC->AsmInfo->getCodePointerSize()) { + return createStringError(std::errc::not_supported, + "Need at least 1 DT_INIT_ARRAY slot"); + } + + ErrorOr InitArraySection = + BC->getSectionForAddress(*BC->InitArrayAddress); + if (auto EC = InitArraySection.getError()) + return errorCodeToError(EC); + + if (const Relocation *Reloc = InitArraySection->getDynamicRelocationAt(0)) { + if (Reloc->isRelative()) { + BC->StartFunctionAddress = Reloc->Addend; + } else { + MCSymbol *Sym = Reloc->Symbol; + if (!Sym) + return createStringError( + std::errc::not_supported, + "Failed to locate symbol for 0 entry of .init_array"); + const BinaryFunction *BF = BC->getFunctionForSymbol(Sym); + if (!BF) + return createStringError( + std::errc::not_supported, + "Failed to locate binary function for 0 entry of .init_array"); + BC->StartFunctionAddress = BF->getAddress() + Reloc->Addend; + } + return Error::success(); + } + + if (const Relocation *Reloc = InitArraySection->getRelocationAt(0)) { + BC->StartFunctionAddress = Reloc->Value; + return Error::success(); + } + + return createStringError(std::errc::not_supported, + "No relocation for first DT_INIT_ARRAY slot"); +} + Error RewriteInstance::discoverRtFiniAddress() { // Use DT_FINI if it's available. if (BC->FiniAddress) { @@ -1448,6 +1530,68 @@ Error RewriteInstance::discoverRtFiniAddress() { "No relocation for first DT_FINI_ARRAY slot"); } +Error RewriteInstance::updateRtInitReloc() { + if (BC->HasInterpHeader && opts::RuntimeLibInitHook == opts::RLIH_ENTRY_POINT) + return Error::success(); + + // Updating DT_INIT is handled by patchELFDynamic. + if (BC->InitAddress && opts::RuntimeLibInitHook <= opts::RLIH_INIT) + return Error::success(); + + const RuntimeLibrary *RT = BC->getRuntimeLibrary(); + if (!RT || !RT->getRuntimeStartAddress()) + return Error::success(); + + if (!BC->InitArrayAddress) + return Error::success(); + + if (!BC->InitArrayAddress || !BC->InitArraySize) + return createStringError(std::errc::not_supported, + "inconsistent .init_array state"); + + ErrorOr InitArraySection = + BC->getSectionForAddress(*BC->InitArrayAddress); + if (!InitArraySection) + return createStringError(std::errc::not_supported, ".init_array removed"); + + if (std::optional Reloc = + InitArraySection->takeDynamicRelocationAt(0)) { + if (Reloc->isRelative()) { + if (Reloc->Addend != BC->StartFunctionAddress) + return createStringError(std::errc::not_supported, + "inconsistent .init_array dynamic relocation"); + Reloc->Addend = RT->getRuntimeStartAddress(); + InitArraySection->addDynamicRelocation(*Reloc); + } else { + MCSymbol *Sym = Reloc->Symbol; + if (!Sym) + return createStringError( + std::errc::not_supported, + "Failed to locate symbol for 0 entry of .init_array"); + const BinaryFunction *BF = BC->getFunctionForSymbol(Sym); + if (!BF) + return createStringError( + std::errc::not_supported, + "Failed to locate binary function for 0 entry of .init_array"); + if (BF->getAddress() + Reloc->Addend != BC->StartFunctionAddress) + return createStringError(std::errc::not_supported, + "inconsistent .init_array dynamic relocation"); + InitArraySection->addDynamicRelocation(Relocation{ + /*Offset*/ 0, /*Symbol*/ nullptr, /*Type*/ Relocation::getAbs64(), + /*Addend*/ RT->getRuntimeStartAddress(), /*Value*/ 0}); + } + } + // Update the static relocation by adding a pending relocation which will get + // patched when flushPendingRelocations is called in rewriteFile. Note that + // flushPendingRelocations will calculate the value to patch as + // "Symbol + Addend". Since we don't have a symbol, just set the addend to the + // desired value. + InitArraySection->addPendingRelocation(Relocation{ + /*Offset*/ 0, /*Symbol*/ nullptr, /*Type*/ Relocation::getAbs64(), + /*Addend*/ RT->getRuntimeStartAddress(), /*Value*/ 0}); + return Error::success(); +} + void RewriteInstance::updateRtFiniReloc() { // Updating DT_FINI is handled by patchELFDynamic. if (BC->FiniAddress) @@ -4849,7 +4993,8 @@ void RewriteInstance::patchELFSectionHeaderTable(ELFObjectFile *File) { ELFEhdrTy NewEhdr = Obj.getHeader(); if (BC->HasRelocations) { - if (RuntimeLibrary *RtLibrary = BC->getRuntimeLibrary()) + RuntimeLibrary *RtLibrary = BC->getRuntimeLibrary(); + if (RtLibrary && opts::RuntimeLibInitHook == opts::RLIH_ENTRY_POINT) NewEhdr.e_entry = RtLibrary->getRuntimeStartAddress(); else NewEhdr.e_entry = getNewFunctionAddress(NewEhdr.e_entry); @@ -5695,7 +5840,9 @@ void RewriteInstance::patchELFDynamic(ELFObjectFile *File) { if (uint64_t Addr = RtLibrary->getRuntimeFiniAddress()) NewDE.d_un.d_ptr = Addr; } - if (RtLibrary && Dyn.getTag() == ELF::DT_INIT && !BC->HasInterpHeader) { + if (RtLibrary && Dyn.getTag() == ELF::DT_INIT && + (!BC->HasInterpHeader || + opts::RuntimeLibInitHook == opts::RLIH_INIT)) { if (auto Addr = RtLibrary->getRuntimeStartAddress()) { LLVM_DEBUG(dbgs() << "BOLT-DEBUG: Set DT_INIT to 0x" << Twine::utohexstr(Addr) << '\n'); @@ -5771,6 +5918,13 @@ Error RewriteInstance::readELFDynamic(ELFObjectFile *File) { LLVM_DEBUG(dbgs() << "BOLT-DEBUG: Set start function address\n"); BC->StartFunctionAddress = Dyn.getPtr(); } + BC->InitAddress = Dyn.getPtr(); + break; + case ELF::DT_INIT_ARRAY: + BC->InitArrayAddress = Dyn.getPtr(); + break; + case ELF::DT_INIT_ARRAYSZ: + BC->InitArraySize = Dyn.getPtr(); break; case ELF::DT_FINI: BC->FiniAddress = Dyn.getPtr(); From f8abb77b6757fc5a8a251b40669ad17bd781e414 Mon Sep 17 00:00:00 2001 From: Vasily Leonenko Date: Thu, 6 Nov 2025 15:36:03 -0500 Subject: [PATCH 2/6] [BOLT][test] Add hook-init AArch64 test for checking instrumentation initialization --- bolt/test/AArch64/hook-init.s | 206 ++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 bolt/test/AArch64/hook-init.s diff --git a/bolt/test/AArch64/hook-init.s b/bolt/test/AArch64/hook-init.s new file mode 100644 index 0000000000000..e5b11ecae57cc --- /dev/null +++ b/bolt/test/AArch64/hook-init.s @@ -0,0 +1,206 @@ +## Test the different ways of hooking the init function for instrumentation (via +## entry point, DT_INIT and via DT_INIT_ARRAY). We test the latter for both PIE +## and non-PIE binaries because of the different ways of handling relocations +## (static or dynamic), executable and shared library. +## All tests perform the following steps: +## - Compile and link for the case to be tested +## - Some sanity-checks on the dynamic section and relocations in the binary to +## verify it has the shape we want for testing: +## - INTERP in Program Headers +## - DT_INIT or DT_INIT_ARRAY in dynamic section +## - No relative relocations for non-PIE +## - Instrument (with extra --runtime-lib-init-hook=init/init_array options +## in some cases) +## - Verify generated binary +# REQUIRES: system-linux,bolt-runtime,target=aarch64{{.*}} + +# RUN: %clang %cflags -pie %s -Wl,-q -o %t.exe +# RUN: llvm-readelf -d %t.exe | FileCheck --check-prefix=DYN-INIT %s +# RUN: llvm-readelf -l %t.exe | FileCheck --check-prefix=PH-INTERP %s +# RUN: llvm-readelf -r %t.exe | FileCheck --check-prefix=RELOC-PIE %s +# RUN: llvm-bolt %t.exe -o %t --instrument +# RUN: llvm-readelf -hdrs %t | FileCheck --check-prefix=CHECK-INIT-EP %s +# RUN: llvm-bolt %t.exe -o %t-no-ep --instrument --runtime-lib-init-hook=init +# RUN: llvm-readelf -hdrs %t-no-ep | FileCheck --check-prefix=CHECK-INIT-NO-EP %s +# RUN: llvm-bolt %t.exe -o %t-no-ep --instrument --runtime-lib-init-hook=init_array +# RUN: llvm-readelf -hdrs %t-no-ep | FileCheck --check-prefix=CHECK-INIT-ARRAY-NO-EP %s + +# RUN: %clang -shared %cflags -pie %s -Wl,-q -o %t-shared.exe +# RUN: llvm-readelf -d %t-shared.exe | FileCheck --check-prefix=DYN-INIT %s +# RUN: llvm-readelf -l %t-shared.exe | FileCheck --check-prefix=PH-INTERP-SHARED %s +# RUN: llvm-readelf -r %t-shared.exe | FileCheck --check-prefix=RELOC-SHARED-PIE %s +# RUN: llvm-bolt %t-shared.exe -o %t-shared --instrument +# RUN: llvm-readelf -hdrs %t-shared | FileCheck --check-prefix=CHECK-SHARED-INIT %s + +# RUN: %clang %cflags -pie %s -Wl,-q,-init=0 -o %t-no-init.exe +# RUN: llvm-readelf -d %t-no-init.exe | FileCheck --check-prefix=DYN-NO-INIT %s +# RUN: llvm-readelf -l %t-no-init.exe | FileCheck --check-prefix=PH-INTERP %s +# RUN: llvm-readelf -r %t-no-init.exe | FileCheck --check-prefix=RELOC-PIE %s +# RUN: llvm-bolt %t-no-init.exe -o %t-no-init --instrument +# RUN: llvm-readelf -hdrs %t-no-init | FileCheck --check-prefix=CHECK-NO-INIT-EP %s +# RUN: llvm-bolt %t-no-init.exe -o %t-no-init-no-ep --instrument --runtime-lib-init-hook=init +# RUN: llvm-readelf -hdrs %t-no-init-no-ep | FileCheck --check-prefix=CHECK-NO-INIT-NO-EP %s + +# RUN: %clang -shared %cflags -pie %s -Wl,-q,-init=0 -o %t-shared-no-init.exe +# RUN: llvm-readelf -d %t-shared-no-init.exe | FileCheck --check-prefix=DYN-NO-INIT %s +# RUN: llvm-readelf -l %t-shared-no-init.exe | FileCheck --check-prefix=PH-INTERP-SHARED %s +# RUN: llvm-readelf -r %t-shared-no-init.exe | FileCheck --check-prefix=RELOC-SHARED-PIE %s +# RUN: llvm-bolt %t-shared-no-init.exe -o %t-shared-no-init --instrument +# RUN: llvm-readelf -drs %t-shared-no-init | FileCheck --check-prefix=CHECK-SHARED-NO-INIT %s + +## Create a dummy shared library to link against to force creation of the dynamic section. +# RUN: %clang %cflags %p/../Inputs/stub.c -fPIC -shared -o %t-stub.so +# RUN: %clang %cflags %s -no-pie -Wl,-q,-init=0 %t-stub.so -o %t-no-pie-no-init.exe +# RUN: llvm-readelf -r %t-no-pie-no-init.exe | FileCheck --check-prefix=RELOC-NO-PIE %s +# RUN: llvm-bolt %t-no-pie-no-init.exe -o %t-no-pie-no-init --instrument +# RUN: llvm-readelf -hds %t-no-pie-no-init | FileCheck --check-prefix=CHECK-NO-PIE-NO-INIT-EP %s + +## With init: dynamic section should contain DT_INIT +# DYN-INIT: (INIT) + +## Without init: dynamic section should only contain DT_INIT_ARRAY +# DYN-NO-INIT-NOT: (INIT) +# DYN-NO-INIT: (INIT_ARRAY) +# DYN-NO-INIT: (INIT_ARRAYSZ) + +## With interp program header (executable) +# PH-INTERP: Program Headers: +# PH-INTERP: INTERP + +## Without interp program header (shared library) +# PH-INTERP-SHARED: Program Headers: +# PH-INTERP-SHARED-NOT: INTERP + +## With PIE: binary should have relative relocations +# RELOC-PIE: R_AARCH64_RELATIVE + +## With PIE: binary should have relative relocations +# RELOC-SHARED-PIE: R_AARCH64_ABS64 + +## Without PIE: binary should not have relative relocations +# RELOC-NO-PIE-NOT: R_AARCH64_RELATIVE + +## Check that entry point address is set to __bolt_runtime_start for PIE executable with DT_INIT +# CHECK-INIT-EP: ELF Header: +# CHECK-INIT-EP: Entry point address: 0x[[#%x,EP_ADDR:]] +## Check that the dynamic relocation at .init and .init_array were not patched +# CHECK-INIT-EP: Dynamic section at offset {{.*}} contains {{.*}} entries: +# CHECK-INIT-EP-NOT: (INIT) 0x[[#%x, EP_ADDR]] +# CHECK-INIT-EP-NOT: (INIT_ARRAY) 0x[[#%x, EP_ADDR]] +## Check that the new entry point address points to __bolt_runtime_start +# CHECK-INIT-EP: Symbol table '.symtab' contains {{.*}} entries: +# CHECK-INIT-EP: {{0+}}[[#%x, EP_ADDR]] {{.*}} __bolt_runtime_start + +## Check that DT_INIT address is set to __bolt_runtime_start for PIE executable with DT_INIT +# CHECK-INIT-NO-EP: ELF Header: +# CHECK-INIT-NO-EP: Entry point address: 0x[[#%x,EP_ADDR:]] +## Read Dynamic section DT_INIT and DT_INIT_ARRAY entries +# CHECK-INIT-NO-EP: Dynamic section at offset {{.*}} contains {{.*}} entries: +# CHECK-INIT-NO-EP-DAG: (INIT) 0x[[#%x,INIT:]] +# CHECK-INIT-NO-EP-DAG: (INIT_ARRAY) 0x[[#%x,INIT_ARRAY:]] +## Check if ELF entry point address points to _start symbol and new DT_INIT entry points to __bolt_runtime_start +# CHECK-INIT-NO-EP: Symbol table '.symtab' contains {{.*}} entries: +# CHECK-INIT-NO-EP-DAG: {{0+}}[[#%x, EP_ADDR]] {{.*}} _start +# CHECK-INIT-NO-EP-DAG: {{0+}}[[#%x, INIT]] {{.*}} __bolt_runtime_start + +## Check that 1st entry of DT_INIT_ARRAY is set to __bolt_runtime_start and DT_INIT was not changed +# CHECK-INIT-ARRAY-NO-EP: ELF Header: +# CHECK-INIT-ARRAY-NO-EP: Entry point address: 0x[[#%x,EP_ADDR:]] +## Read Dynamic section DT_INIT and DT_INIT_ARRAY entries +# CHECK-INIT-ARRAY-NO-EP: Dynamic section at offset {{.*}} contains {{.*}} entries: +# CHECK-INIT-ARRAY-NO-EP-DAG: (INIT) 0x[[#%x,INIT:]] +# CHECK-INIT-ARRAY-NO-EP-DAG: (INIT_ARRAY) 0x[[#%x,INIT_ARRAY:]] +## Read the dynamic relocation from 1st entry of .init_array +# CHECK-INIT-ARRAY-NO-EP: Relocation section '.rela.dyn' at offset {{.*}} contains {{.*}} entries +# CHECK-INIT-ARRAY-NO-EP: {{0+}}[[#%x,INIT_ARRAY]] {{.*}} R_AARCH64_RELATIVE [[#%x,INIT_ADDR:]] +# CHECK-INIT-ARRAY-NO-EP-NOT: {{0+}}[[#%x,INIT_ARRAY]] {{.*}} R_AARCH64_RELATIVE [[#%x,INIT]] +## Check that 1st entry of .init_array points to __bolt_runtime_start +# CHECK-INIT-ARRAY-NO-EP: Symbol table '.symtab' contains {{.*}} entries: +# CHECK-INIT-ARRAY-NO-EP-DAG: {{0+}}[[#%x, EP_ADDR]] {{.*}} _start +# CHECK-INIT-ARRAY-NO-EP-DAG: {{[0-9]]*}}: {{0+}}[[#%x, INIT_ADDR]] {{.*}} __bolt_runtime_start + +## Check that entry point address is set to __bolt_runtime_start for PIE executable without DT_INIT +# CHECK-NO-INIT-EP: ELF Header: +# CHECK-NO-INIT-EP: Entry point address: 0x[[#%x,EP_ADDR:]] +## Check that the dynamic relocation at .init and .init_array were not patched +# CHECK-NO-INIT-EP: Dynamic section at offset {{.*}} contains {{.*}} entries: +# CHECK-NO-INIT-EP-NOT: (INIT) 0x[[#%x, EP_ADDR]] +# CHECK-NO-INIT-EP-NOT: (INIT_ARRAY) 0x[[#%x, EP_ADDR]] +## Check that the new entry point address points to __bolt_runtime_start +# CHECK-NO-INIT-EP: Symbol table '.symtab' contains {{.*}} entries: +# CHECK-NO-INIT-EP: {{0+}}[[#%x, EP_ADDR]] {{.*}} __bolt_runtime_start + +## Check that DT_INIT is set to __bolt_runtime_start for shared library with DT_INIT +# CHECK-SHARED-INIT: Dynamic section at offset {{.*}} contains {{.*}} entries: +# CHECK-SHARED-INIT-DAG: (INIT) 0x[[#%x, INIT:]] +# CHECK-SHARED-INIT-DAG: (INIT_ARRAY) 0x[[#%x, INIT_ARRAY:]] +## Check that the dynamic relocation at .init_array was not patched +# CHECK-SHARED-INIT: Relocation section '.rela.dyn' at offset {{.*}} contains {{.*}} entries +# CHECK-SHARED-INIT-NOT: {{0+}}[[#%x, INIT_ARRAY]] {{.*}} R_AARCH64_ABS64 {{0+}}[[#%x, INIT]] +## Check that dynamic section DT_INIT points to __bolt_runtime_start +# CHECK-SHARED-INIT: Symbol table '.symtab' contains {{.*}} entries: +# CHECK-SHARED-INIT: {{0+}}[[#%x, INIT]] {{.*}} __bolt_runtime_start + +## Check that entry point address is set to __bolt_runtime_start for PIE executable without DT_INIT +# CHECK-NO-INIT-NO-EP: ELF Header: +# CHECK-NO-INIT-NO-EP: Entry point address: 0x[[#%x,EP_ADDR:]] +# CHECK-NO-INIT-NO-EP: Dynamic section at offset {{.*}} contains {{.*}} entries: +# CHECK-NO-INIT-NO-EP-NOT: (INIT) +# CHECK-NO-INIT-NO-EP: (INIT_ARRAY) 0x[[#%x,INIT_ARRAY:]] +## Read the dynamic relocation from 1st entry of .init_array +# CHECK-NO-INIT-NO-EP: Relocation section '.rela.dyn' at offset {{.*}} contains {{.*}} entries +# CHECK-NO-INIT-NO-EP: {{0+}}[[#%x,INIT_ARRAY]] {{.*}} R_AARCH64_RELATIVE [[#%x,INIT_ADDR:]] +## Check that 1st entry of .init_array points to __bolt_runtime_start +# CHECK-NO-INIT-NO-EP: Symbol table '.symtab' contains {{.*}} entries: +# CHECK-NO-INIT-NO-EP-DAG: {{0+}}[[#%x, EP_ADDR]] {{.*}} _start +# CHECK-NO-INIT-NO-EP-DAG: {{[0-9]]*}}: {{0+}}[[#%x, INIT_ADDR]] {{.*}} __bolt_runtime_start + +## Check that entry point address is set to __bolt_runtime_start for shared library without DT_INIT +# CHECK-SHARED-NO-INIT: Dynamic section at offset {{.*}} contains {{.*}} entries: +# CHECK-SHARED-NO-INIT-NOT: (INIT) +# CHECK-SHARED-NO-INIT: (INIT_ARRAY) 0x[[#%x,INIT_ARRAY:]] +## Read the dynamic relocation from 1st entry of .init_array +# CHECK-SHARED-NO-INIT: Relocation section '.rela.dyn' at offset {{.*}} contains {{.*}} entries +# CHECK-SHARED-NO-INIT: {{0+}}[[#%x, INIT_ARRAY]] {{.*}} R_AARCH64_ABS64 [[#%x,INIT_ADDR:]] +## Check that 1st entry of .init_array points to __bolt_runtime_start +# CHECK-SHARED-NO-INIT: Symbol table '.symtab' contains {{.*}} entries: +# CHECK-SHARED-NO-INIT: {{[0-9]]*}}: {{0+}}[[#%x, INIT_ADDR]] {{.*}} __bolt_runtime_start + +## Check that entry point address is set to __bolt_runtime_start for non-PIE executable with DT_INIT +# CHECK-NO-PIE-NO-INIT-EP: ELF Header: +# CHECK-NO-PIE-NO-INIT-EP: Entry point address: 0x[[#%x,EP_ADDR:]] +## Check that the dynamic relocation at .init and .init_array were not patched +# CHECK-NO-PIE-NO-INIT-EP: Dynamic section at offset {{.*}} contains {{.*}} entries: +# CHECK-NO-PIE-NO-INIT-EP-NOT: (INIT) 0x[[#%x, EP_ADDR]] +# CHECK-NO-PIE-NO-INIT-EP-NOT: (INIT_ARRAY) 0x[[#%x, EP_ADDR]] +## Check that the new entry point address points to __bolt_runtime_start +# CHECK-NO-PIE-NO-INIT-EP: Symbol table '.symtab' contains {{.*}} entries: +# CHECK-NO-PIE-NO-INIT-EP: {{0+}}[[#%x, EP_ADDR]] {{.*}} __bolt_runtime_start + + .globl _start + .type _start, %function +_start: + # Dummy relocation to force relocation mode. + .reloc 0, R_AARCH64_NONE + ret +.size _start, .-_start + + .globl _init + .type _init, %function +_init: + ret + .size _init, .-_init + + .globl _fini + .type _fini, %function +_fini: + ret + .size _fini, .-_fini + + .section .init_array,"aw" + .align 3 + .dword _init + + .section .fini_array,"aw" + .align 3 + .dword _fini From 857fec8635ef541cba7aa3f9ed5a69cde1cfded9 Mon Sep 17 00:00:00 2001 From: Vasily Leonenko Date: Mon, 10 Nov 2025 00:43:29 +0300 Subject: [PATCH 3/6] [BOLT][test] Fix instrumentation tests for X86 (add .init entries) --- bolt/test/X86/internal-call-instrument-so.s | 9 ++++++++- bolt/test/runtime/X86/instrument-wrong-target.s | 7 +++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/bolt/test/X86/internal-call-instrument-so.s b/bolt/test/X86/internal-call-instrument-so.s index 99e5b29221409..fe23bc61afa32 100644 --- a/bolt/test/X86/internal-call-instrument-so.s +++ b/bolt/test/X86/internal-call-instrument-so.s @@ -5,7 +5,7 @@ # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o # Delete our BB symbols so BOLT doesn't mark them as entry points # RUN: llvm-strip --strip-unneeded %t.o -# RUN: ld.lld %t.o -o %t.exe -q -shared -fini=_fini +# RUN: ld.lld %t.o -o %t.exe -q -shared -fini=_fini -init=_init # RUN: llvm-bolt --instrument %t.exe --relocs -o %t.out .text @@ -48,6 +48,13 @@ _fini: hlt .size _fini, .-_fini + .globl _init + .type _init, %function + .p2align 4 +_init: + retq + .size _init, .-_init + .data .globl var var: diff --git a/bolt/test/runtime/X86/instrument-wrong-target.s b/bolt/test/runtime/X86/instrument-wrong-target.s index 343d93a89ed13..fa40d43f10a0f 100644 --- a/bolt/test/runtime/X86/instrument-wrong-target.s +++ b/bolt/test/runtime/X86/instrument-wrong-target.s @@ -19,6 +19,13 @@ _start: ret .size _start, .-_start + .globl _init + .type _init, %function + # Force DT_INIT to be created (needed for instrumentation). +_init: + ret + .size _init, .-_init + .globl _fini .type _fini, %function # Force DT_FINI to be created (needed for instrumentation). From 1c199be0e53e7073ae81510cae7f8aa922e21205 Mon Sep 17 00:00:00 2001 From: Vasily Leonenko Date: Wed, 12 Nov 2025 10:26:16 -0500 Subject: [PATCH 4/6] [BOLT] Don't fail if instrumentation-sleep-time>0 and input binary don't have fini & fini_array --- bolt/lib/Rewrite/RewriteInstance.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index d356d5c3f97db..428ba8b623de4 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -80,6 +80,7 @@ namespace opts { extern cl::list HotTextMoveSections; extern cl::opt Hugify; extern cl::opt Instrument; +extern cl::opt InstrumentationSleepTime; extern cl::opt KeepNops; extern cl::opt Lite; extern cl::list PrintOnly; @@ -1501,6 +1502,10 @@ Error RewriteInstance::discoverRtFiniAddress() { } if (!BC->FiniArrayAddress || !BC->FiniArraySize) { + // It is still possible to generate profile without fini hook if + // InstrumentationSleepTime is set + if (opts::InstrumentationSleepTime > 0) + return Error::success(); return createStringError( std::errc::not_supported, "Instrumentation needs either DT_FINI or DT_FINI_ARRAY"); @@ -1601,6 +1606,13 @@ void RewriteInstance::updateRtFiniReloc() { if (!RT || !RT->getRuntimeFiniAddress()) return; + // It is still possible to generate profile without fini hook if + // InstrumentationSleepTime is set + if ((!BC->FiniArrayAddress || !BC->FiniArraySize) && + opts::InstrumentationSleepTime > 0) { + return; + } + assert(BC->FiniArrayAddress && BC->FiniArraySize && "inconsistent .fini_array state"); From fb200c50878e89e18656423e3e133b08024f1d81 Mon Sep 17 00:00:00 2001 From: Vasily Leonenko Date: Wed, 12 Nov 2025 07:31:10 -0500 Subject: [PATCH 5/6] [BOLT] Update updateRtFiniReloc to return error instead of assertions --- bolt/include/bolt/Rewrite/RewriteInstance.h | 2 +- bolt/lib/Rewrite/RewriteInstance.cpp | 25 ++++++++++++--------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h index 6b2a0143bbc42..5950b3c1630e1 100644 --- a/bolt/include/bolt/Rewrite/RewriteInstance.h +++ b/bolt/include/bolt/Rewrite/RewriteInstance.h @@ -109,7 +109,7 @@ class RewriteInstance { /// If DT_FINI_ARRAY is used for instrumentation, update the relocation of its /// first entry to point to the instrumentation library's fini address. - void updateRtFiniReloc(); + Error updateRtFiniReloc(); /// Create and initialize metadata rewriters for this instance. void initializeMetadataManager(); diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 428ba8b623de4..9f41d37493e17 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -814,7 +814,8 @@ Error RewriteInstance::run() { if (opts::Instrument && !BC->IsStaticExecutable) { if (Error E = updateRtInitReloc()) return E; - updateRtFiniReloc(); + if (Error E = updateRtFiniReloc()) + return E; } if (opts::OutputFilename == "/dev/null") { @@ -1597,33 +1598,36 @@ Error RewriteInstance::updateRtInitReloc() { return Error::success(); } -void RewriteInstance::updateRtFiniReloc() { +Error RewriteInstance::updateRtFiniReloc() { // Updating DT_FINI is handled by patchELFDynamic. if (BC->FiniAddress) - return; + return Error::success(); const RuntimeLibrary *RT = BC->getRuntimeLibrary(); if (!RT || !RT->getRuntimeFiniAddress()) - return; + return Error::success(); // It is still possible to generate profile without fini hook if // InstrumentationSleepTime is set if ((!BC->FiniArrayAddress || !BC->FiniArraySize) && opts::InstrumentationSleepTime > 0) { - return; + return Error::success(); } - assert(BC->FiniArrayAddress && BC->FiniArraySize && - "inconsistent .fini_array state"); + if (!BC->FiniArrayAddress || !BC->FiniArraySize) + return createStringError(std::errc::not_supported, + "inconsistent .fini_array state"); ErrorOr FiniArraySection = BC->getSectionForAddress(*BC->FiniArrayAddress); - assert(FiniArraySection && ".fini_array removed"); + if (!FiniArraySection) + return createStringError(std::errc::not_supported, ".fini_array removed"); if (std::optional Reloc = FiniArraySection->takeDynamicRelocationAt(0)) { - assert(Reloc->Addend == BC->FiniFunctionAddress && - "inconsistent .fini_array dynamic relocation"); + if (Reloc->Addend != BC->FiniFunctionAddress) + return createStringError(std::errc::not_supported, + "inconsistent .fini_array dynamic relocation"); Reloc->Addend = RT->getRuntimeFiniAddress(); FiniArraySection->addDynamicRelocation(*Reloc); } @@ -1636,6 +1640,7 @@ void RewriteInstance::updateRtFiniReloc() { FiniArraySection->addPendingRelocation(Relocation{ /*Offset*/ 0, /*Symbol*/ nullptr, /*Type*/ Relocation::getAbs64(), /*Addend*/ RT->getRuntimeFiniAddress(), /*Value*/ 0}); + return Error::success(); } void RewriteInstance::registerFragments() { From 3ec1e51866b672d6bd8dc9983ebd8a1207ca6dff Mon Sep 17 00:00:00 2001 From: Vasily Leonenko Date: Wed, 19 Nov 2025 21:48:03 +0300 Subject: [PATCH 6/6] [BOLT] Print information about hooking methods for runtime library init/fini Also extend AArch64 hook-init & hook-fini tests with corresponding bolt output checks. --- bolt/lib/Rewrite/RewriteInstance.cpp | 24 ++++++++++++++++----- bolt/test/AArch64/hook-fini.s | 14 ++++++++++--- bolt/test/AArch64/hook-init.s | 31 +++++++++++++++++++++------- 3 files changed, 53 insertions(+), 16 deletions(-) diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 9f41d37493e17..4387a06e87dba 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -1595,6 +1595,9 @@ Error RewriteInstance::updateRtInitReloc() { InitArraySection->addPendingRelocation(Relocation{ /*Offset*/ 0, /*Symbol*/ nullptr, /*Type*/ Relocation::getAbs64(), /*Addend*/ RT->getRuntimeStartAddress(), /*Value*/ 0}); + outs() << "BOLT-INFO: Runtime library initialization was hooked via 1st " + "entry of .init_array, set to " + << Twine::utohexstr(RT->getRuntimeStartAddress()) << "\n"; return Error::success(); } @@ -1640,6 +1643,9 @@ Error RewriteInstance::updateRtFiniReloc() { FiniArraySection->addPendingRelocation(Relocation{ /*Offset*/ 0, /*Symbol*/ nullptr, /*Type*/ Relocation::getAbs64(), /*Addend*/ RT->getRuntimeFiniAddress(), /*Value*/ 0}); + outs() << "BOLT-INFO: Runtime library finalization was hooked via 1st entry " + "of .fini_array, set to " + << Twine::utohexstr(RT->getRuntimeFiniAddress()) << "\n"; return Error::success(); } @@ -5011,9 +5017,12 @@ void RewriteInstance::patchELFSectionHeaderTable(ELFObjectFile *File) { if (BC->HasRelocations) { RuntimeLibrary *RtLibrary = BC->getRuntimeLibrary(); - if (RtLibrary && opts::RuntimeLibInitHook == opts::RLIH_ENTRY_POINT) + if (RtLibrary && opts::RuntimeLibInitHook == opts::RLIH_ENTRY_POINT) { NewEhdr.e_entry = RtLibrary->getRuntimeStartAddress(); - else + outs() << "BOLT-INFO: Runtime library initialization was hooked via ELF " + "Header Entry Point, set to " + << Twine::utohexstr(NewEhdr.e_entry) << "\n"; + } else NewEhdr.e_entry = getNewFunctionAddress(NewEhdr.e_entry); assert((NewEhdr.e_entry || !Obj.getHeader().e_entry) && "cannot find new address for entry point"); @@ -5854,16 +5863,21 @@ void RewriteInstance::patchELFDynamic(ELFObjectFile *File) { } RuntimeLibrary *RtLibrary = BC->getRuntimeLibrary(); if (RtLibrary && Dyn.getTag() == ELF::DT_FINI) { - if (uint64_t Addr = RtLibrary->getRuntimeFiniAddress()) + if (uint64_t Addr = RtLibrary->getRuntimeFiniAddress()) { NewDE.d_un.d_ptr = Addr; + outs() << "BOLT-INFO: Runtime library finalization was hooked via " + "DT_FINI, set to " + << Twine::utohexstr(Addr) << "\n"; + } } if (RtLibrary && Dyn.getTag() == ELF::DT_INIT && (!BC->HasInterpHeader || opts::RuntimeLibInitHook == opts::RLIH_INIT)) { if (auto Addr = RtLibrary->getRuntimeStartAddress()) { - LLVM_DEBUG(dbgs() << "BOLT-DEBUG: Set DT_INIT to 0x" - << Twine::utohexstr(Addr) << '\n'); NewDE.d_un.d_ptr = Addr; + outs() << "BOLT-INFO: Runtime library initialization was hooked via " + "DT_INIT, set to " + << Twine::utohexstr(Addr) << "\n"; } } break; diff --git a/bolt/test/AArch64/hook-fini.s b/bolt/test/AArch64/hook-fini.s index 4f321d463ef32..4f929674bd5e0 100644 --- a/bolt/test/AArch64/hook-fini.s +++ b/bolt/test/AArch64/hook-fini.s @@ -15,13 +15,13 @@ # RUN: %clang %cflags -pie %s -Wl,-q -o %t.exe # RUN: llvm-readelf -d %t.exe | FileCheck --check-prefix=DYN-FINI %s # RUN: llvm-readelf -r %t.exe | FileCheck --check-prefix=RELOC-PIE %s -# RUN: llvm-bolt %t.exe -o %t --instrument +# RUN: llvm-bolt %t.exe -o %t --instrument | FileCheck --check-prefix=CHECK-BOLT-RT-FINI %s # RUN: llvm-readelf -drs %t | FileCheck --check-prefix=CHECK-FINI %s # RUN: %clang %cflags -pie %s -Wl,-q,-fini=0 -o %t-no-fini.exe # RUN: llvm-readelf -d %t-no-fini.exe | FileCheck --check-prefix=DYN-NO-FINI %s # RUN: llvm-readelf -r %t-no-fini.exe | FileCheck --check-prefix=RELOC-PIE %s -# RUN: llvm-bolt %t-no-fini.exe -o %t-no-fini --instrument +# RUN: llvm-bolt %t-no-fini.exe -o %t-no-fini --instrument | FileCheck --check-prefix=CHECK-BOLT-RT-FINI-ARRAY %s # RUN: llvm-readelf -drs %t-no-fini | FileCheck --check-prefix=CHECK-NO-FINI %s # RUN: llvm-readelf -ds -x .fini_array %t-no-fini | FileCheck --check-prefix=CHECK-NO-FINI-RELOC %s @@ -29,7 +29,7 @@ # RUN: %clang %cflags %p/../Inputs/stub.c -fPIC -shared -o %t-stub.so # RUN: %clang %cflags %s -no-pie -Wl,-q,-fini=0 %t-stub.so -o %t-no-pie-no-fini.exe # RUN: llvm-readelf -r %t-no-pie-no-fini.exe | FileCheck --check-prefix=RELOC-NO-PIE %s -# RUN: llvm-bolt %t-no-pie-no-fini.exe -o %t-no-pie-no-fini --instrument +# RUN: llvm-bolt %t-no-pie-no-fini.exe -o %t-no-pie-no-fini --instrument | FileCheck --check-prefix=CHECK-BOLT-RT-FINI-ARRAY %s # RUN: llvm-readelf -ds -x .fini_array %t-no-pie-no-fini | FileCheck --check-prefix=CHECK-NO-PIE-NO-FINI %s ## With fini: dynamic section should contain DT_FINI @@ -46,6 +46,14 @@ ## Without PIE: binary should not have relative relocations # RELOC-NO-PIE-NOT: R_AARCH64_RELATIVE +## Check BOLT output output finalization hook (DT_FINI) +# CHECK-BOLT-RT-FINI: Runtime library finalization was hooked via DT_FINI +# CHECK-BOLT-RT-FINI-NOT: Runtime library finalization was hooked via 1st entry of .fini_array + +## Check BOLT output output finalization hook (1st entry of .fini_array) +# CHECK-BOLT-RT-FINI-ARRAY-NOT: Runtime library finalization was hooked via DT_FINI +# CHECK-BOLT-RT-FINI-ARRAY: Runtime library finalization was hooked via 1st entry of .fini_array + ## Check that DT_FINI is set to __bolt_runtime_fini # CHECK-FINI: Dynamic section at offset {{.*}} contains {{.*}} entries: # CHECK-FINI-DAG: (FINI) 0x[[FINI:[[:xdigit:]]+]] diff --git a/bolt/test/AArch64/hook-init.s b/bolt/test/AArch64/hook-init.s index e5b11ecae57cc..27bf783479167 100644 --- a/bolt/test/AArch64/hook-init.s +++ b/bolt/test/AArch64/hook-init.s @@ -18,41 +18,41 @@ # RUN: llvm-readelf -d %t.exe | FileCheck --check-prefix=DYN-INIT %s # RUN: llvm-readelf -l %t.exe | FileCheck --check-prefix=PH-INTERP %s # RUN: llvm-readelf -r %t.exe | FileCheck --check-prefix=RELOC-PIE %s -# RUN: llvm-bolt %t.exe -o %t --instrument +# RUN: llvm-bolt %t.exe -o %t --instrument | FileCheck --check-prefix=CHECK-BOLT-RT-EP %s # RUN: llvm-readelf -hdrs %t | FileCheck --check-prefix=CHECK-INIT-EP %s -# RUN: llvm-bolt %t.exe -o %t-no-ep --instrument --runtime-lib-init-hook=init +# RUN: llvm-bolt %t.exe -o %t-no-ep --instrument --runtime-lib-init-hook=init | FileCheck --check-prefix=CHECK-BOLT-RT-INIT %s # RUN: llvm-readelf -hdrs %t-no-ep | FileCheck --check-prefix=CHECK-INIT-NO-EP %s -# RUN: llvm-bolt %t.exe -o %t-no-ep --instrument --runtime-lib-init-hook=init_array +# RUN: llvm-bolt %t.exe -o %t-no-ep --instrument --runtime-lib-init-hook=init_array | FileCheck --check-prefix=CHECK-BOLT-RT-INIT-ARRAY %s # RUN: llvm-readelf -hdrs %t-no-ep | FileCheck --check-prefix=CHECK-INIT-ARRAY-NO-EP %s # RUN: %clang -shared %cflags -pie %s -Wl,-q -o %t-shared.exe # RUN: llvm-readelf -d %t-shared.exe | FileCheck --check-prefix=DYN-INIT %s # RUN: llvm-readelf -l %t-shared.exe | FileCheck --check-prefix=PH-INTERP-SHARED %s # RUN: llvm-readelf -r %t-shared.exe | FileCheck --check-prefix=RELOC-SHARED-PIE %s -# RUN: llvm-bolt %t-shared.exe -o %t-shared --instrument +# RUN: llvm-bolt %t-shared.exe -o %t-shared --instrument | FileCheck --check-prefix=CHECK-BOLT-RT-INIT %s # RUN: llvm-readelf -hdrs %t-shared | FileCheck --check-prefix=CHECK-SHARED-INIT %s # RUN: %clang %cflags -pie %s -Wl,-q,-init=0 -o %t-no-init.exe # RUN: llvm-readelf -d %t-no-init.exe | FileCheck --check-prefix=DYN-NO-INIT %s # RUN: llvm-readelf -l %t-no-init.exe | FileCheck --check-prefix=PH-INTERP %s # RUN: llvm-readelf -r %t-no-init.exe | FileCheck --check-prefix=RELOC-PIE %s -# RUN: llvm-bolt %t-no-init.exe -o %t-no-init --instrument +# RUN: llvm-bolt %t-no-init.exe -o %t-no-init --instrument | FileCheck --check-prefix=CHECK-BOLT-RT-EP %s # RUN: llvm-readelf -hdrs %t-no-init | FileCheck --check-prefix=CHECK-NO-INIT-EP %s -# RUN: llvm-bolt %t-no-init.exe -o %t-no-init-no-ep --instrument --runtime-lib-init-hook=init +# RUN: llvm-bolt %t-no-init.exe -o %t-no-init-no-ep --instrument --runtime-lib-init-hook=init | FileCheck --check-prefix=CHECK-BOLT-RT-INIT-ARRAY %s # RUN: llvm-readelf -hdrs %t-no-init-no-ep | FileCheck --check-prefix=CHECK-NO-INIT-NO-EP %s # RUN: %clang -shared %cflags -pie %s -Wl,-q,-init=0 -o %t-shared-no-init.exe # RUN: llvm-readelf -d %t-shared-no-init.exe | FileCheck --check-prefix=DYN-NO-INIT %s # RUN: llvm-readelf -l %t-shared-no-init.exe | FileCheck --check-prefix=PH-INTERP-SHARED %s # RUN: llvm-readelf -r %t-shared-no-init.exe | FileCheck --check-prefix=RELOC-SHARED-PIE %s -# RUN: llvm-bolt %t-shared-no-init.exe -o %t-shared-no-init --instrument +# RUN: llvm-bolt %t-shared-no-init.exe -o %t-shared-no-init --instrument | FileCheck --check-prefix=CHECK-BOLT-RT-INIT-ARRAY %s # RUN: llvm-readelf -drs %t-shared-no-init | FileCheck --check-prefix=CHECK-SHARED-NO-INIT %s ## Create a dummy shared library to link against to force creation of the dynamic section. # RUN: %clang %cflags %p/../Inputs/stub.c -fPIC -shared -o %t-stub.so # RUN: %clang %cflags %s -no-pie -Wl,-q,-init=0 %t-stub.so -o %t-no-pie-no-init.exe # RUN: llvm-readelf -r %t-no-pie-no-init.exe | FileCheck --check-prefix=RELOC-NO-PIE %s -# RUN: llvm-bolt %t-no-pie-no-init.exe -o %t-no-pie-no-init --instrument +# RUN: llvm-bolt %t-no-pie-no-init.exe -o %t-no-pie-no-init --instrument | FileCheck --check-prefix=CHECK-BOLT-RT-EP %s # RUN: llvm-readelf -hds %t-no-pie-no-init | FileCheck --check-prefix=CHECK-NO-PIE-NO-INIT-EP %s ## With init: dynamic section should contain DT_INIT @@ -80,6 +80,21 @@ ## Without PIE: binary should not have relative relocations # RELOC-NO-PIE-NOT: R_AARCH64_RELATIVE +## Check BOLT output output initialization hook (ELF Header Entry Point) +# CHECK-BOLT-RT-EP: Runtime library initialization was hooked via ELF Header Entry Point +# CHECK-BOLT-RT-EP-NOT: Runtime library initialization was hooked via DT_INIT +# CHECK-BOLT-RT-EP-NOT: Runtime library initialization was hooked via 1st entry of .init_array + +## Check BOLT output output initialization hook (DT_INIT) +# CHECK-BOLT-RT-INIT-NOT: Runtime library initialization was hooked via ELF Header Entry Point +# CHECK-BOLT-RT-INIT: Runtime library initialization was hooked via DT_INIT +# CHECK-BOLT-RT-INIT-NOT: Runtime library initialization was hooked via 1st entry of .init_array + +## Check BOLT output output initialization hook (1st entry of .init_array) +# CHECK-BOLT-RT-INIT-ARRAY-NOT: Runtime library initialization was hooked via ELF Header Entry Point +# CHECK-BOLT-RT-INIT-ARRAY-NOT: Runtime library initialization was hooked via DT_INIT +# CHECK-BOLT-RT-INIT-ARRAY: Runtime library initialization was hooked via 1st entry of .init_array + ## Check that entry point address is set to __bolt_runtime_start for PIE executable with DT_INIT # CHECK-INIT-EP: ELF Header: # CHECK-INIT-EP: Entry point address: 0x[[#%x,EP_ADDR:]]