Skip to content

fix(settings): app fails to launch on real hardware — misaligned relocation from packed struct pointer - #7

Open
vvzvlad wants to merge 1 commit into
eldios:watchfacefrom
vvzvlad:fix/misaligned-reloc-strftime-format
Open

fix(settings): app fails to launch on real hardware — misaligned relocation from packed struct pointer#7
vvzvlad wants to merge 1 commit into
eldios:watchfacefrom
vvzvlad:fix/misaligned-reloc-strftime-format

Conversation

@vvzvlad

@vvzvlad vvzvlad commented Jul 25, 2026

Copy link
Copy Markdown

Problem

On real hardware (Pebble Time 2 / emery) TimelyNG never launches — selecting
it drops straight back to the launcher. The firmware log shows:

[WARN] process_loader_storage.c:162  Invalid app relocation target[68]: 0x78d7
[WARN] app_manager.c:315             Tried to launch an invalid app in bank 6!
[WARN] app_manager.c:629             Failed to start app <TimelyNG>! Restarting launcher

So the app is rejected at load time, during relocation fix-up — it is not a
heap or SDK-version problem (heap is ~99 KB free, sdk_version 5.104 matches).

Root cause

persist in src/settings.h is __attribute__((__packed__)) and contains a
pointer member:

typedef struct persist {
  uint8_t version;              // 18 single-byte fields (offsets 0..17)
  ...
  uint8_t vibe_pat_connect;
  char *strftime_format;        // pointer at unaligned offset 18
  ...
} __attribute__((__packed__)) persist;

Because the struct is packed, strftime_format lands at byte offset 18. The
static initialiser in src/settings.c set it to a string literal:

.strftime_format = "%Y-%m-%d",

That stores an absolute address, so the toolchain emits an R_ARM_ABS32
relocation at image offset 0x78d7 (= &s_settings + 18), which is not
word-aligned
. prv_apply_relocations() in the app loader requires every
relocation target to be word-aligned and rejects the whole app when it isn't —
hence "Invalid app relocation target" and the app never runs.

This likely doesn't reproduce in every emulator/SDK (older loaders didn't
enforce the alignment check), which is why it slipped through, but the current
Core Devices firmware enforces it.

Fix

persist.strftime_format is never read in C — the custom date format used at
runtime is adv_settings.custom_date_fmt (Timely.c, date_format == 255).
So initialise the field to a null pointer instead of a literal:

.strftime_format = 0,

A null pointer needs no relocation, so the offending R_ARM_ABS32 entry
disappears. The struct layout is unchanged, so persist_read_data /
persist_write_data stay byte-compatible with existing installs.

Verification

  • Rebuilt for emery: relocation count drops 76 → 75, and every remaining
    entry is word-aligned and in range (previously entry 68 = 0x78d7).
  • Installed the rebuilt .pbw on a real Pebble Time 2 and confirmed the
    watchface launches and stays running (app run state: RUNNING,
    no "invalid app" / no fault loop).

🤖 Generated with Claude Code

persist.strftime_format is a char* at an unaligned offset inside a
__attribute__((packed)) struct. Initialising it with a string literal
made the compiler emit an R_ARM_ABS32 relocation at a non-word-aligned
image offset (0x78d7). The PebbleOS app loader requires relocation
targets to be word-aligned and rejects the app at load time:
"Invalid app relocation target[68]" -> "invalid app in bank 6" ->
"Failed to start app <TimelyNG>", so the watchface never launched.

The field is never read in C (the custom date format lives in
adv_settings.custom_date_fmt), so initialise it to a null pointer.
No struct layout change, so persisted settings stay compatible.
Relocations drop 76 -> 75, all word-aligned; verified installing and
launching on Pebble Time 2 (emery).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant