mirror of
https://github.com/apache/nuttx.git
synced 2026-08-01 20:28:58 +00:00
Lets a NOMMU target execute downloadable modules in place from memory-mapped NOR flash, so a module's text and rodata never consume RAM. It is the consumer of xipfs: the loader maps a module's read-only segment with MAP_XIP_STRICT, which resolves to a direct flash pointer or fails with -ENXIO rather than falling back to a RAM copy, and pins the extent for as long as the module is loaded so the defragmenter cannot relocate code that is executing. Only the writable segment is copied to RAM, once per running instance. The loader follows DT_NEEDED so a module can use shared libraries, each object getting its own GOT and its own data. FDPIC is what makes this possible: text is position-independent and each LOAD segment is placed independently, with the text-to-data offset communicated at load time through function descriptors and the GOT. A descriptor is a pair -- entry pointer plus data base -- so a module function handed back to the firmware carries the data base it needs. r9 holds that base at runtime, per the ARM FDPIC ABI. Reserving r9 across the base firmware is what allows a firmware routine to call back into module code and still arrive with the module's data base intact. Toolchain.defs puts --fixed-r9 in ARCHCPUFLAGS rather than CFLAGS, because almost every board Make.defs assigns CFLAGS with ':=' after including it, which would discard the flag; ARCHCPUFLAGS is re-expanded by that same assignment and so survives it. The CONFIG_PIC --fixed-r10 case is skipped under FDPIC, since reserving both registers would cost one for nothing. The DT_NEEDED walk is depth capped. fdpic_loaddepends() recursed once per link of a dependency chain with a path buffer on each frame and nothing to stop it, so a malformed module set overflowed the stack of whichever task called the loader instead of being rejected. A dependency *cycle* was never the hazard -- an object joins the load's list before its own dependencies are walked, so a library naming something already loaded finds it there and stops -- what was unbounded is a chain of distinct names, which the list cannot bound, hence an explicit cap rather than cycle detection. A module's .rofixup section is skipped, and the file header records why. .rofixup is the FDPIC self-relocation list a static executable's crt0 walks to derive its own GOT when no loader is present. A module links -shared -nostartfiles, so no crt0 runs, and the built objects hold exactly one entry there -- the address of the GOT itself, which this loader computes and installs at every entry into module code anyway. Assisted-by: Claude Code:claude-opus-5 Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
88 lines
2.4 KiB
C
88 lines
2.4 KiB
C
/****************************************************************************
|
|
* binfmt/binfmt_initialize.c
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <nuttx/binfmt/binfmt.h>
|
|
|
|
#include <nuttx/debug.h>
|
|
|
|
#include "binfmt.h"
|
|
|
|
#ifndef CONFIG_BINFMT_DISABLE
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: binfmt_initialize
|
|
*
|
|
* Description:
|
|
* initialize binfmt subsystem
|
|
*
|
|
****************************************************************************/
|
|
|
|
void binfmt_initialize(void)
|
|
{
|
|
int ret;
|
|
|
|
#ifdef CONFIG_BUILTIN
|
|
ret = builtin_initialize();
|
|
if (ret < 0)
|
|
{
|
|
berr("ERROR: builtin_initialize failed: %d\n", ret);
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_ELF
|
|
ret = elf_initialize();
|
|
if (ret < 0)
|
|
{
|
|
berr("ERROR: elf_initialize failed: %d\n", ret);
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_NXFLAT
|
|
ret = nxflat_initialize();
|
|
if (ret < 0)
|
|
{
|
|
berr("ERROR: nxflat_initialize failed: %d\n", ret);
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_FDPIC
|
|
ret = fdpic_initialize();
|
|
if (ret < 0)
|
|
{
|
|
berr("ERROR: fdpic_initialize failed: %d\n", ret);
|
|
}
|
|
#endif
|
|
|
|
UNUSED(ret);
|
|
}
|
|
|
|
#endif /* CONFIG_BINFMT_DISABLE */
|