casaroli commented on code in PR #20132:
URL: https://github.com/apache/nuttx/pull/20132#discussion_r4208191264


##########
Documentation/components/fdpic.rst:
##########
@@ -0,0 +1,513 @@
+.. _fdpic:
+
+=============
+FDPIC Modules
+=============
+
+Overview
+========
+
+An FDPIC module is an ELF shared object whose read-only and writable
+segments are placed independently of one another.  NuttX uses the
+read-only segment where it already lies on the media and never copies
+it; only the writable segment is copied to RAM, once per running
+instance.  A module's code and ``.rodata`` therefore cost no RAM at all,
+and several instances of one module share them.
+
+FDPIC is not a separate binary format and has no loader of its own.  An
+object announces itself in its OS/ABI byte,
+``e_ident[EI_OSABI] == ELFOSABI_ARM_FDPIC`` (65), which ``readelf -h``
+reports as *OS/ABI: ARM FDPIC*, and the ELF loader takes it from there.
+Everything else -- ``exec()``, ``posix_spawn()``, ``dlopen()``, the
+symbol table -- is the ordinary ELF path.
+
+What FDPIC adds over the position independent ELF support already in the
+tree is a function pointer that carries its own data base.  That is what
+lets a module be called back on a thread it did not create, and what
+lets a module and the libraries it uses hold distinct data bases at the
+same time.
+
+Function descriptors
+--------------------
+
+Code reaches its own data through a base register -- **r9** on ARM --
+holding the address of that object's GOT.  Because code and data are
+placed independently, a bare code address is not enough to call a
+function: the callee needs its data base too.  FDPIC therefore
+represents a function pointer as a two word *descriptor*:
+
+===========  ==============================================================
+Word         Contents
+===========  ==============================================================
+``entry``    Code address, including its Thumb bit
+``got``      Data base to install in the PIC base register before
+             branching
+===========  ==============================================================
+
+Building those descriptors is most of what relocation does.  Because
+each one names its own base, a pointer handed to the base firmware
+carries everything needed to call back into the module later, from any
+thread.
+
+A module links against nothing.  libc and everything else are undefined
+imports, resolved at load time against the globally registered symbols
+first, then any shared libraries the module names, then the symbol table
+``exec()`` supplied.
+
+Placement
+---------
+
+The loader asks the filesystem where the file lies on its media.  Two
+mechanisms exist and they are not interchangeable:
+
+* ``XIPFSIOC_PIN`` is for a filesystem that can move a file's blocks.  It
+  returns an address together with a pin that holds the extent still, and
+  the pin is given back with ``XIPFSIOC_UNPIN`` when the module is
+  unloaded.  :doc:`XIPFS <filesystem/xipfs>` is the one in tree.
+
+* ``FIOC_XIPBASE`` is for a filesystem whose layout never changes, which
+  has nothing to hold and answers with a bare address.  ROMFS and TMPFS
+  are those.
+
+The pin is asked for first, because a filesystem that needs one is not
+safe without it.  The loader asks for a pin only if it can hold one,
+which is the flat build, or the pin would stay for ever.
+
+A filesystem that answers neither is still usable.  The loader then
+copies the text to RAM, as it does for any other module.  The module
+loses the shared text and the flash saving, but it runs.
+
+The writable segment is allocated and copied per instance, and a pool of
+function descriptors is reserved behind it for the relocations that ask
+the loader to manufacture one.  When the task starts,
+``up_initial_state()`` installs the object's data base -- ``DT_PLTGOT``,
+or the GOT immediately after ``PT_DYNAMIC`` in an object with no
+imports -- into the PIC base register.
+
+Shared libraries
+----------------
+
+A module may name shared libraries in ``DT_NEEDED``.  The loader loads
+each one during relocation, through ``libelf_insert()`` as ``dlopen()``
+does, and then binds the module's undefined symbols against that
+library's exports.  ``CONFIG_LIBC_ELF_MAXDEPEND`` caps how many one module
+may name, and a module that names more is refused.  With
+``CONFIG_ARCH_ADDRENV`` a module carrying ``DT_NEEDED`` is refused, because
+the library would not be in the address space of the program.
+
+Libraries are found the way ``dlopen()`` finds them: an absolute path is
+used as given, and a bare name is searched for along ``LD_LIBRARY_PATH``,
+which needs ``CONFIG_LIBC_ENVPATH`` and is seeded from
+``CONFIG_LDPATH_INITIAL``.
+
+A library lands in the module registry, which holds one instance per
+name, so its data is shared by everything that opens it.  A module
+started with ``exec()`` is different: that path loads a fresh copy each
+time, so two running instances of one module have separate data while
+sharing one copy of the text in flash.
+
+Comparison with NXFLAT and PIC ELF
+==================================
+
+All three run position independent code from flash on a target with no
+MMU, and all three give several instances of one module a shared
+``.text`` with private ``.data``.  They differ in what a *pointer* can
+express and in what the toolchain has to provide.
+
+=========================  ==============  ==============  =============
+Property                   NXFLAT          PIC ELF         FDPIC
+=========================  ==============  ==============  =============
+Format                     NuttX only      ELF             ELF
+Extra build tools          yes             none            linker
+Data base per              task            task            object
+Shared libraries           no              no              yes
+Foreign-thread callback    no              no              yes
+Instruction set            ARM, Thumb-2    unrestricted    Thumb-2 only
+=========================  ==============  ==============  =============
+
+:ref:`NXFLAT <nxflat>` is a NuttX-specific format.  A module imports
+symbols from the base firmware but cannot export any, so shared
+libraries are not possible, and the build needs ``mknxflat`` to generate
+a thunk, ``ldnxflat`` to link, and one of the ``binfmt/libnxflat`` linker
+scripts to place the sections.
+
+**PIC ELF** needs no extra tools.  With ``CONFIG_PIC`` the ELF loader
+allocates the writable sections separately and, when the filesystem
+answers ``FIOC_XIPBASE``, leaves the read-only ones on the media.  Two
+limits follow from having one base register per task: a shared object is
+loaded as a single allocation, because the distance between its text and
+its data is compiled into it, and the data base is installed once per
+task, so every object in a task shares one.
+
+**FDPIC** pays for its descriptors with an ``arm-uclinuxfdpiceabi``
+linker, and gets back the two things a single register
+cannot express.  A task or pthread that a module starts inherits the
+module's D-Space, so a register would be enough there; a work queue
+worker was created at boot and carries no module base, and a descriptor
+supplies one, which is how ``SIGEV_THREAD`` notifications reach module
+code.
+
+Requirements
+============
+
+**An ARM Thumb-2 core.**  The boundary is the instruction set, not the
+core profile: GCC rejects FDPIC in Thumb-1 mode.
+
+=========================  ==========================  =====
+Core                       Architecture                FDPIC
+=========================  ==========================  =====
+Cortex-M3 / M4 / M7        ARMv7-M / ARMv7E-M          yes
+Cortex-M33                 ARMv8-M Mainline            yes
+Cortex-M0 / M0+ / M23      ARMv6-M / ARMv8-M Baseline  no
+=========================  ==========================  =====
+
+RISC-V has no FDPIC ABI -- the psABI addendum is an unmerged proposal and
+no ``EI_OSABI`` value is assigned -- so a RISC-V target cannot use this.
+
+**Flash that is memory mapped and executable**, exposed by a filesystem
+that answers ``XIPFSIOC_PIN`` or ``FIOC_XIPBASE``.  This is what gives
+execute in place.  Without it the module still loads, but from RAM.
+
+**An FDPIC linker.**  A stock ``arm-none-eabi`` GCC compiles correct
+FDPIC code for both C and C++.  Its assembler accepts the relocations that
+code produces in FDPIC mode only: GCC 14 and later select that mode for
+``-mfdpic``, and for an older GCC the build passes ``-Wa,--fdpic``.  Only
+``arm-uclinuxfdpiceabi`` binutils carry the ``armelf_linux_fdpiceabi``
+emulation that the link needs, and ``arm-none-eabi-ld`` rejects it.
+
+No distribution packages that target, so build binutils for it -- which
+takes about a minute and needs nothing else::
+
+  configure --target=arm-uclinuxfdpiceabi --prefix=$HOME/fdpic \
+      --disable-nls --disable-werror
+  make && make install
+  export PATH=$HOME/fdpic/bin:$PATH
+
+An FDPIC GCC is not needed.
+
+**The base firmware must reserve r9.**  It is not enough for the module
+to be well behaved: a firmware routine calling back into module code
+arrives with the module's data base in r9 only if the compiler was never
+free to allocate that register elsewhere.  ``CONFIG_FDPIC`` selects
+``CONFIG_PIC``, under which ``arch/arm/src/common/Toolchain.defs`` adds
+``--fixed-r9``; see :ref:`nxflat` for why it goes into ``ARCHCFLAGS``
+rather than ``CFLAGS`` and how to check that it arrived.
+
+Configuration
+=============
+
+``CONFIG_FDPIC`` lives under ``CONFIG_ELF``.  A working configuration
+also needs a symbol table for modules to import from and a filesystem
+that can expose its media::
+
+  CONFIG_ELF=y
+  CONFIG_FDPIC=y
+  CONFIG_LIBC_EXECFUNCS=y
+  CONFIG_EXECFUNCS_HAVE_SYMTAB=y
+  CONFIG_EXECFUNCS_SYSTEM_SYMTAB=y
+  CONFIG_FS_XIPFS=y
+
+``crt0`` runs the constructors of a module only with
+``CONFIG_HAVE_CXXINITIALIZE``.
+
+Shared libraries need three more.  A library resolves its own imports
+against the table of ``CONFIG_LIBC_ELF_HAVE_SYMTAB``, and the last two let
+a library be named rather than spelled out as an absolute path::
+
+  CONFIG_LIBC_ELF_HAVE_SYMTAB=y
+  CONFIG_LIBC_ENVPATH=y
+  CONFIG_LDPATH_INITIAL="/mnt/xipfs"
+
+``dlopen()`` needs ``CONFIG_LIBC_DLFCN`` too.
+
+Only the make build generates the table of
+``CONFIG_EXECFUNCS_SYSTEM_SYMTAB``.  A CMake configuration needs a symbol

Review Comment:
   ok, i will do in separate pr



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to