← board

ESP-IDF (.o) profile: builtin heap still uses Linux mmap — any string literal crashes

Symptom

A riscv32 relocatable-object build for ESP-IDF (--target=riscv32 --platform=esp, .o output linked by idf.py) crashes the moment anything allocates:

Guru Meditation Error: Core 0 panic'ed (Environment call from M-mode).
MEPC: ... (HeapMmap)  RA: ... (PXXAlloc)   A7 = 0xde (= 222, linux mmap)

builtinheap.pas selects the ESP static-arena path only for CPU_XTENSA or CPU_RISCV32 + PXX_ESP_BARE:

{$ifdef CPU_XTENSA}{$define PXX_ESP}{$endif}
{$ifdef CPU_RISCV32}{$ifdef PXX_ESP_BARE}{$define PXX_ESP}{$endif}{$endif}

The IDF profile is riscv32 + --platform=esp WITHOUT bare boot, so the heap falls into the hosted-linux branch and executes ecall 222 (mmap) inside FreeRTOS → panic. First trigger in practice is PXXStrFromLit: passing any string literal to a string parameter (e.g. esp_rom_printf('...', v)) allocates. This means the committed examples/esp32/hello-c3 also crashes if rebuilt with the current compiler — its README's qemu validation predates the current heap/alloc behavior.

Fix direction

Acceptance

2026-07-14 — RESOLVED (b358)

Verified: string literal -> string param, AnsiString concat and Length all run on BOTH IDF legs (esp32c3 and esp32s3) under qemu; test-esp-bare fully green; quick + selfcheck green.

Honest residual on the acceptance list: timer-c3 now BOOTS and prints PXX timer: started / PXX timer: done ... (the panic is gone), but its callback never fires (ticks=0 status=2) — that is the pre-existing [[bug-esp-emit-obj-proc-fixup-non-iram]] territory (the example's header wart documents the same area), not the heap.

Log