[libc-commits] [libc] [libc] Add startup code for ARM v7-A, ARM v7-R variants (PR #153576)

William Huynh via libc-commits libc-commits at lists.llvm.org
Fri Aug 15 02:13:15 PDT 2025


https://github.com/saturn691 updated https://github.com/llvm/llvm-project/pull/153576

>From 9cfdd4660df0d50f6edf97f3b4ae37544fa78639 Mon Sep 17 00:00:00 2001
From: William Huynh <William.Huynh at arm.com>
Date: Thu, 14 Aug 2025 14:33:10 +0100
Subject: [PATCH 1/2] [libc] Add startup code for ARM v7-A, ARM v7-R variants

These variants require a different exception table that requires a
bit of initialisation.

This allows us to enable testing for these variants downstream.
---
 libc/startup/baremetal/arm/start.cpp | 67 ++++++++++++++++++++++++++--
 1 file changed, 64 insertions(+), 3 deletions(-)

diff --git a/libc/startup/baremetal/arm/start.cpp b/libc/startup/baremetal/arm/start.cpp
index 493445e2922b0..a926206c73a6f 100644
--- a/libc/startup/baremetal/arm/start.cpp
+++ b/libc/startup/baremetal/arm/start.cpp
@@ -15,6 +15,8 @@
 #include "startup/baremetal/fini.h"
 #include "startup/baremetal/init.h"
 
+#include <arm_acle.h>
+
 extern "C" {
 int main(int argc, char **argv);
 void _start();
@@ -33,6 +35,7 @@ extern uintptr_t __bss_size[];
 } // extern "C"
 
 namespace {
+#if __ARM_ARCH_PROFILE == 'M'
 // Based on
 // https://developer.arm.com/documentation/107565/0101/Use-case-examples/Generic-Information/What-is-inside-a-program-image-/Vector-table
 void NMI_Handler() {}
@@ -55,8 +58,8 @@ const HandlerType vector_table[] = {
     reinterpret_cast<HandlerType>(&__stack), // SP
     _start,                                  // Reset
     NMI_Handler,                             // NMI Handler
-    HardFault_Handler,                       // Hard Fault Handlerß
-    MemManage_Handler,                       // MPU Fault Han`dler
+    HardFault_Handler,                       // Hard Fault Handler
+    MemManage_Handler,                       // MPU Fault Handler
     BusFault_Handler,                        // Bus Fault Handler
     UsageFault_Handler,                      // Usage Fault Handler
     0,                                       // Reserved
@@ -70,12 +73,64 @@ const HandlerType vector_table[] = {
     SysTick_Handler,                         // SysTick Handler
                                              // Unused
 };
+#else
+// Based on
+// https://developer.arm.com/documentation/den0013/0400/Boot-Code/Booting-a-bare-metal-system
+void Reset_Handler() { LIBC_NAMESPACE::exit(1); }
+void Undefined_Handler() { LIBC_NAMESPACE::exit(1); }
+void SWI_Handler() { LIBC_NAMESPACE::exit(1); }
+void PrefetchAbort_Handler() { LIBC_NAMESPACE::exit(1); }
+void DataAbort_Handler() { LIBC_NAMESPACE::exit(1); }
+void IRQ_Handler() { LIBC_NAMESPACE::exit(1); }
+void FIQ_Handler() { LIBC_NAMESPACE::exit(1); }
+
+// The AArch32 exception vector table has 8 entries, each of which is 4
+// bytes long, and contains code. The whole table must be 32-byte aligned.
+// The table may also be relocated, so we make it position-independent by
+// having a table of handler addresses and loading the address to pc.
+[[gnu::section(".vectors"), gnu::aligned(32), gnu::used, gnu::naked,
+  gnu::target("arm")]]
+void vector_table() {
+  asm("LDR pc, [pc, #24]");
+  asm("LDR pc, [pc, #24]");
+  asm("LDR pc, [pc, #24]");
+  asm("LDR pc, [pc, #24]");
+  asm("LDR pc, [pc, #24]");
+  asm("LDR pc, [pc, #24]");
+  asm("LDR pc, [pc, #24]");
+  asm("LDR pc, [pc, #24]");
+  asm(".word %c0" : : "X"(Reset_Handler));
+  asm(".word %c0" : : "X"(Undefined_Handler));
+  asm(".word %c0" : : "X"(SWI_Handler));
+  asm(".word %c0" : : "X"(PrefetchAbort_Handler));
+  asm(".word %c0" : : "X"(DataAbort_Handler));
+  asm(".word %c0" : : "X"(0));
+  asm(".word %c0" : : "X"(IRQ_Handler));
+  asm(".word %c0" : : "X"(FIQ_Handler));
+}
+#endif
 } // namespace
 
 namespace LIBC_NAMESPACE_DECL {
 [[noreturn]] void do_start() {
   // FIXME: set up the QEMU test environment
 
+#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
+#endif
+
   // Perform the equivalent of scatterloading
   LIBC_NAMESPACE::memcpy(__data_start, __data_source,
                          reinterpret_cast<uintptr_t>(__data_size));
@@ -89,7 +144,13 @@ namespace LIBC_NAMESPACE_DECL {
 }
 } // namespace LIBC_NAMESPACE_DECL
 
-extern "C" void _start() {
+extern "C" {
+#ifdef __ARM_ARCH_ISA_ARM
+// If ARM state is supported, it must be used (instead of Thumb)
+[[gnu::naked, gnu::target("arm")]]
+#endif
+void _start() {
   asm volatile("mov sp, %0" : : "r"(&__stack));
   asm volatile("bl %0" : : "X"(LIBC_NAMESPACE::do_start));
 }
+} // extern "C"

>From dabfd30382021619daa63ee54af79f4f0e0cfaa4 Mon Sep 17 00:00:00 2001
From: William Huynh <William.Huynh at arm.com>
Date: Fri, 15 Aug 2025 10:13:03 +0100
Subject: [PATCH 2/2] Add suggestion from @michaelrj-google

---
 libc/startup/baremetal/arm/start.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/startup/baremetal/arm/start.cpp b/libc/startup/baremetal/arm/start.cpp
index a926206c73a6f..c089a14f5f782 100644
--- a/libc/startup/baremetal/arm/start.cpp
+++ b/libc/startup/baremetal/arm/start.cpp
@@ -15,7 +15,7 @@
 #include "startup/baremetal/fini.h"
 #include "startup/baremetal/init.h"
 
-#include <arm_acle.h>
+#include <arm_acle.h> // For __arm_wsr
 
 extern "C" {
 int main(int argc, char **argv);



More information about the libc-commits mailing list