[compiler-rt] [compiler-rt] Add CMake option to enable execute-only code generation on AArch64 (PR #140555)

via llvm-commits llvm-commits at lists.llvm.org
Mon May 19 07:59:08 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-xray

@llvm/pr-subscribers-compiler-rt-sanitizer

Author: Csanád Hajdú (Il-Capitano)

<details>
<summary>Changes</summary>

For a full toolchain supporting execute-only code generation the runtime libraries also need to be pre-compiled with it enabled. For compiler-rt this can now be enabled with the `COMPILER_RT_EXECUTE_ONLY_CODE` CMake option during build configuration.

The build option can only be enabled for a runtimes build of compiler-rt, because a recent version of Clang is needed to correctly compile assembly files with execute-only code support.

Related RFC: https://discourse.llvm.org/t/rfc-execute-only-code-support-for-runtime-libraries-on-aarch64/86180

---
Full diff: https://github.com/llvm/llvm-project/pull/140555.diff


15 Files Affected:

- (modified) compiler-rt/CMakeLists.txt (+20) 
- (modified) compiler-rt/cmake/builtin-config-ix.cmake (+2) 
- (modified) compiler-rt/cmake/config-ix.cmake (+2) 
- (modified) compiler-rt/lib/builtins/CMakeLists.txt (+14-1) 
- (modified) compiler-rt/lib/builtins/assembly.h (+14-1) 
- (modified) compiler-rt/lib/fuzzer/CMakeLists.txt (+3-1) 
- (modified) compiler-rt/lib/hwasan/hwasan_setjmp_aarch64.S (+1-1) 
- (modified) compiler-rt/lib/hwasan/hwasan_tag_mismatch_aarch64.S (+1-1) 
- (modified) compiler-rt/lib/msan/tests/CMakeLists.txt (+2) 
- (modified) compiler-rt/lib/orc/elfnix_tls.aarch64.S (+4) 
- (modified) compiler-rt/lib/orc/sysv_reenter.arm64.S (+4) 
- (modified) compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S (+1) 
- (modified) compiler-rt/lib/tsan/CMakeLists.txt (+2) 
- (modified) compiler-rt/lib/tsan/rtl/tsan_rtl_aarch64.S (+2-4) 
- (modified) compiler-rt/lib/xray/xray_trampoline_AArch64.S (+1-1) 


``````````diff
diff --git a/compiler-rt/CMakeLists.txt b/compiler-rt/CMakeLists.txt
index 9f8e8334d75ba..0e91e419fa373 100644
--- a/compiler-rt/CMakeLists.txt
+++ b/compiler-rt/CMakeLists.txt
@@ -307,6 +307,12 @@ option(COMPILER_RT_USE_BUILTINS_LIBRARY
 
 option(COMPILER_RT_USE_ATOMIC_LIBRARY "Use compiler-rt atomic instead of libatomic" OFF)
 
+option(COMPILER_RT_EXECUTE_ONLY_CODE "Compile compiler-rt as execute-only" OFF)
+if (COMPILER_RT_EXECUTE_ONLY_CODE AND NOT LLVM_RUNTIMES_BUILD)
+  message(SEND_ERROR "COMPILER_RT_EXECUTE_ONLY_CODE is only supported "
+                     "for runtimes build of compiler-rt.")
+endif()
+
 include(config-ix)
 
 #================================
@@ -603,6 +609,20 @@ string(REGEX REPLACE "-stdlib=[a-zA-Z+]*" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}
 list(APPEND COMPILER_RT_COMMON_CFLAGS ${stdlib_flag})
 list(APPEND COMPILER_RT_COMMON_LINK_FLAGS ${stdlib_flag})
 
+# Add flags for execute-only code generation.
+# We need to add to both COMPILER_RT_COMMON_CFLAGS and CMAKE_<LANG>_FLAGS.
+if (COMPILER_RT_HAS_MEXECUTE_ONLY_FLAG)
+  append_list_if(COMPILER_RT_EXECUTE_ONLY_CODE -mexecute-only COMPILER_RT_COMMON_CFLAGS)
+  append_list_if(COMPILER_RT_EXECUTE_ONLY_CODE -DCOMPILER_RT_EXECUTE_ONLY_CODE COMPILER_RT_COMMON_CFLAGS)
+  append_string_if(COMPILER_RT_EXECUTE_ONLY_CODE -mexecute-only CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+  append_string_if(COMPILER_RT_EXECUTE_ONLY_CODE -DCOMPILER_RT_EXECUTE_ONLY_CODE CMAKE_ASM_FLAGS)
+elseif (COMPILER_RT_HAS_MPURE_CODE_FLAG)
+  append_list_if(COMPILER_RT_EXECUTE_ONLY_CODE -mpure-code COMPILER_RT_COMMON_CFLAGS)
+  append_list_if(COMPILER_RT_EXECUTE_ONLY_CODE -DCOMPILER_RT_EXECUTE_ONLY_CODE COMPILER_RT_COMMON_CFLAGS)
+  append_string_if(COMPILER_RT_EXECUTE_ONLY_CODE -mpure-code CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+  append_string_if(COMPILER_RT_EXECUTE_ONLY_CODE -DCOMPILER_RT_EXECUTE_ONLY_CODE CMAKE_ASM_FLAGS)
+endif()
+
 # TODO: There's a lot of duplication across lib/*/tests/CMakeLists.txt files,
 # move some of the common flags to COMPILER_RT_UNITTEST_CFLAGS.
 
diff --git a/compiler-rt/cmake/builtin-config-ix.cmake b/compiler-rt/cmake/builtin-config-ix.cmake
index 8c9c84ad64bc0..82fde12d85bf0 100644
--- a/compiler-rt/cmake/builtin-config-ix.cmake
+++ b/compiler-rt/cmake/builtin-config-ix.cmake
@@ -26,6 +26,8 @@ builtin_check_c_compiler_flag("-Xclang -mcode-object-version=none" COMPILER_RT_H
 builtin_check_c_compiler_flag(-Wbuiltin-declaration-mismatch COMPILER_RT_HAS_WBUILTIN_DECLARATION_MISMATCH_FLAG)
 builtin_check_c_compiler_flag(/Zl COMPILER_RT_HAS_ZL_FLAG)
 builtin_check_c_compiler_flag(-fcf-protection=full COMPILER_RT_HAS_FCF_PROTECTION_FLAG)
+builtin_check_c_compiler_flag(-mexecute-only       COMPILER_RT_HAS_MEXECUTE_ONLY_FLAG)
+builtin_check_c_compiler_flag(-mpure-code          COMPILER_RT_HAS_MPURE_CODE_FLAG)
 
 builtin_check_c_compiler_source(COMPILER_RT_HAS_ATOMIC_KEYWORD
 "
diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake
index e3310b1ff0e2c..e44eeb0ab1c20 100644
--- a/compiler-rt/cmake/config-ix.cmake
+++ b/compiler-rt/cmake/config-ix.cmake
@@ -115,6 +115,8 @@ check_cxx_compiler_flag(--sysroot=.          COMPILER_RT_HAS_SYSROOT_FLAG)
 check_cxx_compiler_flag("-Werror -mcrc"      COMPILER_RT_HAS_MCRC_FLAG)
 check_cxx_compiler_flag(-fno-partial-inlining COMPILER_RT_HAS_FNO_PARTIAL_INLINING_FLAG)
 check_cxx_compiler_flag("-Werror -ftrivial-auto-var-init=pattern" COMPILER_RT_HAS_TRIVIAL_AUTO_INIT)
+check_cxx_compiler_flag(-mexecute-only       COMPILER_RT_HAS_MEXECUTE_ONLY_FLAG)
+check_cxx_compiler_flag(-mpure-code          COMPILER_RT_HAS_MPURE_CODE_FLAG)
 
 if(NOT WIN32 AND NOT CYGWIN)
   # MinGW warns if -fvisibility-inlines-hidden is used.
diff --git a/compiler-rt/lib/builtins/CMakeLists.txt b/compiler-rt/lib/builtins/CMakeLists.txt
index d9b7800a95565..3842c089c1fbf 100644
--- a/compiler-rt/lib/builtins/CMakeLists.txt
+++ b/compiler-rt/lib/builtins/CMakeLists.txt
@@ -885,6 +885,7 @@ else ()
       cmake_push_check_state()
       # TODO: we should probably make most of the checks in builtin-config depend on the target flags.
       set(BUILTIN_CFLAGS_${arch} ${BUILTIN_CFLAGS})
+      set(BUILTIN_DEFS_${arch} ${BUILTIN_DEFS})
       # CMAKE_REQUIRED_FLAGS must be a space separated string
       # Join BUILTIN_CFLAGS_${arch} and TARGET_${arch}_CFLAGS as a
       # space-separated string.
@@ -922,6 +923,13 @@ else ()
       if(COMPILER_RT_HAS_${arch}_BFLOAT16)
         list(APPEND ${arch}_SOURCES ${BF16_SOURCES})
       endif()
+      if (COMPILER_RT_HAS_MEXECUTE_ONLY_FLAG)
+        append_list_if(COMPILER_RT_EXECUTE_ONLY_CODE -mexecute-only BUILTIN_CFLAGS_${arch})
+        append_list_if(COMPILER_RT_EXECUTE_ONLY_CODE COMPILER_RT_EXECUTE_ONLY_CODE BUILTIN_DEFS_${arch})
+      elseif (COMPILER_RT_HAS_MPURE_CODE_FLAG)
+        append_list_if(COMPILER_RT_EXECUTE_ONLY_CODE -mpure-code BUILTIN_CFLAGS_${arch})
+        append_list_if(COMPILER_RT_EXECUTE_ONLY_CODE COMPILER_RT_EXECUTE_ONLY_CODE BUILTIN_DEFS_${arch})
+      endif()
 
       # Remove a generic C builtin when an arch-specific builtin is specified.
       filter_builtin_sources(${arch}_SOURCES ${arch})
@@ -943,7 +951,7 @@ else ()
                               ARCHS ${arch}
                               DEPS ${deps_${arch}}
                               SOURCES ${${arch}_SOURCES}
-                              DEFS ${BUILTIN_DEFS}
+                              DEFS ${BUILTIN_DEFS_${arch}}
                               CFLAGS ${BUILTIN_CFLAGS_${arch}}
                               PARENT_TARGET builtins)
       cmake_pop_check_state()
@@ -1015,6 +1023,11 @@ if (COMPILER_RT_BUILD_CRT)
   if (COMPILER_RT_HAS_FCF_PROTECTION_FLAG)
     append_list_if(COMPILER_RT_ENABLE_CET -fcf-protection=full CRT_CFLAGS)
   endif()
+  if (COMPILER_RT_HAS_MEXECUTE_ONLY_FLAG)
+    append_list_if(COMPILER_RT_EXECUTE_ONLY_CODE -mexecute-only CRT_CFLAGS)
+  elseif (COMPILER_RT_HAS_MPURE_CODE_FLAG)
+    append_list_if(COMPILER_RT_EXECUTE_ONLY_CODE -mpure-code CRT_CFLAGS)
+  endif()
 
   foreach(arch ${BUILTIN_SUPPORTED_ARCH})
     add_compiler_rt_runtime(clang_rt.crtbegin
diff --git a/compiler-rt/lib/builtins/assembly.h b/compiler-rt/lib/builtins/assembly.h
index 385dc190369d9..2e4195d0ba6a8 100644
--- a/compiler-rt/lib/builtins/assembly.h
+++ b/compiler-rt/lib/builtins/assembly.h
@@ -71,9 +71,17 @@
 
 #endif
 
+#if defined(__aarch64__) && defined(__ELF__) &&                                \
+    defined(COMPILER_RT_EXECUTE_ONLY_CODE)
+#define TEXT_SECTION                                                           \
+  .section .text,"axy", at progbits,unique,0
+#else
+#define TEXT_SECTION                                                           \
+  .text
+#endif
+
 #if defined(__arm__) || defined(__aarch64__) || defined(__arm64ec__)
 #define FUNC_ALIGN                                                             \
-  .text SEPARATOR                                                              \
   .balign 16 SEPARATOR
 #else
 #define FUNC_ALIGN
@@ -230,6 +238,7 @@
 #endif
 
 #define DEFINE_COMPILERRT_FUNCTION(name)                                       \
+  TEXT_SECTION SEPARATOR                                                       \
   DEFINE_CODE_STATE                                                            \
   FILE_LEVEL_DIRECTIVE SEPARATOR                                               \
   .globl FUNC_SYMBOL(SYMBOL_NAME(name)) SEPARATOR                              \
@@ -239,6 +248,7 @@
   FUNC_SYMBOL(SYMBOL_NAME(name)):
 
 #define DEFINE_COMPILERRT_THUMB_FUNCTION(name)                                 \
+  TEXT_SECTION SEPARATOR                                                       \
   DEFINE_CODE_STATE                                                            \
   FILE_LEVEL_DIRECTIVE SEPARATOR                                               \
   .globl FUNC_SYMBOL(SYMBOL_NAME(name)) SEPARATOR                              \
@@ -248,6 +258,7 @@
   FUNC_SYMBOL(SYMBOL_NAME(name)):
 
 #define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name)                               \
+  TEXT_SECTION SEPARATOR                                                       \
   DEFINE_CODE_STATE                                                            \
   FILE_LEVEL_DIRECTIVE SEPARATOR                                               \
   .globl FUNC_SYMBOL(SYMBOL_NAME(name)) SEPARATOR                              \
@@ -257,6 +268,7 @@
   FUNC_SYMBOL(SYMBOL_NAME(name)):
 
 #define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name)                     \
+  TEXT_SECTION SEPARATOR                                                       \
   DEFINE_CODE_STATE                                                            \
   .globl FUNC_SYMBOL(name) SEPARATOR                                           \
   SYMBOL_IS_FUNC(name) SEPARATOR                                               \
@@ -265,6 +277,7 @@
   FUNC_SYMBOL(name):
 
 #define DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(name)                     \
+  TEXT_SECTION SEPARATOR                                                       \
   DEFINE_CODE_STATE                                                            \
   FUNC_ALIGN                                                                   \
   .globl FUNC_SYMBOL(name) SEPARATOR                                           \
diff --git a/compiler-rt/lib/fuzzer/CMakeLists.txt b/compiler-rt/lib/fuzzer/CMakeLists.txt
index 6db24610df1f0..adfba850861ac 100644
--- a/compiler-rt/lib/fuzzer/CMakeLists.txt
+++ b/compiler-rt/lib/fuzzer/CMakeLists.txt
@@ -163,8 +163,10 @@ if(OS_NAME MATCHES "Android|Linux|Fuchsia" AND
       CMAKE_ARGS -DCMAKE_CXX_COMPILER_WORKS=ON
                  -DCMAKE_POSITION_INDEPENDENT_CODE=ON
                  -DLIBCXXABI_ENABLE_EXCEPTIONS=OFF
+                 -DLIBCXXABI_EXECUTE_ONLY_CODE=${COMPILER_RT_EXECUTE_ONLY_CODE}
                  -DLIBCXX_ABI_NAMESPACE=__Fuzzer
-                 -DLIBCXX_ENABLE_EXCEPTIONS=OFF)
+                 -DLIBCXX_ENABLE_EXCEPTIONS=OFF
+                 -DLIBCXX_EXECUTE_ONLY_CODE=${COMPILER_RT_EXECUTE_ONLY_CODE})
     target_compile_options(RTfuzzer.${arch} PRIVATE -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1)
     add_dependencies(RTfuzzer.${arch} libcxx_fuzzer_${arch}-install-cmake326-workaround)
     target_compile_options(RTfuzzer_main.${arch} PRIVATE -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1)
diff --git a/compiler-rt/lib/hwasan/hwasan_setjmp_aarch64.S b/compiler-rt/lib/hwasan/hwasan_setjmp_aarch64.S
index 0c0abb6de861f..75ee6bc50baa8 100644
--- a/compiler-rt/lib/hwasan/hwasan_setjmp_aarch64.S
+++ b/compiler-rt/lib/hwasan/hwasan_setjmp_aarch64.S
@@ -28,7 +28,7 @@
 // stack pointer when compiling a C function.
 // Hence we have to write this function in assembly.
 
-.section .text
+TEXT_SECTION
 .file "hwasan_setjmp_aarch64.S"
 
 .global ASM_WRAPPER_NAME(setjmp)
diff --git a/compiler-rt/lib/hwasan/hwasan_tag_mismatch_aarch64.S b/compiler-rt/lib/hwasan/hwasan_tag_mismatch_aarch64.S
index fd060c51cd8e2..d38767f9378fa 100644
--- a/compiler-rt/lib/hwasan/hwasan_tag_mismatch_aarch64.S
+++ b/compiler-rt/lib/hwasan/hwasan_tag_mismatch_aarch64.S
@@ -70,7 +70,7 @@
 // clobbering the x17 register in error reports, and that the program will have
 // a runtime dependency on the __hwasan_tag_mismatch_v2 symbol therefore it will
 // fail to start up given an older (i.e. incompatible) runtime.
-.section .text
+TEXT_SECTION
 .file "hwasan_tag_mismatch_aarch64.S"
 .global __hwasan_tag_mismatch
 .type __hwasan_tag_mismatch, %function
diff --git a/compiler-rt/lib/msan/tests/CMakeLists.txt b/compiler-rt/lib/msan/tests/CMakeLists.txt
index a8500225337e6..53f570cfff27f 100644
--- a/compiler-rt/lib/msan/tests/CMakeLists.txt
+++ b/compiler-rt/lib/msan/tests/CMakeLists.txt
@@ -139,6 +139,8 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS AND
     add_custom_libcxx(libcxx_msan_${arch} ${LIBCXX_PREFIX}
       DEPS ${MSAN_RUNTIME_LIBRARIES}
       CFLAGS ${MSAN_LIBCXX_CFLAGS} ${TARGET_CFLAGS}
+      CMAKE_ARGS -DLIBCXX_EXECUTE_ONLY_CODE=${COMPILER_RT_EXECUTE_ONLY_CODE}
+                 -DLIBCXXABI_EXECUTE_ONLY_CODE=${COMPILER_RT_EXECUTE_ONLY_CODE}
       USE_TOOLCHAIN)
     set(MSAN_LIBCXX_DIR ${LIBCXX_PREFIX}/lib/)
 
diff --git a/compiler-rt/lib/orc/elfnix_tls.aarch64.S b/compiler-rt/lib/orc/elfnix_tls.aarch64.S
index 8dcdd535be8ae..22bd5b560c852 100644
--- a/compiler-rt/lib/orc/elfnix_tls.aarch64.S
+++ b/compiler-rt/lib/orc/elfnix_tls.aarch64.S
@@ -15,7 +15,11 @@
 
 #define REGISTER_SAVE_SPACE_SIZE     32 * 24
 
+#if defined(COMPILER_RT_EXECUTE_ONLY_CODE)
+        .section .text,"axy", at progbits,unique,0
+#else
         .text
+#endif
 
   // returns address of TLV in x0, all other registers preserved
   // TODO: add fast-path for repeat access
diff --git a/compiler-rt/lib/orc/sysv_reenter.arm64.S b/compiler-rt/lib/orc/sysv_reenter.arm64.S
index 74941c459d6ac..87a857c56ac61 100644
--- a/compiler-rt/lib/orc/sysv_reenter.arm64.S
+++ b/compiler-rt/lib/orc/sysv_reenter.arm64.S
@@ -13,7 +13,11 @@
 // The content of this file is arm64-only
 #if defined(__arm64__) || defined(__aarch64__)
 
+#if defined(__ELF__) && defined(COMPILER_RT_EXECUTE_ONLY_CODE)
+        .section .text,"axy", at progbits,unique,0
+#else
         .text
+#endif
 
         // Saves GPRs, calls __orc_rt_resolve
         .globl __orc_rt_sysv_reenter
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S
index cdfa6f1d7f53b..99d0aae0d2faa 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S
@@ -5,6 +5,7 @@
 
 ASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA)
 
+TEXT_SECTION
 .comm _ZN14__interception10real_vforkE,8,8
 .globl ASM_WRAPPER_NAME(vfork)
 ASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork))
diff --git a/compiler-rt/lib/tsan/CMakeLists.txt b/compiler-rt/lib/tsan/CMakeLists.txt
index 7928116879c09..686543e15fa6c 100644
--- a/compiler-rt/lib/tsan/CMakeLists.txt
+++ b/compiler-rt/lib/tsan/CMakeLists.txt
@@ -30,6 +30,8 @@ if(COMPILER_RT_LIBCXX_PATH AND
     add_custom_libcxx(libcxx_tsan_${arch} ${LIBCXX_PREFIX}
       DEPS ${TSAN_RUNTIME_LIBRARIES}
       CFLAGS ${TARGET_CFLAGS} -fsanitize=thread
+      CMAKE_ARGS -DLIBCXX_EXECUTE_ONLY_CODE=${COMPILER_RT_EXECUTE_ONLY_CODE}
+                 -DLIBCXXABI_EXECUTE_ONLY_CODE=${COMPILER_RT_EXECUTE_ONLY_CODE}
       USE_TOOLCHAIN)
     list(APPEND libcxx_tsan_deps libcxx_tsan_${arch}-install-cmake326-workaround)
   endforeach()
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_aarch64.S b/compiler-rt/lib/tsan/rtl/tsan_rtl_aarch64.S
index 7d920bee4a2db..93ad0d663c7a8 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_aarch64.S
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_aarch64.S
@@ -4,10 +4,8 @@
 #include "sanitizer_common/sanitizer_asm.h"
 #include "builtins/assembly.h"
 
-#if !defined(__APPLE__)
-.section .text
-#else
-.section __TEXT,__text
+TEXT_SECTION
+#if defined(__APPLE__)
 .align 3
 #endif
 
diff --git a/compiler-rt/lib/xray/xray_trampoline_AArch64.S b/compiler-rt/lib/xray/xray_trampoline_AArch64.S
index 2586def04cbb1..5d951f3821a50 100644
--- a/compiler-rt/lib/xray/xray_trampoline_AArch64.S
+++ b/compiler-rt/lib/xray/xray_trampoline_AArch64.S
@@ -37,7 +37,7 @@
 #endif
 .endm
 
-.text
+TEXT_SECTION
 .p2align 2
 .global ASM_SYMBOL(__xray_FunctionEntry)
 ASM_HIDDEN(__xray_FunctionEntry)

``````````

</details>


https://github.com/llvm/llvm-project/pull/140555


More information about the llvm-commits mailing list