Commit graph

8 commits

Author SHA1 Message Date
Marco Casaroli
0518ccb9ca libs/libc/elf, binfmt: Describe the GOT by base and size, not by index.
gotindex named the .got section header, and every user then reached through
shdr[] for what it actually wanted.  Only one of the five wanted the index.

gotbase and gotsize say it directly.  gotsize is the extent of .got and is
also what says the object has one, and gotbase is where the GOT ended up:
the placed address of .got for an ordinary object, or DT_PLTGOT for an FDPIC
one, which libelf_bind() already reads.  Both are set in libelf_loadfile(),
after the sections are placed, so gotbase is the address the object will be
read at rather than the one it was linked for.

The GOT walk in libelf_loadfile() now runs only when there is a base, which
also keeps it off an FDPIC object.  An FDPIC object's sections are never
placed, so .got carried a link time sh_addr there, and the walk read and
wrote through it.  Its GOT is relocated through its own relocations.

The check that gates libelf_xipacquire() runs before the load, when neither
field is set, so it looks the section up by name.  It hands the index it
found to libelf_loadfile(), which is the only reason that function takes
one: the object is searched once, not twice.

One behaviour changes: a .got that exists but is empty now reads as no GOT.
There is nothing for any of the five users to do with an empty one.

Built for pimoroni-pico-2-plus with CONFIG_PIC, CONFIG_ELF and
CONFIG_LIBC_ELF, and for mps3-an547:bl, which is the board that read the
index.  Run on QEMU with mps3-an547:picostest, which loads PIC ELF modules
from a romfs: hello prints, and ostest reaches the timed mutex test, the
same as before the change.

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-09-08 16:31:16 -03:00
Marco Casaroli
04dc50e71a libs/libc/elf: Fix two ways an FDPIC module failed to relocate.
Running one for the first time turned up two holes in the ET_DYN path.
Neither shows up in a build.

An undefined symbol is resolved with libelf_findglobal(), which searches
only the table of globally registered symbols.  The export table that
exec() hands its caller went no further than the ET_REL path, so an
ET_DYN module could not import anything the caller supplied.  Invisible
while such modules resolved everything internally; an FDPIC module
imports its libc, and every import failed with "Unable to resolve addr of
ext ref printf" although the caller had passed a table containing printf.
The export table is now threaded into libelf_relocatedyn() and consulted
when the global table has no answer, leaving the existing lookup order
intact.

A relocation naming a symbol defined inside the object was dropped
silently.  The code handles a relocation with no symbol, and one against
an undefined symbol, but a defined symbol fell through both.  That was
harmless while every dynamic relocation arriving here had symbol index
zero, which is the case for R_ARM_RELATIVE.  FDPIC brings the first ones
that do not: a pointer to a static function is emitted against the
*section* symbol, so the value is the section base and the offset within
it -- including the Thumb bit -- is carried as the addend.  Deriving a
value from the word being patched, as the no-symbol case does, would
translate that addend as though it were an address.  Confirmed against a
real module: .text at 0x23c plus an addend of 0x95 gives 0x2d1, which is
the function with its Thumb bit.

Also stop libelf_symname() reporting a nameless symbol as an error.  A
section symbol has no name, and libelf_findsymbol() walks the whole table
looking for optional entries such as nx_stacksize, so it meets these
routinely and checks for -ESRCH itself.  At error level it printed ten or
more lines per module load and buried the diagnostics that matter.

Built and run on lm3s6965-ek with the examples/elf ROMFS.  The ET_REL
test modules load as before, and an FDPIC module now loads, relocates,
resolves printf and puts from the table exec() supplied, and calls
through a function descriptor of its own.

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-09-08 16:31:16 -03:00
Marco Casaroli
450cfad383 libs/libc/elf: Read the dynamic tags an FDPIC object needs.
libelf_relocatedyn() reads the handful of DT_* tags it needs to walk the
relocation tables and ignores the rest.  Three more matter now.

DT_PLTGOT is where the object's data base lives.  An FDPIC module runs
with that in the PIC base register, and every function descriptor built
for it names the same base as the one its callee should run with, so
without it there is nothing to put in a descriptor's second word.

The DT_*_ARRAY tags are the constructor and destructor tables.  These are
already found through the section headers a few lines further down, and
that path is kept, but the dynamic tags are the authoritative copy and an
object is not obliged to carry section headers at all.  Both paths now
translate through libelf_addr(), so they agree on the answer rather than
depending on which ran last.  The tag values themselves were missing from
include/elf.h and are added.

Sizing the descriptor pool has to happen here rather than later.
R_ARM_FUNCDESC asks the loader to manufacture a descriptor and hand back
its address, which means the space must exist by the time the relocation
is applied, and by then the segment has been placed.  So libelf_elfsize()
reserves it behind the writable data, bounded by the relocation count --
one relocation cannot ask for more than one descriptor.  That bound has
slack in it, but a descriptor is two words and modules are small, which
is cheaper than walking every relocation twice to get an exact count.

Nothing here runs for a non-FDPIC object.  Built and booted
mps3-an547:picostest with no change in behaviour.

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-09-08 16:31:16 -03:00
Marco Casaroli
e662d523b2 libs/libc/elf: Fix the nxstyle errors in the lines this touches.
CI feeds nxstyle the diff hunks with three lines of context, so style errors
that are older than this change, in the lines around the hunks, fail the
check job.  They are a switch body indented two columns too deep, an
initializer brace one level in, and two declarations with no blank line
after them.

Whitespace only, no change in behaviour.

Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-08-27 19:01:58 -03:00
Marco Casaroli
014ea57042 libs/libc/elf: Translate link-time addresses through one place.
The ET_DYN path computes run-time addresses from link-time ones in five
places, each open-coding the arithmetic, and two of them disagree about
how: libelf_relocatedyn() adds textalloc to a relocation's r_offset in
one branch and subtracts datasec before adding datastart in the next,
while the value translation a few lines further down picks between those
two forms with an explicit test on datasec.

Collect that into libelf_addr(), which makes the test once: an address
below the data segment's link-time base belongs to text, anything at or
above it to data.

This changes nothing today.  libelf_elfsize() sets

  segpad   = datasec - (text_vaddr + textsize)

and libelf_load() then places

  datastart = textalloc + textsize + segpad

so datastart - datasec is textalloc, and the data branch reduces to
textalloc + vaddr -- exactly what the text branch returns, and exactly
what adding a single load bias did before.  The two forms are the same
arithmetic written twice.

They stop being the same once text and data are placed independently,
which is what an FDPIC object requires: its two PT_LOAD segments are
relocated separately so that the read-only one can be mapped in place on
the media while only the writable one is copied.  Having the translation
in one function is what makes that possible without auditing every
open-coded expression again.

Built for mps3-an547:picostest, which is CONFIG_ELF with CONFIG_PIC, and
boots identically to the same configuration without this change.

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-08-27 19:01:58 -03:00
Piyush Patle
0dccc8ba21 include/debug.h: Move to include/nuttx/debug.h
debug.h is a NuttX-specific, non-POSIX header. Placing it in the
top-level include/ directory creates naming conflicts with external
projects that define their own debug.h.
This commit moves the canonical header to include/nuttx/debug.h,
following the NuttX convention for non-POSIX/non-standard headers,
and updates all in-tree references.

A backward-compatibility shim is left at include/debug.h that
emits a deprecation #warning and re-includes <nuttx/debug.h>,
allowing out-of-tree code to continue building while migrating.

Signed-off-by: Piyush Patle <piyushpatle228@gmail.com>
2026-04-07 07:50:06 -03:00
Tiago Medicci Serrano
d250808c1c esp32s3/elf: Fix ELF loader on ESP32-S3 when using external PSRAM
Prior to this commit, it wasn't possible to load ELF modules from
the external PSRAM. There were two main issues about it: 1) copying
data using the instruction bus was being used instead of the data
bus (this, per si, isn't a problem, but requires special attention
regarding data alignment), and 2) the cache was not being properly
cleaned and flushed to properly access the loaded data using the
instruction bus.

Signed-off-by: Tiago Medicci Serrano <tiago.medicci@espressif.com>
2025-08-20 02:23:03 +08:00
chao an
52482219c8 libc/elf: rename modlib to libelf
Renaming "modlib" to "libelf" is more in line with the implementation content,
which makes it easier for individual developers to understand the capabilities of this module.

CONFIG_LIBC_MODLIB -> CONFIG_LIBC_ELF

Signed-off-by: chao an <anchao.archer@bytedance.com>
2025-04-11 09:43:22 +08:00
Renamed from libs/libc/modlib/modlib_bind.c (Browse further)