double_sci_m33.S: rtwopi/trigtab tables have no alignment directive; Clang leaves them byte-aligned and ldmia faults (UNALIGNED) on RP2350 #3183

Open
opened 2026-09-06 10:33:51 -05:00 by e38e2e892 · 0 comments
e38e2e892 commented 2026-09-06 10:33:51 -05:00 (Migrated from github.com)

Summary

src/rp2_common/pico_double/double_sci_m33.S defines its two data tables, rtwopi and trigtab, with double_section (a fresh "ax" section each) and no alignment directive. When the file is assembled by Clang's integrated assembler (LLVM Embedded Toolchain for Arm 19.1.5, PICO_COMPILER=pico_arm_cortex_m33_clang), those sections get sh_addralign = 1, so the linker may place a table at a 2-byte-aligned address behind Thumb code. The code then reads them with word-aligned-only instructions (ldmia r3,{r2-r5} in the sin/cos range reduction and in atan2_entry), which raises a UsageFault (UNALIGNED, escalated to HardFault when UsageFault is disabled) on the Cortex-M33.

Observed on pico-sdk 2.3.0 (98a542c1a62fb549ffb5d66a3e5892b06276b670); the file is unchanged on master and develop as of today.

Evidence

llvm-readelf -S on the object built for rp2350-arm-s:

  [ 3] .text.rtwopi      PROGBITS        00000000 000034 0000a0 00  AX  0   0  1
  [12] .text.exptab      PROGBITS        00000000 000678 0001fc 00  AX  0   0  4
  [17] .text.trigtab     PROGBITS        00000000 000d3c 000200 00  AX  0   0  1

exptab is preceded by .align 2 and gets alignment 4; the other two are not and get 1. In one link trigtab landed at 0x10001066, and a program calling atan2() faulted at the first table read:

cfsr=0x01000000 (UFSR.UNALIGNED)  hfsr=0xc0000000  stacked pc=0x1000142c
1000142c: cb3c   ldm r3, {r2, r3, r4, r5}     ; r3 = 0x10001106 (trigtab + 0xa0)

Whether a given build faults depends on the size of the code the linker places before the table, so it is easy to miss: a build that happens to land the table on a word boundary runs fine.

GCC builds are unaffected in practice because GNU as gives these sections word alignment.

Fix

Two lines:

 double_section rtwopi
+.p2align 2
 
 // 1/2π to plenty of accuracy, 256 bits per line
@@
 double_section trigtab
+.p2align 2
 trigtab:

float_sci_m33_vfp.S already carries .p2align before its tables, so this brings the double file in line with it. Happy to open a PR if that is preferred.

Configuration

  • pico-sdk 2.3.0, PICO_PLATFORM=rp2350-arm-s, PICO_BOARD=pico2
  • PICO_COMPILER=pico_arm_cortex_m33_clang, PICO_CLIB=llvm_libc, PICO_HARD_FLOAT_ABI=1 (the section alignment does not depend on the ABI)
  • LLVM Embedded Toolchain for Arm 19.1.5
  • pico_double_pico_dcp (the default pico double implementation on RP2350 Arm)
### Summary `src/rp2_common/pico_double/double_sci_m33.S` defines its two data tables, `rtwopi` and `trigtab`, with `double_section` (a fresh `"ax"` section each) and no alignment directive. When the file is assembled by Clang's integrated assembler (LLVM Embedded Toolchain for Arm 19.1.5, `PICO_COMPILER=pico_arm_cortex_m33_clang`), those sections get `sh_addralign = 1`, so the linker may place a table at a 2-byte-aligned address behind Thumb code. The code then reads them with word-aligned-only instructions (`ldmia r3,{r2-r5}` in the sin/cos range reduction and in `atan2_entry`), which raises a UsageFault (UNALIGNED, escalated to HardFault when UsageFault is disabled) on the Cortex-M33. Observed on pico-sdk 2.3.0 (`98a542c1a62fb549ffb5d66a3e5892b06276b670`); the file is unchanged on `master` and `develop` as of today. ### Evidence `llvm-readelf -S` on the object built for `rp2350-arm-s`: ``` [ 3] .text.rtwopi PROGBITS 00000000 000034 0000a0 00 AX 0 0 1 [12] .text.exptab PROGBITS 00000000 000678 0001fc 00 AX 0 0 4 [17] .text.trigtab PROGBITS 00000000 000d3c 000200 00 AX 0 0 1 ``` `exptab` is preceded by `.align 2` and gets alignment 4; the other two are not and get 1. In one link `trigtab` landed at `0x10001066`, and a program calling `atan2()` faulted at the first table read: ``` cfsr=0x01000000 (UFSR.UNALIGNED) hfsr=0xc0000000 stacked pc=0x1000142c 1000142c: cb3c ldm r3, {r2, r3, r4, r5} ; r3 = 0x10001106 (trigtab + 0xa0) ``` Whether a given build faults depends on the size of the code the linker places before the table, so it is easy to miss: a build that happens to land the table on a word boundary runs fine. GCC builds are unaffected in practice because GNU as gives these sections word alignment. ### Fix Two lines: ```diff double_section rtwopi +.p2align 2 // 1/2π to plenty of accuracy, 256 bits per line @@ double_section trigtab +.p2align 2 trigtab: ``` `float_sci_m33_vfp.S` already carries `.p2align` before its tables, so this brings the double file in line with it. Happy to open a PR if that is preferred. ### Configuration - pico-sdk 2.3.0, `PICO_PLATFORM=rp2350-arm-s`, `PICO_BOARD=pico2` - `PICO_COMPILER=pico_arm_cortex_m33_clang`, `PICO_CLIB=llvm_libc`, `PICO_HARD_FLOAT_ABI=1` (the section alignment does not depend on the ABI) - LLVM Embedded Toolchain for Arm 19.1.5 - `pico_double_pico_dcp` (the default `pico` double implementation on RP2350 Arm)
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-raspberrypi/pico-sdk#3183
No description provided.