[libc-commits] [libc] 73e1c53 - [libc][ARM] Defend banked SP setup against register allocator (#206757)

via libc-commits libc-commits at lists.llvm.org
Fri Jul 3 01:16:32 PDT 2026


Author: Simon Tatham
Date: 2026-07-03T09:16:27+01:00
New Revision: 73e1c53474a46a9686d7111c8566be2d90263aa4

URL: https://github.com/llvm/llvm-project/commit/73e1c53474a46a9686d7111c8566be2d90263aa4
DIFF: https://github.com/llvm/llvm-project/commit/73e1c53474a46a9686d7111c8566be2d90263aa4.diff

LOG: [libc][ARM] Defend banked SP setup against register allocator (#206757)

The startup code for bare-metal AArch32 A/R shifts the CPU through all
the different modes which have their own copies of SP, updating all the
stack pointers to the same value. But it does it using C intrinsics,
leaving the register allocation to the compiler – so it's possible that
the register allocator happens to use one of the _other_ banked
registers, such as LR.

For example, when I built this code today, it happened that LR was used
to hold one of the constants written into CPSR_c to change mode. That
constant was written into the SVC mode LR before any mode changes, but
the MSR instruction that tried to use it was run in a different mode, so
it copied from _that_ mode's LR, which contained uninitialised nonsense
in place of the desired constant, triggering a boot-time crash.

I think it's safer to use a single asm statement for the whole job,
guaranteeing which registers it uses.

Added: 
    

Modified: 
    libc/startup/baremetal/arm/start.cpp

Removed: 
    


################################################################################
diff  --git a/libc/startup/baremetal/arm/start.cpp b/libc/startup/baremetal/arm/start.cpp
index 42e883175c8f3..d1dc3434f5f6a 100644
--- a/libc/startup/baremetal/arm/start.cpp
+++ b/libc/startup/baremetal/arm/start.cpp
@@ -174,17 +174,27 @@ namespace LIBC_NAMESPACE_DECL {
 #if __ARM_ARCH_PROFILE == 'A' || __ARM_ARCH_PROFILE == 'R'
   // Set up registers to be used in exception handling
   // Copy the current sp value to each of the banked copies of sp.
-  __arm_wsr("CPSR_c", 0x11); // FIQ
-  asm volatile("mov sp, %0" : : "r"(__builtin_frame_address(0)));
-  __arm_wsr("CPSR_c", 0x12); // IRQ
-  asm volatile("mov sp, %0" : : "r"(__builtin_frame_address(0)));
-  __arm_wsr("CPSR_c", 0x17); // ABT
-  asm volatile("mov sp, %0" : : "r"(__builtin_frame_address(0)));
-  __arm_wsr("CPSR_c", 0x1B); // UND
-  asm volatile("mov sp, %0" : : "r"(__builtin_frame_address(0)));
-  __arm_wsr("CPSR_c", 0x1F); // SYS
-  asm volatile("mov sp, %0" : : "r"(__builtin_frame_address(0)));
-  __arm_wsr("CPSR_c", 0x13); // SVC
+  asm volatile("mov r0, sp\n"
+               "mov r1, #0x11\n" // FIQ
+               "msr CPSR_c, r1\n"
+               "mov sp, r0\n"
+               "mov r1, #0x12\n" // IRQ
+               "msr CPSR_c, r1\n"
+               "mov sp, r0\n"
+               "mov r1, #0x17\n" // ABT
+               "msr CPSR_c, r1\n"
+               "mov sp, r0\n"
+               "mov r1, #0x1B\n" // UND
+               "msr CPSR_c, r1\n"
+               "mov sp, r0\n"
+               "mov r1, #0x1F\n" // SYS
+               "msr CPSR_c, r1\n"
+               "mov sp, r0\n"
+               "mov r1, #0x13\n" // return to SVC
+               "msr CPSR_c, r1"
+               :
+               :
+               : "r0", "r1");
 #endif
 
 #if __ARM_ARCH_PROFILE == 'A' && !defined(__ARM_ARCH_ISA_A64) && __ARM_ARCH >= 7


        


More information about the libc-commits mailing list