Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,13 @@ config ARCH_HAVE_ELF_EXECUTABLE
bool
default n

config ARCH_HAVE_ELF_FDPIC
bool
default n
---help---
The architecture has a PIC base register and the ELF relocations
that an FDPIC object uses.

config ARCH_HAVE_TRUSTZONE
bool
default n
Expand Down
2 changes: 2 additions & 0 deletions arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1096,6 +1096,7 @@ config ARCH_ARMV7M
default n
select ARCH_HAVE_CPUINFO
select ARCH_HAVE_DEBUG
select ARCH_HAVE_ELF_FDPIC
select ARCH_HAVE_PERF_EVENTS

config ARCH_CORTEXM3
Expand Down Expand Up @@ -1245,6 +1246,7 @@ config ARCH_ARMV8M
default n
select ARCH_HAVE_CPUINFO
select ARCH_HAVE_DEBUG
select ARCH_HAVE_ELF_FDPIC
select ARCH_HAVE_PERF_EVENTS

config ARCH_CORTEXM23
Expand Down
39 changes: 39 additions & 0 deletions arch/arm/include/arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,45 @@ do { \
); \
} while (0)

#ifdef CONFIG_FDPIC

/****************************************************************************
* Name: up_fdpic_invoke
*
* Description:
* Call a module entry point with the module data base in the PIC base
* register. Put the caller data base back after the call.
*
* Input Parameters:
* arg - The one word argument, passed in r0.
* entry - The code address to enter.
* got - The module data base to install.
*
****************************************************************************/

static inline void up_fdpic_invoke(uintptr_t arg, uintptr_t entry,
uintptr_t got)
{
register uintptr_t r0v __asm__ ("r0") = arg;

/* arg is already in r0. r4 goes on the stack with the PIC register to
* keep the push aligned to 8 bytes.
*/

__asm__ __volatile__
(
"push {r4, " PIC_REG_STRING "}\n" /* Save the caller's base */
"mov " PIC_REG_STRING ", %[got]\n" /* Install the module's base */
"blx %[entry]\n" /* Enter the module */
"pop {r4, " PIC_REG_STRING "}\n" /* Restore the caller's base */
: "+r" (r0v)
: [entry] "r" (entry), [got] "r" (got)
: "r1", "r2", "r3", "r12", "lr", "cc", "memory"
);
}

#endif /* CONFIG_FDPIC */

#endif /* CONFIG_PIC */

#ifdef CONFIG_ARCH_ADDRENV
Expand Down
12 changes: 12 additions & 0 deletions arch/arm/include/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,18 @@
#define R_ARM_THM_TLS_DESCSEQ16 129 /* Thumb16 */
#define R_ARM_THM_TLS_DESCSEQ32 130 /* Thumb32 */

/* FDPIC relocations. Values from the ARM FDPIC ABI as implemented by
* binutils (include/elf/arm.h).
*/

#define R_ARM_GOTFUNCDESC 161 /* Data GOT entry holding a descriptor */
#define R_ARM_GOTOFFFUNCDESC 162 /* Data GOT-relative descriptor */
#define R_ARM_FUNCDESC 163 /* Data Address of a descriptor */
#define R_ARM_FUNCDESC_VALUE 164 /* Data The descriptor itself: {code, GOT} */
#define R_ARM_TLS_GD32_FDPIC 165 /* Data */
#define R_ARM_TLS_LDM32_FDPIC 166 /* Data */
#define R_ARM_TLS_IE32_FDPIC 167 /* Data */

/* Processor specific values for the Phdr p_type field. */

#define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */
Expand Down
66 changes: 58 additions & 8 deletions arch/arm/src/cmake/elf.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,67 @@ nuttx_mod_compile_options(-fvisibility=hidden -mlong-calls)
nuttx_elf_compile_options_ifdef(CONFIG_UNWINDER_ARM -fno-unwind-tables
-fno-asynchronous-unwind-tables)

# An ELF module needs r9 as its PIC base, so it must not also have the register
# fixed: GCC rejects that pair with "unable to use 'r9' for PIC register". This
# mirrors CELFFLAGS in common/Toolchain.defs, which filters --fixed-r9 back out
# of the inherited CFLAGS for the same reason.
# -fno-use-cxa-atexit, because the default registers each static object's
# destructor with __cxa_atexit(dtor, obj, &__dso_handle), and __dso_handle comes
# from crtbegin, which a module does not link. Turning it off also puts the
# destructors in .fini_array, which is where the loader looks for them when the
# module is unloaded. This mirrors CXXELFFLAGS in common/Toolchain.defs.

nuttx_elf_compile_options_ifdef(CONFIG_PIC -mpic-register=r9)
nuttx_elf_compile_options(-fno-use-cxa-atexit)

nuttx_elf_link_options_ifdef(
CONFIG_PIC --unresolved-symbols=ignore-in-object-files --emit-relocs)
if(CONFIG_FDPIC)

nuttx_elf_link_options_ifdef(CONFIG_BINFMT_ELF_RELOCATABLE -r)
# An FDPIC module is a shared object whose two segments the loader places
# independently. The stock compiler emits correct FDPIC objects for both C
# and C++, so only the link needs the arm-uclinuxfdpiceabi linker: the stock
# one carries the armelf emulation alone and would turn every import into a
# jump slot where the ABI wants a function descriptor.

if(NOT FDPIC_CROSSDEV)
set(FDPIC_CROSSDEV arm-uclinuxfdpiceabi-)
endif()

# Say which linker is missing rather than failing later with a command that
# cannot be run.

find_program(FDPIC_LD "${FDPIC_CROSSDEV}ld")

if(NOT FDPIC_LD)
message(
FATAL_ERROR
"CONFIG_FDPIC needs ${FDPIC_CROSSDEV}ld, which is not on PATH. "
"It is in the NuttX CI image, and tools/ci/docker/linux/Dockerfile "
"shows how it is built. Set FDPIC_CROSSDEV to use a different prefix")
endif()

set(CMAKE_ELF_LD
"${FDPIC_LD}"
CACHE INTERNAL "Linker for FDPIC modules")

nuttx_elf_compile_options(-mfdpic -fPIC -Wa,--noexecstack)

nuttx_elf_link_options(-m armelf_linux_fdpiceabi -shared -z now)

else()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add if CONFIG_PIC and remove ifdef suffix at line 65 and 67


# An ELF module needs r9 as its PIC base, so it must not also have the
# register fixed: GCC rejects that pair with "unable to use 'r9' for PIC
# register". This mirrors CELFFLAGS in common/Toolchain.defs, which filters
# --fixed-r9 back out of the inherited CFLAGS for the same reason.

nuttx_elf_compile_options_ifdef(CONFIG_PIC -mpic-register=r9)

nuttx_elf_link_options_ifdef(
CONFIG_PIC --unresolved-symbols=ignore-in-object-files --emit-relocs)

endif()

# Not with CONFIG_PIC: there the module is linked as an executable, which is
# what common/Toolchain.defs does too.

if(CONFIG_BINFMT_ELF_RELOCATABLE AND NOT CONFIG_PIC)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why need check pic

nuttx_elf_link_options(-r)
endif()

nuttx_mod_link_options(-r)

Expand Down
42 changes: 42 additions & 0 deletions arch/arm/src/common/Toolchain.defs
Original file line number Diff line number Diff line change
Expand Up @@ -633,16 +633,58 @@ CELFFLAGS = $(filter-out --fixed-r9,$(CFLAGS)) -fvisibility=hidden \
CXXELFFLAGS = $(filter-out --fixed-r9,$(CXXFLAGS)) -fvisibility=hidden \
-mlong-calls

# -fno-use-cxa-atexit, because the default registers each static object's
# destructor with __cxa_atexit(dtor, obj, &__dso_handle), and __dso_handle
# comes from crtbegin, which a module does not link. Turning it off also
# puts the destructors in .fini_array, which is where the loader looks for
# them when the module is unloaded.

CXXELFFLAGS += -fno-use-cxa-atexit

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need modify cmakefile and other arch


ifeq ($(CONFIG_PIC),y)
# ARCHCFLAGS, not CFLAGS: board Make.defs reassign CFLAGS with ':='
# after including this file, which would discard the flag.

ARCHCFLAGS += --fixed-r9

ifeq ($(CONFIG_FDPIC),y)
# An FDPIC module is a shared object whose two segments the loader places
# independently. The stock compiler emits correct FDPIC objects for both C
# and C++, so only the link needs the arm-uclinuxfdpiceabi linker: the
# stock one carries the armelf emulation alone and would turn every import
# into a jump slot where the ABI wants a function descriptor.

FDPIC_CROSSDEV ?= arm-uclinuxfdpiceabi-
MODULELD = $(FDPIC_CROSSDEV)ld

# Say which linker is missing rather than letting make report a command it
# cannot run. The report is deferred to the link itself rather than made
# here, so that a tree configured for FDPIC on a host without the linker can
# still be cleaned and reconfigured.

FDPIC_LD_FOUND := $(shell command -v $(MODULELD) 2> /dev/null)

ifeq ($(FDPIC_LD_FOUND),)
FDPIC_NO_LD_MSG = CONFIG_FDPIC needs $(FDPIC_CROSSDEV)ld, which is not \
on PATH. It is in the NuttX CI image, and \
tools/ci/docker/linux/Dockerfile shows how it is built. Set \
FDPIC_CROSSDEV to use a different prefix.

MODULELD = $(SHELL) -c 'echo "ERROR: $(FDPIC_NO_LD_MSG)" 1>&2; exit 1' --
endif

CELFFLAGS += -mfdpic -fPIC -Wa,--noexecstack

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not reference PICFLAGS

CXXELFFLAGS += -mfdpic -fPIC -Wa,--noexecstack

LDELFFLAGS += -m armelf_linux_fdpiceabi -shared -z now
else
CELFFLAGS += $(PICFLAGS) -mpic-register=r9
CXXELFFLAGS += $(PICFLAGS) -mpic-register=r9

# Generate an executable elf, need to ignore undefined symbols
LDELFFLAGS += --unresolved-symbols=ignore-in-object-files --emit-relocs
endif

else
ifneq ($(CONFIG_BINFMT_ELF_EXECUTABLE),y)
LDELFFLAGS += -r
Expand Down
32 changes: 32 additions & 0 deletions binfmt/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,38 @@ config ELF_STACKSIZE
default DEFAULT_TASK_STACKSIZE
---help---
This is the default stack size that will be used when starting ELF binaries.

config FDPIC
bool "FDPIC modules"
default n
select PIC
depends on ARCH_HAVE_ELF_FDPIC
---help---
Load ELF modules built for the FDPIC ABI.

An FDPIC module places its read-only and writable segments
independently, so its text can be executed directly out of flash
while only the writable segment is copied to RAM, once per running
instance. A filesystem that can show its media, such as XIPFS or
ROMFS, gives that result. On any other filesystem the loader copies
the text to RAM, and the module runs but shares nothing.

Building a module needs an arm-uclinuxfdpiceabi linker. The stock
arm-none-eabi compiler emits correct FDPIC objects for both C and
C++, so only the link needs it.

What this adds over the position independent ELF support already
present is a function pointer that carries its own data base, as a
two word descriptor rather than a bare code address. That is what
lets a module be called back on a thread it did not create, such as
the work queue worker that runs a SIGEV_THREAD notification.

Selecting this makes ten libc and sched entry points that can
accept a callback from a module resolve such a descriptor before
storing or branching to it. Each costs a register read and a
branch on a path that is not hot.

FDPIC is specified only for ARM Thumb-2.
endif
endif

Expand Down
12 changes: 10 additions & 2 deletions cmake/nuttx_add_application.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,15 @@ function(nuttx_add_application)
if(TARGET STARTUP_OBJS)
add_dependencies(${TARGET} STARTUP_OBJS)
endif()
if(NOT "${CMAKE_LD}" MATCHES "gcc$")
# A module may need a different linker from the one that links the
# firmware: an FDPIC module does, because the stock linker cannot
# produce one. CMAKE_ELF_LD is that linker, and it is the ordinary one
# unless the architecture says otherwise.

if(NOT CMAKE_ELF_LD)
set(CMAKE_ELF_LD ${CMAKE_LD})
endif()
if(NOT "${CMAKE_ELF_LD}" MATCHES "gcc$")
set(USE_LINKER True)
endif()
if(STACKSIZE)
Expand Down Expand Up @@ -179,7 +187,7 @@ function(nuttx_add_application)
POST_BUILD
COMMAND
# add default link option
${CMAKE_LD} -T ${NUTTX_BINARY_DIR}/gnu-elf.ld
${CMAKE_ELF_LD} -T ${NUTTX_BINARY_DIR}/gnu-elf.ld
# add global MOD link option if dynlib link
$<$<BOOL:${DYNLIB_ELF_MODE}>:$<TARGET_PROPERTY:nuttx_global,NUTTX_MOD_APP_LINK_OPTIONS>>
# add global ELF link option if m&kernel link
Expand Down
11 changes: 11 additions & 0 deletions fs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,17 @@ config PSEUDOFS_ATTRIBUTES
Enable support for attributes(e.g. mode, uid, gid and time)
in the pseudo file system.

config FS_PIN
bool
default n
---help---
Selected by a file system that can pin a file's blocks in place and
hand out their media address, so that a module's read-only segment
can be executed where it already lies instead of being copied.

The pin is held for as long as the module is loaded and given back
when it is unloaded.

config FS_PERMISSION
bool "Enable UNIX Filesystem Permission Support"
default n
Expand Down
1 change: 1 addition & 0 deletions fs/xipfs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ config FS_XIPFS
bool "XIPFS contiguous execute-in-place file system"
default n
depends on !DISABLE_MOUNTPOINT && MTD
select FS_PIN
---help---
Enable support for XIPFS, a file system that stores each file as a
single physically contiguous, erase-block aligned extent on memory
Expand Down
7 changes: 7 additions & 0 deletions include/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@
#define ELFOSABI_MODESTO 11 /* Novell Modesto. */
#define ELFOSABI_OPENBSD 12 /* OpenBSD. */
#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */
#define ELFOSABI_ARM_FDPIC 65 /* ARM FDPIC */
#define ELFOSABI_ARM 97 /* ARM */
#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */

Expand Down Expand Up @@ -278,6 +279,12 @@
#define DT_TEXTREL 22 /* d_un=ignored */
#define DT_JMPREL 23 /* d_un=d_ptr */
#define DT_BINDNOW 24 /* d_un=ignored */
#define DT_INIT_ARRAY 25 /* d_un=d_ptr */
#define DT_FINI_ARRAY 26 /* d_un=d_ptr */
#define DT_INIT_ARRAYSZ 27 /* d_un=d_val */
#define DT_FINI_ARRAYSZ 28 /* d_un=d_val */
#define DT_PREINIT_ARRAY 32 /* d_un=d_ptr */
#define DT_PREINIT_ARRAYSZ 33 /* d_un=d_val */
#define DT_LOPROC 0x70000000 /* d_un=unspecified */
#define DT_HIPROC 0x7fffffff /* d_un= unspecified */

Expand Down
Loading
Loading