Skip to content

Conversation

@kovdan01
Copy link
Contributor

@kovdan01 kovdan01 commented Jul 25, 2025

When ptrauth_calls is present but ptrauth_init_fini is not, compiler emits raw unsigned pointers in .init_array/.fini_array sections. Previously, __do_init/__do_fini pointers, which are explicitly added to the sections, were implicitly signed (due to the presense of ptrauth_calls), while all the other pointers in the sections were implicitly added by the compiler and thus non-signed.. As a result, the sections contained a mix of unsigned function pointers and function pointers signed with default signing schema.

This patch introduces use of inline assembly for this particular case, so we can manually specify that we do not want to sign the pointers.

Note that we cannot use __builtin_ptrauth_strip for this purpose since its result is not a constant expression.

@kovdan01 kovdan01 self-assigned this Jul 25, 2025
@kovdan01 kovdan01 moved this to In Progress in Pointer Authentication Tasks Jul 25, 2025
@kovdan01 kovdan01 requested a review from asl July 25, 2025 20:06
@kovdan01 kovdan01 force-pushed the pauth-compiler-rt-init-fini branch from 9a8bf68 to a049b76 Compare July 25, 2025 20:24
@kovdan01 kovdan01 marked this pull request as ready for review July 25, 2025 20:26
@github-actions
Copy link

github-actions bot commented Jul 25, 2025

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff HEAD~1 HEAD --extensions c -- compiler-rt/lib/builtins/crtbegin.c
View the diff from clang-format here.
diff --git a/compiler-rt/lib/builtins/crtbegin.c b/compiler-rt/lib/builtins/crtbegin.c
index 447474bd0..44cd9b614 100644
--- a/compiler-rt/lib/builtins/crtbegin.c
+++ b/compiler-rt/lib/builtins/crtbegin.c
@@ -54,33 +54,33 @@ static void __attribute__((used)) __do_init(void) {
 }
 
 #ifdef CRT_HAS_INITFINI_ARRAY
-# if __has_feature(ptrauth_init_fini)
+#if __has_feature(ptrauth_init_fini)
 // TODO: use __ptrauth-qualified pointers when they are supported on clang side
-#  if __has_feature(ptrauth_init_fini_address_discrimination)
+#if __has_feature(ptrauth_init_fini_address_discrimination)
 __attribute__((section(".init_array"), used)) static void *__init =
     ptrauth_sign_constant(&__do_init, ptrauth_key_init_fini_pointer,
                           ptrauth_blend_discriminator(
                               &__init, __ptrauth_init_fini_discriminator));
-#  else
+#else
 __attribute__((section(".init_array"), used)) static void *__init =
     ptrauth_sign_constant(&__do_init, ptrauth_key_init_fini_pointer,
                           __ptrauth_init_fini_discriminator);
-#  endif
-# elif __has_feature(ptrauth_calls)
-#  ifdef __aarch64__
+#endif
+#elif __has_feature(ptrauth_calls)
+#ifdef __aarch64__
 // If ptrauth_init_fini feature is not present, compiler emits raw unsigned
 // pointers in .init_array. Use inline assembly to avoid implicit signing of
 // __do_init function pointer with ptrauth_calls enabled.
 __asm__(".pushsection .init_array,\"aw\",@init_array\n\t"
         ".xword __do_init\n\t"
         ".popsection");
-#  else
-#   error "ptrauth_calls is only supported for AArch64"
-#  endif
-# else
+#else
+#error "ptrauth_calls is only supported for AArch64"
+#endif
+#else
 __attribute__((section(".init_array"),
                used)) static void (*__init)(void) = __do_init;
-# endif
+#endif
 #elif defined(__i386__) || defined(__x86_64__)
 __asm__(".pushsection .init,\"ax\",@progbits\n\t"
         "call __do_init\n\t"
@@ -136,33 +136,33 @@ static void __attribute__((used)) __do_fini(void) {
 }
 
 #ifdef CRT_HAS_INITFINI_ARRAY
-# if __has_feature(ptrauth_init_fini)
+#if __has_feature(ptrauth_init_fini)
 // TODO: use __ptrauth-qualified pointers when they are supported on clang side
-#  if __has_feature(ptrauth_init_fini_address_discrimination)
+#if __has_feature(ptrauth_init_fini_address_discrimination)
 __attribute__((section(".fini_array"), used)) static void *__fini =
     ptrauth_sign_constant(&__do_fini, ptrauth_key_init_fini_pointer,
                           ptrauth_blend_discriminator(
                               &__fini, __ptrauth_init_fini_discriminator));
-#  else
+#else
 __attribute__((section(".fini_array"), used)) static void *__fini =
     ptrauth_sign_constant(&__do_fini, ptrauth_key_init_fini_pointer,
                           __ptrauth_init_fini_discriminator);
-#  endif
-# elif __has_feature(ptrauth_calls)
-#  ifdef __aarch64__
+#endif
+#elif __has_feature(ptrauth_calls)
+#ifdef __aarch64__
 // If ptrauth_init_fini feature is not present, compiler emits raw unsigned
 // pointers in .fini_array. Use inline assembly to avoid implicit signing of
 // __do_fini function pointer with ptrauth_calls enabled.
 __asm__(".pushsection .fini_array,\"aw\",@fini_array\n\t"
         ".xword __do_fini\n\t"
         ".popsection");
-#  else
-#   error "ptrauth_calls is only supported for AArch64"
-#  endif
-# else
+#else
+#error "ptrauth_calls is only supported for AArch64"
+#endif
+#else
 __attribute__((section(".fini_array"),
                used)) static void (*__fini)(void) = __do_fini;
-# endif
+#endif
 #elif defined(__i386__) || defined(__x86_64__)
 __asm__(".pushsection .fini,\"ax\",@progbits\n\t"
         "call __do_fini\n\t"

@kovdan01
Copy link
Contributor Author

While clang-format complains about custom macro indents, I suppose it's worth keep them to enhance readability in nested ifdefs.

When `ptrauth_calls` is present but `ptrauth_init_fini` is not, compiler
emits raw unsigned pointers in `.init_array`/`.fini_array` sections.
Previously, `__do_init`/`__do_fini` pointers in these sections were
implicitly signed (due to the presense of `ptrauth_calls`). As a result,
the sections contained a mix of unsigned function pointers and function
pointers signed with default signing schema.

This patch introduces use of inline assembly for this particular case,
so we can manually specify that we do not want to sign the pointers.

Note that we cannot use `__builtin_ptrauth_strip` for this purpose since
its result is not a constant expression.
@kovdan01 kovdan01 force-pushed the pauth-compiler-rt-init-fini branch from a049b76 to 919c7df Compare July 25, 2025 20:49
Copy link
Contributor

@atrosinenko atrosinenko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure whether fixing clang-format violations is strictly required in the builtins library (by the way, even in this file I can see an indented define, though only a single line), but in other respects this patch looks good to me.

When ptrauth_calls is present but ptrauth_init_fini is not, compiler emits raw unsigned pointers in .init_array/.fini_array sections. Previously, __do_init/__do_fini pointers in these sections were implicitly signed (due to the presense of ptrauth_calls).

Considering the description, it feels like it could be made a bit easier to understand by mentioning that __do_init and __do_fini pointers are explicitly added to these sections - that's why they ended up being implicitly signed while every other pointer was non-signed.

@kovdan01 kovdan01 merged commit 19ba224 into llvm:main Jul 29, 2025
8 of 9 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in Pointer Authentication Tasks Jul 29, 2025
@kovdan01 kovdan01 added this to the LLVM 21.x Release milestone Jul 29, 2025
@github-project-automation github-project-automation bot moved this to Needs Triage in LLVM Release Status Jul 29, 2025
@kovdan01
Copy link
Contributor Author

/cherry-pick 19ba224

@llvmbot
Copy link
Member

llvmbot commented Jul 29, 2025

/pull-request #151096

@llvmbot llvmbot moved this from Needs Triage to Done in LLVM Release Status Jul 29, 2025
tru pushed a commit to llvmbot/llvm-project that referenced this pull request Aug 1, 2025
When `ptrauth_calls` is present but `ptrauth_init_fini` is not, compiler
emits raw unsigned pointers in `.init_array`/`.fini_array` sections.
Previously, `__do_init`/`__do_fini` pointers, which are explicitly added
to the sections, were implicitly signed (due to the presense of
`ptrauth_calls`), while all the other pointers in the sections were
implicitly added by the compiler and thus non-signed.. As a result, the
sections contained a mix of unsigned function pointers and function
pointers signed with default signing schema.

This patch introduces use of inline assembly for this particular case,
so we can manually specify that we do not want to sign the pointers.

Note that we cannot use `__builtin_ptrauth_strip` for this purpose since
its result is not a constant expression.

(cherry picked from commit 19ba224)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants