refactor(core): simplify unpriv app vector table
What changed, and why it matters
This commit is a code cleanup that moves a small data table (the 'coreapp header') out of the processor's interrupt vector table file and into its own dedicated file. It does not change what the firmware does, only where the table is defined in the source code. There is no indication this fixes or introduces a security problem.
No security action required. Treat as a normal maintainability refactor. If reviewing for assurance, verify the new coreapp_header.S produces identical bytes to the removed conditional blocks for each build configuration (USE_APP_LOADING, USE_STORAGE_HWKEY).
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change refactors how the unprivileged application header is emitted. Previously, the same assembly file (vectortable.S) conditionally produced either a full ARM vector table (for kernel builds) or a compact coreapp header (for firmware/app builds). The commit extracts the coreapp header into a new file, coreapp_header.S, and updates the linker scripts to reference .coreapp_header instead of .vector_table. The generated binary layout appears functionally equivalent: the same words (reset handler, stack section, TLS section, API getter, SAES unprivileged callbacks) are placed at the same location after the kernel section. No runtime behavior change is visible in the diff.
Changed components
core/SConscript.firmwarecore/embed/projects/firmware/stm32/coreapp_header.Score/embed/sys/linker/stm32f4/firmware.ldcore/embed/sys/linker/stm32u58/firmware.ldcore/embed/sys/linker/stm32u5g/firmware.ldcore/embed/sys/startup/stm32f4/vectortable.Score/embed/sys/startup/stm32u5/vectortable.SInspect captured patch +36 / −40
diff --git a/core/SConscript.firmware b/core/SConscript.firmware
index c24241d2..5757e6ee 100644
--- a/core/SConscript.firmware
+++ b/core/SConscript.firmware
@@ -483,6 +483,7 @@ SOURCE_FIRMWARE = [
'embed/projects/firmware/boot_image_embdata.c',
'embed/projects/firmware/header.S',
'embed/projects/firmware/main.c',
+ 'embed/projects/firmware/stm32/coreapp_header.S',
'embed/projects/firmware/mphalport.c',
'embed/projects/firmware/nlrthumb.c',
]
diff --git a/core/embed/projects/firmware/stm32/coreapp_header.S b/core/embed/projects/firmware/stm32/coreapp_header.S
new file mode 100644
index 00000000..96363556
--- /dev/null
+++ b/core/embed/projects/firmware/stm32/coreapp_header.S
@@ -0,0 +1,32 @@
+ .syntax unified
+
+ .text
+
+ .section .coreapp_header, "a"
+coreapp_header:
+ .word reset_handler
+ .word _stack_section_start
+ .word _stack_section_size
+
+#ifdef USE_APP_LOADING
+ .word _tls_section_start
+ .word _tls_section_size
+ .word coreapp_api_get
+#else
+ .word 0
+ .word 0
+ .word 0
+#endif
+
+#if USE_STORAGE_HWKEY
+ .word saes_unpriv_input
+ .word saes_unpriv_output
+ .word saes_unpriv_callback
+#else
+ .word 0
+ .word 0
+ .word 0
+#endif
+
+
+ .end
diff --git a/core/embed/sys/linker/stm32f4/firmware.ld b/core/embed/sys/linker/stm32f4/firmware.ld
index 3be3e6be..dac9be08 100644
--- a/core/embed/sys/linker/stm32f4/firmware.ld
+++ b/core/embed/sys/linker/stm32f4/firmware.ld
@@ -43,7 +43,7 @@ SECTIONS {
.flash : ALIGN(512) {
KEEP(*(.kernel));
. = ALIGN(COREAPP_ALIGNMENT);
- KEEP(*(.vector_table));
+ KEEP(*(.coreapp_header));
. = ALIGN(4);
*(.text*);
. = ALIGN(4);
diff --git a/core/embed/sys/linker/stm32u58/firmware.ld b/core/embed/sys/linker/stm32u58/firmware.ld
index 2fd61dc6..ff41125a 100644
--- a/core/embed/sys/linker/stm32u58/firmware.ld
+++ b/core/embed/sys/linker/stm32u58/firmware.ld
@@ -38,7 +38,7 @@ SECTIONS {
.flash : ALIGN(CODE_ALIGNMENT) {
KEEP(*(.kernel));
. = ALIGN(COREAPP_ALIGNMENT);
- KEEP(*(.vector_table));
+ KEEP(*(.coreapp_header));
. = ALIGN(4);
*(.text*);
. = ALIGN(4);
diff --git a/core/embed/sys/linker/stm32u5g/firmware.ld b/core/embed/sys/linker/stm32u5g/firmware.ld
index e4bb2d5b..74fffeb6 100644
--- a/core/embed/sys/linker/stm32u5g/firmware.ld
+++ b/core/embed/sys/linker/stm32u5g/firmware.ld
@@ -41,7 +41,7 @@ SECTIONS {
.flash : ALIGN(CODE_ALIGNMENT) {
KEEP(*(.kernel));
. = ALIGN(COREAPP_ALIGNMENT);
- KEEP(*(.vector_table));
+ KEEP(*(.coreapp_header));
. = ALIGN(4);
*(.text*);
. = ALIGN(4);
diff --git a/core/embed/sys/startup/stm32f4/vectortable.S b/core/embed/sys/startup/stm32f4/vectortable.S
index f996e2e1..ff8b610b 100644
--- a/core/embed/sys/startup/stm32f4/vectortable.S
+++ b/core/embed/sys/startup/stm32f4/vectortable.S
@@ -128,19 +128,6 @@ vector_table:
add_handler LTDC_ER_IRQHandler
add_handler DMA2D_IRQHandler
-#else
-
- .section .vector_table, "a"
-vector_table:
- .word reset_handler
- .word _stack_section_start
- .word _stack_section_size
- .word 0 // TLS start
- .word 0 // TLS size
- .word 0 // API interface getter
- .word 0 // SAES unpriv input
- .word 0 // SAES unpriv output
- .word 0 // SAES unpriv callback
#endif
.end
diff --git a/core/embed/sys/startup/stm32u5/vectortable.S b/core/embed/sys/startup/stm32u5/vectortable.S
index ccce9c69..2d292bae 100644
--- a/core/embed/sys/startup/stm32u5/vectortable.S
+++ b/core/embed/sys/startup/stm32u5/vectortable.S
@@ -176,30 +176,6 @@ vector_table:
add_handler DSI_IRQHandler
add_handler DCACHE2_IRQHandler
-#else
-
- .section .vector_table, "a"
-vector_table:
- .word reset_handler
- .word _stack_section_start
- .word _stack_section_size
- .word _tls_section_start
- .word _tls_section_size
-#ifdef USE_APP_LOADING
- .word coreapp_api_get
-#else
- .word 0
-#endif
-#if USE_STORAGE_HWKEY
- .word saes_unpriv_input
- .word saes_unpriv_output
- .word saes_unpriv_callback
-#else
- .word 0
- .word 0
- .word 0
-#endif
-
#endif
.end
Why this scored 12/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.