From f6f1974b3a8a739e68c1d5fd2962fc4124753b7c Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Thu, 13 Nov 2025 17:25:22 -0800 Subject: [PATCH 1/3] [compiler-rt] Add baremetal version of profile library. Adds a flag COMPILER_RT_PROFILE_BAREMETAL, which disables the parts of the profile runtime which require a filesystem or malloc. This minimal library only requires string.h from the C library. This is useful for profiling or code coverage of baremetal images, which don't have filesystem APIs, and might not have malloc configured (or have limited heap space). There's some room for improvement here in the future for doing profiling and code coverage for baremetal. If we revised the profiling format, and introduced some additional host tooling, we could move some of the metadata into non-allocated sections, and construct the profraw file on the host. But this patch is sufficient for some use-cases. --- compiler-rt/CMakeLists.txt | 2 ++ compiler-rt/lib/profile/CMakeLists.txt | 28 +++++++++++++++---- compiler-rt/lib/profile/InstrProfiling.c | 2 -- compiler-rt/lib/profile/InstrProfiling.h | 5 ++++ compiler-rt/lib/profile/InstrProfilingMerge.c | 3 +- .../lib/profile/InstrProfilingMergeFile.c | 1 - .../lib/profile/InstrProfilingPlatformLinux.c | 5 +++- .../lib/profile/InstrProfilingPlatformOther.c | 3 +- compiler-rt/lib/profile/InstrProfilingPort.h | 12 ++------ 9 files changed, 40 insertions(+), 21 deletions(-) diff --git a/compiler-rt/CMakeLists.txt b/compiler-rt/CMakeLists.txt index 1ed4e66d5622f..66fe9c6563230 100644 --- a/compiler-rt/CMakeLists.txt +++ b/compiler-rt/CMakeLists.txt @@ -309,6 +309,8 @@ option(COMPILER_RT_USE_BUILTINS_LIBRARY option(COMPILER_RT_USE_ATOMIC_LIBRARY "Use compiler-rt atomic instead of libatomic" OFF) +option(COMPILER_RT_PROFILE_BAREMETAL "Build minimal baremetal profile library" OFF) + include(config-ix) #================================ diff --git a/compiler-rt/lib/profile/CMakeLists.txt b/compiler-rt/lib/profile/CMakeLists.txt index a6402f80b890a..7795e7399f493 100644 --- a/compiler-rt/lib/profile/CMakeLists.txt +++ b/compiler-rt/lib/profile/CMakeLists.txt @@ -60,12 +60,9 @@ int main() { add_compiler_rt_component(profile) set(PROFILE_SOURCES - GCDAProfiling.c InstrProfiling.c InstrProfilingInternal.c - InstrProfilingValue.c InstrProfilingBuffer.c - InstrProfilingFile.c InstrProfilingMerge.c InstrProfilingMergeFile.c InstrProfilingNameVar.c @@ -77,10 +74,25 @@ set(PROFILE_SOURCES InstrProfilingPlatformLinux.c InstrProfilingPlatformOther.c InstrProfilingPlatformWindows.c - InstrProfilingRuntime.cpp - InstrProfilingUtil.c ) +if (NOT COMPILER_RT_PROFILE_BAREMETAL) + # For baremetal, exclude the following: + # - Anything that contains filesystem operations (InstrProfilingFile.c, + # InstrProfilingUtils.c) + # - Initialization, because it isn't necesary without the filesystem bits + # on ELF targets (InstrProfilingRuntime.cpp). + # - Value profiling, because it requires malloc (InstrProfilingValue.c). + # This could be optional if someone needs it. + # - GCDA profiling, which is unrelated (GCDAProfiling.c) + list(APPEND PROFILE_SOURCES GCDAProfiling.c + InstrProfilingFile.c + InstrProfilingRuntime.cpp + InstrProfilingUtil.c + InstrProfilingValue.c + ) +endif() + set(PROFILE_HEADERS InstrProfiling.h InstrProfilingInternal.h @@ -135,6 +147,12 @@ if(COMPILER_RT_TARGET_HAS_UNAME) -DCOMPILER_RT_HAS_UNAME=1) endif() +if(COMPILER_RT_PROFILE_BAREMETAL) + set(EXTRA_FLAGS + ${EXTRA_FLAGS} + -DCOMPILER_RT_PROFILE_BAREMETAL=1) +endif() + if(MSVC) # profile historically has only been supported with the static runtime # on windows diff --git a/compiler-rt/lib/profile/InstrProfiling.c b/compiler-rt/lib/profile/InstrProfiling.c index da04d8ebdec95..d59ec78ad3296 100644 --- a/compiler-rt/lib/profile/InstrProfiling.c +++ b/compiler-rt/lib/profile/InstrProfiling.c @@ -10,8 +10,6 @@ // with freestanding compilation. See `darwin_add_builtin_libraries`. #include -#include -#include #include #include "InstrProfiling.h" diff --git a/compiler-rt/lib/profile/InstrProfiling.h b/compiler-rt/lib/profile/InstrProfiling.h index 8791d5aa5dd70..187ef55ef3784 100644 --- a/compiler-rt/lib/profile/InstrProfiling.h +++ b/compiler-rt/lib/profile/InstrProfiling.h @@ -10,7 +10,10 @@ #define PROFILE_INSTRPROFILING_H_ #include "InstrProfilingPort.h" +#include +#ifndef COMPILER_RT_PROFILE_BAREMETAL #include +#endif // Make sure __LLVM_INSTR_PROFILE_GENERATE is always defined before // including instr_prof_interface.h so the interface functions are @@ -200,7 +203,9 @@ int __llvm_profile_write_file(void); * copying the old profile file to new profile file and this function is usually * used when the proess doesn't have permission to open file. */ +#ifndef COMPILER_RT_PROFILE_BAREMETAL int __llvm_profile_set_file_object(FILE *File, int EnableMerge); +#endif /*! \brief Register to write instrumentation data to file at exit. */ int __llvm_profile_register_write_file_atexit(void); diff --git a/compiler-rt/lib/profile/InstrProfilingMerge.c b/compiler-rt/lib/profile/InstrProfilingMerge.c index 92721c4fd55ea..9b84b512ad9c7 100644 --- a/compiler-rt/lib/profile/InstrProfilingMerge.c +++ b/compiler-rt/lib/profile/InstrProfilingMerge.c @@ -11,7 +11,6 @@ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" -#include "InstrProfilingUtil.h" #define INSTR_PROF_VALUE_PROF_DATA #include "profile/InstrProfData.inc" @@ -131,9 +130,11 @@ COMPILER_RT_VISIBILITY int __llvm_profile_merge_from_buffer(const char *ProfileData, uint64_t ProfileSize) { if (__llvm_profile_get_version() & VARIANT_MASK_TEMPORAL_PROF) { +#ifndef COMPILER_RT_PROFILE_BAREMETAL PROF_ERR("%s\n", "Temporal profiles do not support profile merging at runtime. " "Instead, merge raw profiles using the llvm-profdata tool."); +#endif return 1; } diff --git a/compiler-rt/lib/profile/InstrProfilingMergeFile.c b/compiler-rt/lib/profile/InstrProfilingMergeFile.c index 8923ba21cc580..d8fe1f6677950 100644 --- a/compiler-rt/lib/profile/InstrProfilingMergeFile.c +++ b/compiler-rt/lib/profile/InstrProfilingMergeFile.c @@ -13,7 +13,6 @@ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" -#include "InstrProfilingUtil.h" #define INSTR_PROF_VALUE_PROF_DATA #include "profile/InstrProfData.inc" diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c b/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c index 558b7fc8cad62..650dbbcb0a665 100644 --- a/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c +++ b/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c @@ -8,14 +8,17 @@ #if defined(__linux__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \ (defined(__sun__) && defined(__svr4__)) || defined(__NetBSD__) || \ - defined(_AIX) || defined(__wasm__) || defined(__HAIKU__) + defined(_AIX) || defined(__wasm__) || defined(__HAIKU__) || \ + defined(COMPILER_RT_PROFILE_BAREMETAL) +#ifndef COMPILER_RT_PROFILE_BAREMETAL #if !defined(_AIX) && !defined(__wasm__) #include #include #endif #include #include +#endif #include "InstrProfiling.h" #include "InstrProfilingInternal.h" diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformOther.c b/compiler-rt/lib/profile/InstrProfilingPlatformOther.c index 19414ab78b3be..bedf934af29b6 100644 --- a/compiler-rt/lib/profile/InstrProfilingPlatformOther.c +++ b/compiler-rt/lib/profile/InstrProfilingPlatformOther.c @@ -9,7 +9,8 @@ #if !defined(__APPLE__) && !defined(__linux__) && !defined(__FreeBSD__) && \ !defined(__Fuchsia__) && !(defined(__sun__) && defined(__svr4__)) && \ !defined(__NetBSD__) && !defined(_WIN32) && !defined(_AIX) && \ - !defined(__wasm__) && !defined(__HAIKU__) + !defined(__wasm__) && !defined(__HAIKU__) && \ + !defined(COMPILER_RT_PROFILE_BAREMETAL) #include #include diff --git a/compiler-rt/lib/profile/InstrProfilingPort.h b/compiler-rt/lib/profile/InstrProfilingPort.h index 66d697885eaee..151ed94007413 100644 --- a/compiler-rt/lib/profile/InstrProfilingPort.h +++ b/compiler-rt/lib/profile/InstrProfilingPort.h @@ -117,7 +117,9 @@ static inline size_t getpagesize(void) { return S.dwPageSize; } #else /* defined(_WIN32) */ +#ifndef COMPILER_RT_PROFILE_BAREMETAL #include +#endif #endif /* defined(_WIN32) */ #define PROF_ERR(Format, ...) \ @@ -137,16 +139,6 @@ static inline size_t getpagesize(void) { #define O_BINARY 0 #endif -#if defined(__FreeBSD__) - -#include -#include - -#else /* defined(__FreeBSD__) */ - -#include #include -#endif /* defined(__FreeBSD__) && defined(__i386__) */ - #endif /* PROFILE_INSTRPROFILING_PORT_H_ */ From 5e6f4b3042862373519de296882820941e9e47f0 Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Mon, 17 Nov 2025 15:41:38 -0800 Subject: [PATCH 2/3] Add comments explaining the different profile files. Also adjust ifdef to be a bit more clear. --- .../lib/profile/InstrProfilingPlatformLinux.c | 20 ++++++++++++++++--- .../lib/profile/InstrProfilingPlatformOther.c | 7 +++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c b/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c index 650dbbcb0a665..acdb222004fd4 100644 --- a/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c +++ b/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c @@ -6,16 +6,30 @@ |* \*===----------------------------------------------------------------------===*/ +// This file defines profile data symbols for ELF, wasm, XCOFF. It assumes +// __start_ and __stop_ symbols for profile data point at the beginning and +// end of the sections in question. (This is technically a linker feature, +// not a file format feature, but linkers for these targets support it.) +// +// MachO (MacOS/iOS) and PE-COFF (Windows) have a similar support, but the +// identifiers are different, so the support is in separate files. +// +// Support for targets which don't have linker support is in +// InstrProfilingPlatformOther.c. +// +// This file also contains code to extract ELF build IDs from the ELF file, +// to identify the build which generated the file. + #if defined(__linux__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \ (defined(__sun__) && defined(__svr4__)) || defined(__NetBSD__) || \ defined(_AIX) || defined(__wasm__) || defined(__HAIKU__) || \ defined(COMPILER_RT_PROFILE_BAREMETAL) -#ifndef COMPILER_RT_PROFILE_BAREMETAL -#if !defined(_AIX) && !defined(__wasm__) +#if !defined(_AIX) && !defined(__wasm__) && \ + !defined(COMPILER_RT_PROFILE_BAREMETAL) +// Includes for non-baremetal ELF targets, used to output build IDs. #include #include -#endif #include #include #endif diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformOther.c b/compiler-rt/lib/profile/InstrProfilingPlatformOther.c index bedf934af29b6..f5d1c74f10115 100644 --- a/compiler-rt/lib/profile/InstrProfilingPlatformOther.c +++ b/compiler-rt/lib/profile/InstrProfilingPlatformOther.c @@ -6,6 +6,13 @@ |* \*===----------------------------------------------------------------------===*/ +// This file defines a fallback implementation to compute the locations of +// profile data sections, for targets that don't have linker support. No +// commonly used targets use this codepath. +// +// This implementation expects the compiler instrumentation pass to define a +// constructor in each file which calls into this file. + #if !defined(__APPLE__) && !defined(__linux__) && !defined(__FreeBSD__) && \ !defined(__Fuchsia__) && !(defined(__sun__) && defined(__svr4__)) && \ !defined(__NetBSD__) && !defined(_WIN32) && !defined(_AIX) && \ From d24eab6ca234e7aebf1b4471a4cb42371b855067 Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Wed, 19 Nov 2025 16:52:50 -0800 Subject: [PATCH 3/3] Make sure profile lib builds if CMAKE_SYSTEM_NAME is Generic. --- compiler-rt/cmake/config-ix.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake index 8dfbdecbd6b97..c2d3ed9788b2f 100644 --- a/compiler-rt/cmake/config-ix.cmake +++ b/compiler-rt/cmake/config-ix.cmake @@ -842,7 +842,7 @@ else() endif() if (PROFILE_SUPPORTED_ARCH AND NOT LLVM_USE_SANITIZER AND - OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows|Android|Fuchsia|SunOS|NetBSD|AIX|WASI|Haiku") + (OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows|Android|Fuchsia|SunOS|NetBSD|AIX|WASI|Haiku" OR COMPILER_RT_PROFILE_BAREMETAL)) set(COMPILER_RT_HAS_PROFILE TRUE) else() set(COMPILER_RT_HAS_PROFILE FALSE)