diff --git a/EXTERNAL_LIBS.md b/EXTERNAL_LIBS.md index af7b2380..a9e4ae0c 100644 --- a/EXTERNAL_LIBS.md +++ b/EXTERNAL_LIBS.md @@ -250,10 +250,40 @@ sort -u -o /tmp/resolvable.txt /tmp/resolvable.txt | grep -vE "^__|uxTopUsedPriority" ``` -Known-harmless leftovers (resolved at final `.fal`/loader link): `__aeabi_*`, -`__paritysi2`, `__popcountsi2`, `uxTopUsedPriority`. Also ignore `FF_*` style -`extern const char[]` if the app defines them in one of its own `.c` (e.g. -`protocols_common.c`) — check with `grep`. +Known-harmless leftovers: `uxTopUsedPriority` (linker builtin). Also ignore +`FF_*` style `extern const char[]` if the app defines them in one of its own +`.c` (e.g. `protocols_common.c`) — check with `grep`. + +**IMPORTANT — libgcc/compiler-rt helpers under XIP.** Helpers the compiler emits +(`__paritysi2`, `__popcountsi2`, `__aeabi_*`, etc.) are NOT self-contained in the +`.fap`: they show up as undefined (`U`) and must be resolved against the firmware +at load time, exactly like any other imported symbol. They live in `firmware.elf` +(`arm-none-eabi-nm build/f7-firmware-C/firmware.elf | grep __paritysi2`) but are +only reachable by apps if they are also in the SDK table +(`targets/f7/api_symbols.csv` with status `+`). If a helper is missing there: +- A **non-XIP** app (fits in RAM) often still appears to run because that code + path may never execute — the app loads. This is why several stock apps that use + `__paritysi2` "work". +- A **ForceXIP** app (subghz, nfc) **hard-crashes the Flipper with an OOM reboot** + at load: the XIP fast-relocation pass hits the unresolved hash mid-stream and + aborts. Log: `XIP: unresolved fast rel record N`. + +The `nm` offline check above will NOT flag these (they're technically resolvable +against firmware — they're just not in the table). To find the exact culprit, +temporarily log the hash+name in `elf_file.c` where the XIP fast-rel loop sets +`unresolved fast rel record` (use `elf_file_find_string_by_hash`). + +Fix: **declare the helper's prototype in +`targets/f7/platform_specific/intrinsic_export.h`** (an SDK header that exists +exactly to expose libgcc/compiler-rt intrinsics which have no normal header), +then rebuild twice so the SDK checker adds it to `api_symbols.csv` and finalizes +the version. Do NOT hand-edit `api_symbols.csv` for these — the checker +regenerates the table from headers and will delete rows it can't trace to a +header (it reported `Removed: {__paritysi2, __popcountsi2}` when we tried). +Added this way: `__paritysi2` and `__popcountsi2` (both `int (unsigned int)`), +needed by the SubGhz/NFC protocol code (bit parity/popcount) under XIP. +`__aeabi_f2d`/`__aeabi_uldivmod` were already declared there (that's why +`lfrfid`, which only uses `__aeabi_f2d`, never crashed). ## Fix depending on where the symbol lives diff --git a/lib/flipper_application/elf/elf_file.c b/lib/flipper_application/elf/elf_file.c index 6db28502..39e90104 100644 --- a/lib/flipper_application/elf/elf_file.c +++ b/lib/flipper_application/elf/elf_file.c @@ -1130,7 +1130,29 @@ static bool elf_xip_stream_section(ELFFile* elf, ELFSection* sec, bool patch_mod fast_records[i].address = elf_address_of_by_hash(elf, hash_or_idx); } if(fast_records[i].address == ELF_INVALID_ADDRESS) { - FURI_LOG_E(TAG, "XIP: unresolved fast rel record %lu", i); + /* Diagnostic: report which symbol/section failed to + * resolve. A common culprit is a libgcc/compiler-rt + * helper (e.g. __paritysi2) not exported in the SDK + * table (api_symbols.csv) — see EXTERNAL_LIBS.md. */ + if(is_section) { + FURI_LOG_E( + TAG, + "XIP: unresolved fast rel record %lu SECTION idx=%lu val=%lX", + i, + (unsigned long)hash_or_idx, + (unsigned long)section_value); + } else { + FuriString* sym_name = furi_string_alloc(); + bool found = + elf_file_find_string_by_hash(elf, hash_or_idx, sym_name); + FURI_LOG_E( + TAG, + "XIP: unresolved fast rel record %lu HASH=%lX name=%s", + i, + (unsigned long)hash_or_idx, + found ? furi_string_get_cstr(sym_name) : ""); + furi_string_free(sym_name); + } ok = false; } fr += 3 * fast_records[i].offsets_count; diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index fd3a7a5d..00a9bc94 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,92.1,, +Version,+,93.1,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/applications.h,, Header,+,applications/services/bt/bt_service/bt.h,, @@ -376,6 +376,8 @@ Function,-,__isnand,int,double Function,-,__isnanf,int,float Function,-,__itoa,char*,"int, char*, int" Function,-,__locale_mb_cur_max,int, +Function,+,__paritysi2,int,unsigned int +Function,+,__popcountsi2,int,unsigned int Function,+,__retarget_lock_acquire,void,_LOCK_T Function,+,__retarget_lock_acquire_recursive,void,_LOCK_T Function,-,__retarget_lock_close,void,_LOCK_T diff --git a/targets/f7/platform_specific/intrinsic_export.h b/targets/f7/platform_specific/intrinsic_export.h index 989bcafb..845b3219 100644 --- a/targets/f7/platform_specific/intrinsic_export.h +++ b/targets/f7/platform_specific/intrinsic_export.h @@ -9,6 +9,11 @@ extern "C" { void __clear_cache(void*, void*); void* __aeabi_uldivmod(uint64_t, uint64_t); double __aeabi_f2d(float); +/* Bit parity/popcount helpers emitted by the compiler for SubGhz/NFC protocol + * code. Needed by ForceXIP apps (subghz, nfc) whose XIP fast-relocation resolves + * these against the firmware at load time. See EXTERNAL_LIBS.md. */ +int __paritysi2(unsigned int); +int __popcountsi2(unsigned int); #ifdef __cplusplus }