libelf_elfsize() takes textalign and dataalign from the section headers,
which only the ET_REL path walks. An ET_DYN object is sized from its
program headers instead, so both fields stay at zero, and the allocation
a few lines later asks for that alignment:
loadinfo->textalloc = lib_memalign(loadinfo->textalign, ...);
Zero is not a valid alignment, and every path that receives it divides by
it. mm_memalign() accepts zero as a power of two, because 0 & -0 is 0,
then takes the "alignment <= MM_ALIGN" branch and evaluates
"((uintptr_t)ptr) % alignment" in a DEBUGASSERT. With
CONFIG_MM_HEAP_MEMPOOL and a pool that fits the request the object never
reaches that branch and gets ALIGN_UP(blk, 0) instead, which is
((blk - 1) / 0) * 0.
On Cortex-M this is usually invisible: UDIV returns zero for a division
by zero unless CCR.DIV_0_TRP is set, which NuttX does not set, so the
assertion compares zero against zero and passes. It is a SIGFPE on the
simulator, and the mempool path returns a null pointer wherever the
division yields zero, which the loader reports as -ENOMEM.
Ask for a natural word when the program headers gave nothing. p_align is
the linker's page granularity, not a section requirement, so honouring it
would cost a page per module for no gain, and the sections of a shared
object need no more than a word.
Built for mps3-an547:picostest, which is CONFIG_ELF with CONFIG_PIC.
Runtime evidence on hardware follows.
Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>