Add support for the loading of ET_DYN objects

* libs/libc/machine/arm/armv7-m/arch_elf.c
      - Fix cast of error message parameters

    * build-globals.sh
      - Build the modlib_globals.S file used to resolve symbols when dynamically loading

    * libs/libc/modlib/Make.defs
      - Build modlib_globals.S for all targets

    * libs/libc/modlib/modlib_load.c
      - Calculate sizes and text/data addresses based on program headers rather than section headers
      - Handle objects with no program headers

    * libs/libc/modlib/modlib_bind.c
      - Call modlib_readsym with pointer to symbol table
      - Add modlib_relocatedyn to manage relocation of symbols with shared object (ET_DYN)
      - Differentiate between ET_REL and ET_DYN objects
      - Use arch independent symbol ELF_R_SYM
      - Cast sizes to avoid warnings

    * libs/libc/modlib/modlib_load.c
      - Cast sizes to avoid warnings

    * include/elf.h
      - Add definitions that may be found in shared objects

    * include/nuttx/lib/modlib.h
      - Add parameter to modlib_readsym prototype
      - Add prototypes for:
        - modlib_insertsymtab
        - modlib_findglobal
      - Define Elf_Dyn and Elf_Off according to the elf architecture
      - Add fields to mod_loadifno_s:
        - Program headers
        - Exported symbols
        - Data section address
        - Padding requirement
        - Section index for dynamic symbol table
        - Number of symbols exported
      - Add prottotype for modlib_freesymtab

    * libs/libc/dlfcn/lib_dlclose.c
      - Free the symbol table when the dll is closed

    * libs/libc/dlfcn/lib_dlopen.c
      - Add dump of program headers to debug routine
      - Differentiate between ET_REL and ET_DYN objects

    * libs/libc/machine/arm/armv7-m/arch_elf.c
      - Add handling of R_ARM_RELATIVE and R_ARM_JUMP slot relocation types

    * libs/libc/modlib/modlib_loadshdrs.c
      - Rename modlib_loadshdrs.c to modlib_loadhdrs.c
      - Rename modlib_loadshdrs to modlib_loadhdrs
      - Add code to load program headers

    * libs/libc/modlib/modlib_symbols.c
      - Define entry point structure
      - Add offset parameter to modlib_symname() and use to find symbol names
      - Add symtab section header parameter to modlib_readsym()
      - Add offset parameter to modlib_symvalue() to locate symbol names
      - Add modlib_insertsyntab() to create a symbol table for exporting and resolution
      - Add findEP() to resolve a symbol in the modlib_global table
      - Add modlib_findglobal() to find symbol in the modlib_global table
      - Add modlib_freesymtab() to free the symbol table

    * libs/libc/modlib/modlib_uninit.c
      - Free header and sections from a module_loadinfo_s control block

    * libs/libc/modlib/modlib_verify.c
      - Handle ET_DYN shared objects

    * libs/libc/modlib/modlib_globals.S
      - Multi-target global table
      - Define library APIs that may be resolved when loading a shared object
This commit is contained in:
Neale Ferguson
2022-09-26 16:22:03 +10:00
committed by Alan Carvalho de Assis
parent f0107683d5
commit fec789047a
18 changed files with 4918 additions and 140 deletions
+149
View File
@@ -0,0 +1,149 @@
#!/bin/bash
#
# Script to create modlib_global.S which contains a structure define
# the API names and addresses we will export for resolving symbols in
# dynamic loaded shared objects. Typically these are libc APIs.
#
# Find an entrypoint using a binary search
#
findEP()
{
CHECK=$1
SIZE=${#SYM[@]}
L=0
R=$((SIZE - 1))
while [ ${L} -le ${R} ]
do
T=$(( L + R ))
M=$(( T / 2 ))
N=$(( T % 2 ))
M=$(( M - N ))
if [ ${SYM[${M}]} \< ${CHECK} ]; then
L=$(( M + 1 ))
elif [ ${SYM[${M}]} = ${CHECK} ]; then
return 1
else
R=$(( M - 1 ))
fi
done
return 0
}
#
# Extract entrypoints from a library after applying a filter to
# exclude those we aren't interested in.
#
getEP()
{
for ((i = 0; i < ${#OBJ[@]}; i++))
do
FUNCS=`${NM} -g --defined-only ../staging/${OBJ[$i]} | awk '{print $3}' | sort | grep -Ev ${FILTER}`
FUNC=(${FUNCS})
for ((j = 0; j < ${#FUNC[@]}; j++))
do
findEP ${FUNC[$j]}
if [ $? -eq 1 ]; then
EP[${I_EP}]=${FUNC[$j]}
I_EP=$((I_EP + 1))
fi
done
done
}
#
# Symbols to ignore within the NuttX libraries
#
FILTER="^lib_low|^FUNCTION|^STUB|^__start|^_vect|^arm_|^arp_|^bch|^binfmt|^blake|^block_|^cdcacm|^chksum|^clock_|^close_|^crypto_|^devif_|^devnull|^devuran|^devzero|^emerg|^epoll_|^elf_|^_dbgR|^dq_|^env_|^file_|^files_|^fs_|^ftl_|^g_|^get_|^group_|^global|^hcom|^i2c_|^inode_|^iob_|^irq_|^kmm_|^lfs_|^lib_|^local_|^mm_|^modlib_|^mpu_|^mq_|^nGlobals|^net_|^netdev_|^nx|^pipecommon|^posix_spawn_file|^psock_|^ramlog|^rammap|^readline_|^register_|^sched_|^sockfd|^spawn_|^sq_|^stm32|^symtab_|^syslog_|^syslogstream|^task_|^tcp_|^timer_|^uart_|^ub[12]|^udp_|^umm_|^umount|^unload_|^unregister|^up_|^usb|^usrsock_|^watchdog|^wd_"
#
# Extract symbols from the runtime
#
SYMS=`${NM} ../nuttx | awk '{print $3}' | sort | grep -Ev ${FILTER}`
SYM=(${SYMS})
GLOBALS="../libs/libc/modlib/modlib_globals.S"
I_EP=0
#
# Libraries to be searched
#
OBJS="libsched.a libdrivers.a libconfigs.a libstubs.a libkc.a libkmm.a libkarch.a libpass1.a libnet.a libcrypto.a libfs.a libbinfmt.a libxx.a libuc.a libumm.a libuarch.a libapps.a"
OBJ=(${OBJS})
#
# Perform the extraction from the libraries
#
getEP
EPS=`printf '%s\n' "${EP[@]}" | sort -u`
EP=(${EPS})
#
# Generate the modlib_xxxx_globals.S file
#
GLOBALS="libs/libc/modlib/modlib_${arch}_globals.S"
cat >${GLOBALS} <<__EOF__
#if __SIZEOF_POINTER__ == 8
.macro globalEntry index, ep
.weak \p
.quad .L\index
.quad \ep
.endm
# define ALIGN 8
#else
.macro globalEntry index, ep
.weak \ep
.long .L\index
.long \ep
.endm
# define ALIGN 4
#endif
#ifdef __ARM_ARCH_ISA_THUMB2
# ifdef __ARM_ARCH_7M__
.arch armv7e-m
# elif defined ___ARM_ARCH 8
.arch armv8-m.base
#endif
#ifdef __ARM_ASM_SYNTAX_UNIFIED__
.syntax unified
#endif
.thumb
#endif
.data
.align ALIGN
.global globalNames
globalNames:
__EOF__
for ((i = 0; i < ${#EP[@]}; i++))
do
echo ".L${i}: .string \"${EP[$i]}\"" >>${GLOBALS}
done
cat >>${GLOBALS} <<__EOF__
.size globalNames, . - globalNames
.align ${ALIGN}
.global nGlobals
.type nGlobals, "object"
nGlobals:
.word ${#EP[@]}
.size nGlobals, . - nGlobals
.align ${ALIGN}
.global globalTable
.type globalTable, "object"
globalTable:
__EOF__
for ((i = 0; i < ${#EP[@]}; i++))
do
echo " globalEntry ${i}, ${EP[$i]}" >>${GLOBALS}
done
cat >>${GLOBALS} <<__EOF__
.size globalTable, . - globalTable
__EOF__
done
echo "${#EP[@]} symbols defined"
+11
View File
@@ -214,6 +214,17 @@
#define PT_NOTE 4
#define PT_SHLIB 5
#define PT_PHDR 6
/* Processor specific values for the Phdr p_type field. */
#define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */
/* GCC specific */
#define PT_GNU_EH_FRAME 0x6474e550 /* GCC exception handler frame */
#define PT_GNU_STACK 0x6474e551 /* Stack executability */
#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7fffffff
+27
View File
@@ -87,6 +87,14 @@
* Public Types
****************************************************************************/
#ifdef CONFIG_LIBC_ARCH_ELF_64BIT
typedef Elf64_Off Elf_Off;
typedef Elf64_Dyn Elf_Dyn;
#else
typedef Elf32_Off Elf_Off;
typedef Elf32_Dyn Elf_Dyn;
#endif
/* This is the type of the function that is called to uninitialize the
* the loaded module. This may mean, for example, un-registering a device
* driver. If the module is successfully uninitialized, its memory will be
@@ -198,13 +206,19 @@ struct mod_loadinfo_s
size_t dataalign; /* Necessary alignment of .bss/.text */
off_t filelen; /* Length of the entire module file */
Elf_Ehdr ehdr; /* Buffered module file header */
FAR Elf_Phdr *phdr; /* Buffered module program headers */
FAR Elf_Shdr *shdr; /* Buffered module section headers */
FAR void *exported; /* Module exports */
uint8_t *iobuffer; /* File I/O buffer */
uintptr_t datasec; /* ET_DYN - data area start from Phdr */
uintptr_t segpad; /* Padding between text and data */
uint16_t symtabidx; /* Symbol table section index */
uint16_t strtabidx; /* String table section index */
uint16_t dsymtabidx; /* Dynamic symbol table section index */
uint16_t buflen; /* size of iobuffer[] */
int filfd; /* Descriptor for the file being loaded */
int nexports; /* ET_DYN - Number of symbols exported */
};
/****************************************************************************
@@ -530,4 +544,17 @@ int modlib_registry_verify(FAR struct module_s *modp);
int modlib_registry_foreach(mod_callback_t callback, FAR void *arg);
/****************************************************************************
* Name: modlib_freesymtab
*
* Description:
* Free a symbol table for the current module.
*
* Input Parameters:
* modp - Module state descriptor
*
****************************************************************************/
void modlib_freesymtab(FAR struct module_s *modp);
#endif /* __INCLUDE_NUTTX_LIB_MODLIB_H */
+4
View File
@@ -142,6 +142,10 @@ static inline int dlremove(FAR void *handle)
#endif
}
/* Free the modules exported symmbols table */
modlib_freesymtab(modp);
/* Remove the module from the registry */
ret = modlib_registry_del(modp);
+28 -4
View File
@@ -31,12 +31,14 @@
#include <assert.h>
#include <debug.h>
#include <errno.h>
#include <unistd.h>
#include <nuttx/envpath.h>
#include <nuttx/module.h>
#include <nuttx/lib/modlib.h>
#include "libc.h"
#include "debug.h"
/****************************************************************************
* Private Functions
@@ -98,6 +100,23 @@ static void dldump_loadinfo(FAR struct mod_loadinfo_s *loadinfo)
binfo(" sh_entsize: %d\n", shdr->sh_entsize);
}
}
if (loadinfo->phdr && loadinfo->ehdr.e_phnum > 0)
{
for (i = 0; i < loadinfo->ehdr.e_phnum; i++)
{
FAR Elf32_Phdr *phdr = &loadinfo->phdr[i];
binfo("Program Header %d:\n", i);
binfo(" p_type: %08x\n", phdr->p_type);
binfo(" p_offset: %08x\n", phdr->p_offset);
binfo(" p_vaddr: %08x\n", phdr->p_vaddr);
binfo(" p_paddr: %08x\n", phdr->p_paddr);
binfo(" p_filesz: %08x\n", phdr->p_filesz);
binfo(" p_memsz: %08x\n", phdr->p_memsz);
binfo(" p_flags: %08x\n", phdr->p_flags);
binfo(" p_align: %08x\n", phdr->p_align);
}
}
}
#else
# define dldump_loadinfo(i)
@@ -110,6 +129,7 @@ static void dldump_loadinfo(FAR struct mod_loadinfo_s *loadinfo)
#ifdef CONFIG_BUILD_PROTECTED
#ifdef CONFIG_MODLIB_DUMPBUFFER
#define MIN(a,b) ((a) < (b) ? (a) : (b))
static void dldump_initializer(mod_initializer_t initializer,
FAR struct mod_loadinfo_s *loadinfo)
{
@@ -187,6 +207,7 @@ static inline FAR void *dlinsert(FAR const char *filename)
binfo("Failed to initialize for load of ELF program: %d\n", ret);
goto errout_with_loadinfo;
}
memset(modp, 0, sizeof(*modp));
/* Load the program binary */
@@ -227,11 +248,14 @@ static inline FAR void *dlinsert(FAR const char *filename)
/* Call the module initializer */
ret = initializer(&modp->modinfo);
if (ret < 0)
if (loadinfo.ehdr.e_type == ET_REL)
{
binfo("Failed to initialize the module: %d\n", ret);
goto errout_with_load;
ret = initializer(&modp->modinfo);
if (ret < 0)
{
binfo("Failed to initialize the module: %d\n", ret);
goto errout_with_load;
}
}
/* Add the new module entry to the registry */
+11 -1
View File
@@ -122,7 +122,8 @@ int up_relocate(const Elf32_Rel *rel, const Elf32_Sym *sym, uintptr_t addr)
*/
relotype = ELF32_R_TYPE(rel->r_info);
if (sym == NULL && relotype != R_ARM_NONE && relotype != R_ARM_V4BX)
if (sym == NULL && relotype != R_ARM_NONE && relotype != R_ARM_V4BX &&
relotype != R_ARM_RELATIVE && relotype != R_ARM_JUMP_SLOT)
{
return -EINVAL;
}
@@ -492,6 +493,15 @@ int up_relocate(const Elf32_Rel *rel, const Elf32_Sym *sym, uintptr_t addr)
}
break;
case R_ARM_RELATIVE :
case R_ARM_JUMP_SLOT :
{
binfo("Relocating: RELATIVE/JUMP_SLOT at %p value: %08lx with %08lx\n",
(void *)addr,*(unsigned log *) addr, (unsigned long) sym->st_value);
*(uint32_t *) addr = (uint32_t) sym->st_value;
}
break;
default:
berr("ERROR: Unsupported relocation: %" PRId32 "\n",
ELF32_R_TYPE(rel->r_info));
+4 -2
View File
@@ -23,13 +23,15 @@ ifeq ($(CONFIG_LIBC_MODLIB),y)
# Add the nuttx/lib/modlib.h files to the build
CSRCS += modlib_bind.c modlib_depend.c modlib_init.c modlib_iobuffer.c
CSRCS += modlib_load.c modlib_loadshdrs.c
CSRCS += modlib_load.c modlib_loadhdrs.c
CSRCS += modlib_read.c modlib_registry.c modlib_sections.c
CSRCS += modlib_symbols.c modlib_symtab.c modlib_uninit.c modlib_unload.c
CSRCS += modlib_verify.c
CSRCS += modlib_verify.c
# Add the modlib directory to the build
ASRCS += modlib_globals.S
DEPPATH += --dep-path modlib
VPATH += :modlib
+56 -5
View File
@@ -83,7 +83,7 @@ int modlib_findsymtab(FAR struct mod_loadinfo_s *loadinfo);
****************************************************************************/
int modlib_readsym(FAR struct mod_loadinfo_s *loadinfo, int index,
FAR Elf_Sym *sym);
FAR Elf_Sym *sym, FAR Elf_Shdr *shdr);
/****************************************************************************
* Name: modlib_symvalue
@@ -110,13 +110,64 @@ int modlib_readsym(FAR struct mod_loadinfo_s *loadinfo, int index,
****************************************************************************/
int modlib_symvalue(FAR struct module_s *modp,
FAR struct mod_loadinfo_s *loadinfo, FAR Elf_Sym *sym);
FAR struct mod_loadinfo_s *loadinfo, FAR Elf_Sym *sym,
Elf_Off offset);
/****************************************************************************
* Name: modlib_insertsymtab
*
* Description:
* Insert a symbol table for the current module.
*
* Input Parameters:
* modp - Module state information
* loadinfo - Module load information
* shdr - Symbol table section header
* sym - Symbol table entry
*
* Returned Value:
* 0 (OK) is returned on success and a negated errno is returned on
* failure.
*
* ENOMEM - Symbol undefined and not provided via a symbol table
*
****************************************************************************/
int modlib_insertsymtab(FAR struct module_s *modp,
FAR struct mod_loadinfo_s *loadinfo,
FAR Elf_Shdr *shdr,
FAR Elf_Sym *sym);
/****************************************************************************
* Name: modlib_loadshdrs
* Name: modlib_findglobal
*
* Description:
* Loads section headers into memory.
* Find a symbol in the global symbol table
*
* Input Parameters:
* modp - Module state information
* loadinfo - Module load information
* shdr - Symbol table section header
* sym - Symbol table entry
*
* Returned Value:
* 0 (OK) is returned on success and a negated errno is returned on
* failure.
*
* ENOMEM - Symbol undefined and not provided via a symbol table
*
****************************************************************************/
void *modlib_findglobal(FAR struct module_s *modp,
FAR struct mod_loadinfo_s *loadinfo,
FAR Elf_Shdr *shdr,
FAR Elf_Sym *sym);
/****************************************************************************
* Name: modlib_loadhdrs
*
* Description:
* Loads program and section headers into memory.
*
* Returned Value:
* 0 (OK) is returned on success and a negated errno is returned on
@@ -124,7 +175,7 @@ int modlib_symvalue(FAR struct module_s *modp,
*
****************************************************************************/
int modlib_loadshdrs(FAR struct mod_loadinfo_s *loadinfo);
int modlib_loadhdrs(FAR struct mod_loadinfo_s *loadinfo);
/****************************************************************************
* Name: modlib_findsection
File diff suppressed because it is too large Load Diff
+281 -19
View File
@@ -36,6 +36,14 @@
#include "libc.h"
#include "modlib/modlib.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define I_REL 0 /* Index into relxxx[] arrays for relocations */
#define I_PLT 1 /* ... for PLTs */
#define N_RELS 2 /* Number of relxxx[] indexes */
/****************************************************************************
* Private Types
****************************************************************************/
@@ -51,6 +59,16 @@ typedef struct
int idx;
} Elf_SymCache;
struct
{
int strOff; /* Offset to string table */
int symOff; /* Offset to symbol table */
int lSymTab; /* Size of symbol table */
int relEntSz; /* Size of relocation entry */
int relOff[2]; /* Offset to the relocation section */
int relSz[2]; /* Size of relocation table */
} relData;
/****************************************************************************
* Private Functions
****************************************************************************/
@@ -245,7 +263,8 @@ static int modlib_relocate(FAR struct module_s *modp,
/* Read the symbol table entry into memory */
ret = modlib_readsym(loadinfo, symidx, sym);
ret = modlib_symvalue(modp, loadinfo, sym,
loadinfo->shdr[loadinfo->strtabidx].sh_offset);
if (ret < 0)
{
berr("ERROR: Section %d reloc %d: "
@@ -257,7 +276,8 @@ static int modlib_relocate(FAR struct module_s *modp,
/* Get the value of the symbol (in sym.st_value) */
ret = modlib_symvalue(modp, loadinfo, sym);
ret = modlib_symvalue(modp, loadinfo, sym,
loadinfo->shdr[loadinfo->strtabidx].sh_offset);
if (ret < 0)
{
/* The special error -ESRCH is returned only in one condition:
@@ -433,7 +453,8 @@ static int modlib_relocateadd(FAR struct module_s *modp,
/* Read the symbol table entry into memory */
ret = modlib_readsym(loadinfo, symidx, sym);
ret = modlib_readsym(loadinfo, symidx, sym,
&loadinfo->shdr[loadinfo->symtabidx]);
if (ret < 0)
{
berr("ERROR: Section %d reloc %d: "
@@ -445,7 +466,8 @@ static int modlib_relocateadd(FAR struct module_s *modp,
/* Get the value of the symbol (in sym.st_value) */
ret = modlib_symvalue(modp, loadinfo, sym);
ret = modlib_symvalue(modp, loadinfo, sym,
loadinfo->shdr[loadinfo->strtabidx].sh_offset);
if (ret < 0)
{
/* The special error -ESRCH is returned only in one condition:
@@ -519,6 +541,230 @@ static int modlib_relocateadd(FAR struct module_s *modp,
return ret;
}
/****************************************************************************
* Name: modlib_relocatedyn
*
* Description:
* Perform all relocations associated with a dynamic section.
*
* Returned Value:
* 0 (OK) is returned on success and a negated errno is returned on
* failure.
*
****************************************************************************/
static int modlib_relocatedyn(FAR struct module_s *modp,
FAR struct mod_loadinfo_s *loadinfo,
int relidx)
{
FAR Elf_Shdr *shdr = &loadinfo->shdr[relidx];
FAR Elf_Shdr *symhdr;
FAR Elf_Dyn *dyn = NULL;
FAR Elf_Rel *rels = NULL;
FAR Elf_Rel *rel;
FAR Elf_Sym *sym = NULL;
uintptr_t addr;
int ret;
int i;
int idx_rel;
int idx_sym;
dyn = lib_malloc(shdr->sh_size);
ret = modlib_read(loadinfo, (FAR uint8_t *) dyn, shdr->sh_size,
shdr->sh_offset);
if (ret < 0)
{
berr("Failed to read dynamic section header");
return ret;
}
rels = lib_malloc(CONFIG_MODLIB_RELOCATION_BUFFERCOUNT * sizeof(Elf_Rel));
if (!rels)
{
berr("Failed to allocate memory for elf relocation rels\n");
lib_free(dyn);
return -ENOMEM;
}
memset((void *) &relData, 0, sizeof(relData));
for (i = 0; dyn[i].d_tag != DT_NULL; i++)
{
switch (dyn[i].d_tag)
{
case DT_REL :
relData.relOff[I_REL] = dyn[i].d_un.d_val;
break;
case DT_RELSZ :
relData.relSz[I_REL] = dyn[i].d_un.d_val;
break;
case DT_RELENT :
relData.relEntSz = dyn[i].d_un.d_val;
break;
case DT_SYMTAB :
relData.symOff = dyn[i].d_un.d_val;
break;
case DT_STRTAB :
relData.strOff = dyn[i].d_un.d_val;
break;
case DT_JMPREL :
relData.relOff[I_PLT] = dyn[i].d_un.d_val;
break;
case DT_PLTRELSZ :
relData.relSz[I_PLT] = dyn[i].d_un.d_val;
break;
}
}
symhdr = &loadinfo->shdr[loadinfo->dsymtabidx];
sym = lib_malloc(symhdr->sh_size);
if (!sym)
{
berr("Error obtaining storage for dynamic symbol table");
lib_free(rels);
lib_free(dyn);
return -ENOMEM;
}
ret = modlib_read(loadinfo, (uint8_t *) sym, symhdr->sh_size,
symhdr->sh_offset);
if (ret < 0)
{
berr("Error reading dynamic symbol table - %d", ret);
lib_free(sym);
lib_free(rels);
lib_free(dyn);
return ret;
}
relData.lSymTab = relData.strOff - relData.symOff;
for (idx_rel = 0; idx_rel < N_RELS; idx_rel++)
{
if (relData.relOff[idx_rel] == 0)
{
continue;
}
/* Examine each relocation in the .rel.* section. */
ret = OK;
for (i = 0; i < relData.relSz[idx_rel] / relData.relEntSz; i++)
{
/* Process each relocation entry */
rel = &rels[i % CONFIG_MODLIB_RELOCATION_BUFFERCOUNT];
if (!(i % CONFIG_MODLIB_RELOCATION_BUFFERCOUNT))
{
ret = modlib_read(loadinfo, (FAR uint8_t *) rels,
sizeof(Elf_Rel) * CONFIG_MODLIB_RELOCATION_BUFFERCOUNT,
relData.relOff[idx_rel] +
i * sizeof(Elf_Rel));
if (ret < 0)
{
berr("ERROR: Section %d reloc %d:"
"Failed to read relocation entry: %d\n",
relidx, i, ret);
break;
}
}
/* Calculate the relocation address. */
if (rel->r_offset < 0)
{
berr("ERROR: Section %d reloc %d:"
"Relocation address out of range, offset %u\n",
relidx, i, (int) rel->r_offset);
ret = -EINVAL;
lib_free(sym);
lib_free(rels);
lib_free(dyn);
return ret;
}
/* Now perform the architecture-specific relocation */
if ((idx_sym = ELF_R_SYM(rel->r_info)) != 0)
{
if (sym[idx_sym].st_shndx == SHN_UNDEF) /* We have an external reference */
{
void *ep;
ep = modlib_findglobal(modp, loadinfo, symhdr,
&sym[idx_sym]);
if (ep == NULL)
{
berr("ERROR: Unable to resolve addr of ext ref %s\n",
loadinfo->iobuffer);
ret = -EINVAL;
lib_free(sym);
lib_free(rels);
lib_free(dyn);
return ret;
}
addr = rel->r_offset + loadinfo->textalloc;
*(uintptr_t *)addr = (uintptr_t)ep;
}
}
else
{
Elf_Sym dynSym;
addr = rel->r_offset - loadinfo->datasec + loadinfo->datastart;
if ((*(uint32_t *) addr) < loadinfo->datasec)
dynSym.st_value = *(uint32_t *) addr + loadinfo->textalloc;
else
dynSym.st_value = *(uint32_t *) addr -
loadinfo->datasec + loadinfo->datastart;
ret = up_relocate(rel, &dynSym, addr);
}
if (ret < 0)
{
berr("ERROR: Section %d reloc %d: Relocation failed: %d\n",
relidx, i, ret);
lib_free(sym);
lib_free(rels);
lib_free(dyn);
return ret;
}
}
}
/* Iterate through the dynamic symbol table looking for global symbols to
* put in our own symbol table for use with dlgetsym()
*/
/* Relocate the entries in the table */
for (i = 0; i < (symhdr->sh_size / sizeof(Elf_Sym)); i++)
{
Elf_Shdr *s = &loadinfo->shdr[sym[i].st_shndx];
if (sym[i].st_shndx != SHN_UNDEF)
{
if (s->sh_addr < loadinfo->datasec)
sym[i].st_value = sym[i].st_value + loadinfo->textalloc;
else
sym[i].st_value = sym[i].st_value -
loadinfo->datasec + loadinfo->datastart;
}
}
ret = modlib_insertsymtab(modp, loadinfo, symhdr, sym);
lib_free(sym);
lib_free(rels);
lib_free(dyn);
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -578,24 +824,40 @@ int modlib_bind(FAR struct module_s *modp,
continue;
}
/* Make sure that the section is allocated. We can't relocate
* sections that were not loaded into memory.
*/
if ((loadinfo->shdr[infosec].sh_flags & SHF_ALLOC) == 0)
if (loadinfo->ehdr.e_type == ET_DYN)
{
continue;
switch (loadinfo->shdr[i].sh_type)
{
case SHT_DYNAMIC :
ret = modlib_relocatedyn(modp, loadinfo, i);
break;
case SHT_DYNSYM :
loadinfo->dsymtabidx = i;
break;
}
}
/* Process the relocations by type */
if (loadinfo->shdr[i].sh_type == SHT_REL)
else
{
ret = modlib_relocate(modp, loadinfo, i);
}
else if (loadinfo->shdr[i].sh_type == SHT_RELA)
{
ret = modlib_relocateadd(modp, loadinfo, i);
/* Make sure that the section is allocated. We can't relocate
* sections that were not loaded into memory.
*/
if ((loadinfo->shdr[i].sh_flags & SHF_ALLOC) == 0)
{
continue;
}
/* Process the relocations by type */
switch (loadinfo->shdr[i].sh_type)
{
case SHT_REL :
ret = modlib_relocate(modp, loadinfo, i);
break;
case SHT_RELA :
ret = modlib_relocateadd(modp, loadinfo, i);
break;
}
}
if (ret < 0)
File diff suppressed because it is too large Load Diff
+154 -93
View File
@@ -79,36 +79,63 @@ static void modlib_elfsize(struct mod_loadinfo_s *loadinfo)
textsize = 0;
datasize = 0;
for (i = 0; i < loadinfo->ehdr.e_shnum; i++)
if (loadinfo->ehdr.e_phnum > 0)
{
FAR Elf_Shdr *shdr = &loadinfo->shdr[i];
/* SHF_ALLOC indicates that the section requires memory during
* execution.
*/
if ((shdr->sh_flags & SHF_ALLOC) != 0)
for (i = 0; i < loadinfo->ehdr.e_phnum; i++)
{
/* SHF_WRITE indicates that the section address space is write-
* able
*/
if ((shdr->sh_flags & SHF_WRITE) != 0)
FAR Elf_Phdr *phdr = &loadinfo->phdr[i];
FAR void *textaddr = NULL;
if (phdr->p_type == PT_LOAD)
{
datasize = _ALIGN_UP(datasize, shdr->sh_addralign);
datasize += ELF_ALIGNUP(shdr->sh_size);
if (loadinfo->dataalign < shdr->sh_addralign)
if (phdr->p_flags & PF_X)
{
loadinfo->dataalign = shdr->sh_addralign;
textsize += phdr->p_memsz;
textaddr = (void *) phdr->p_vaddr;
}
else
{
datasize += phdr->p_memsz;
loadinfo->datasec = phdr->p_vaddr;
loadinfo->segpad = phdr->p_vaddr -
((uintptr_t) textaddr + textsize);
}
}
else
}
}
else
{
for (i = 0; i < loadinfo->ehdr.e_shnum; i++)
{
FAR Elf_Shdr *shdr = &loadinfo->shdr[i];
/* SHF_ALLOC indicates that the section requires memory during
* execution.
*/
if ((shdr->sh_flags & SHF_ALLOC) != 0)
{
textsize = _ALIGN_UP(textsize, shdr->sh_addralign);
textsize += ELF_ALIGNUP(shdr->sh_size);
if (loadinfo->textalign < shdr->sh_addralign)
/* SHF_WRITE indicates that the section address space is write-
* able
*/
if ((shdr->sh_flags & SHF_WRITE) != 0)
{
loadinfo->textalign = shdr->sh_addralign;
datasize = _ALIGN_UP(datasize, shdr->sh_addralign);
datasize += ELF_ALIGNUP(shdr->sh_size);
if (loadinfo->dataalign < shdr->sh_addralign)
{
loadinfo->dataalign = shdr->sh_addralign;
}
}
else
{
textsize = _ALIGN_UP(textsize, shdr->sh_addralign);
textsize += ELF_ALIGNUP(shdr->sh_size);
if (loadinfo->textalign < shdr->sh_addralign)
{
loadinfo->textalign = shdr->sh_addralign;
}
}
}
}
@@ -141,75 +168,110 @@ static inline int modlib_loadfile(FAR struct mod_loadinfo_s *loadinfo)
int ret;
int i;
/* Read each section into memory that is marked SHF_ALLOC + SHT_NOBITS */
/* Read each PT_LOAD area into memory */
binfo("Loaded sections:\n");
binfo("Loading sections - text: %p.%x data: %p.%x\n",
(void *)loadinfo->textalloc, (int) loadinfo->textsize,
(void *)loadinfo->datastart, (int) loadinfo->datasize);
text = (FAR uint8_t *)loadinfo->textalloc;
data = (FAR uint8_t *)loadinfo->datastart;
for (i = 0; i < loadinfo->ehdr.e_shnum; i++)
if (loadinfo->ehdr.e_phnum > 0)
{
FAR Elf_Shdr *shdr = &loadinfo->shdr[i];
/* SHF_ALLOC indicates that the section requires memory during
* execution
*/
if ((shdr->sh_flags & SHF_ALLOC) == 0)
for (i = 0; i < loadinfo->ehdr.e_phnum; i++)
{
continue;
}
/* SHF_WRITE indicates that the section address space is write-
* able
*/
if ((shdr->sh_flags & SHF_WRITE) != 0)
{
pptr = &data;
}
else
{
pptr = &text;
}
*pptr = (FAR uint8_t *)_ALIGN_UP((uintptr_t)*pptr, shdr->sh_addralign);
/* SHT_NOBITS indicates that there is no data in the file for the
* section.
*/
if (shdr->sh_type != SHT_NOBITS)
{
/* Read the section data from sh_offset to the memory region */
ret = modlib_read(loadinfo, *pptr, shdr->sh_size, shdr->sh_offset);
if (ret < 0)
FAR Elf_Phdr *phdr = &loadinfo->phdr[i];
if (phdr->p_type == PT_LOAD)
{
berr("ERROR: Failed to read section %d: %d\n", i, ret);
return ret;
if (phdr->p_flags & PF_X)
{
ret = modlib_read(loadinfo, text, phdr->p_filesz,
phdr->p_offset);
}
else
{
int bssSize = phdr->p_memsz - phdr->p_filesz;
ret = modlib_read(loadinfo, data, phdr->p_filesz,
phdr->p_offset);
memset((FAR void *)((uintptr_t) data + phdr->p_filesz), 0,
bssSize);
}
if (ret < 0)
{
berr("ERROR: Failed to read section %d: %d\n", i, ret);
return ret;
}
}
}
/* If there is no data in an allocated section, then the allocated
* section must be cleared.
*/
else
}
else
{
for (i = 0; i < loadinfo->ehdr.e_shnum; i++)
{
memset(*pptr, 0, shdr->sh_size);
FAR Elf_Shdr *shdr = &loadinfo->shdr[i];
/* SHF_ALLOC indicates that the section requires memory during
* execution
*/
if ((shdr->sh_flags & SHF_ALLOC) == 0)
{
continue;
}
/* SHF_WRITE indicates that the section address space is write-
* able
*/
if ((shdr->sh_flags & SHF_WRITE) != 0)
{
pptr = &data;
}
else
{
pptr = &text;
}
*pptr = (FAR uint8_t *)_ALIGN_UP((uintptr_t)*pptr, shdr->sh_addralign);
/* SHT_NOBITS indicates that there is no data in the file for the
* section.
*/
if (shdr->sh_type != SHT_NOBITS)
{
/* Read the section data from sh_offset to the memory region */
ret = modlib_read(loadinfo, *pptr, shdr->sh_size, shdr->sh_offset);
if (ret < 0)
{
berr("ERROR: Failed to read section %d: %d\n", i, ret);
return ret;
}
}
/* If there is no data in an allocated section, then the allocated
* section must be cleared.
*/
else
{
memset(*pptr, 0, shdr->sh_size);
}
/* Update sh_addr to point to copy in memory */
binfo("%d. %08lx->%08lx\n", i,
(unsigned long)shdr->sh_addr, (unsigned long)*pptr);
shdr->sh_addr = (uintptr_t)*pptr;
/* Setup the memory pointer for the next time through the loop */
*pptr += ELF_ALIGNUP(shdr->sh_size);
}
/* Update sh_addr to point to copy in memory */
binfo("%d. %08lx->%08lx\n", i,
(unsigned long)shdr->sh_addr, (unsigned long)*pptr);
shdr->sh_addr = (uintptr_t)*pptr;
/* Setup the memory pointer for the next time through the loop */
*pptr += ELF_ALIGNUP(shdr->sh_size);
}
return OK;
@@ -239,12 +301,12 @@ int modlib_load(FAR struct mod_loadinfo_s *loadinfo)
binfo("loadinfo: %p\n", loadinfo);
DEBUGASSERT(loadinfo && loadinfo->filfd >= 0);
/* Load section headers into memory */
/* Load section and program headers into memory */
ret = modlib_loadshdrs(loadinfo);
ret = modlib_loadhdrs(loadinfo);
if (ret < 0)
{
berr("ERROR: modlib_loadshdrs failed: %d\n", ret);
berr("ERROR: modlib_loadhdrs failed: %d\n", ret);
goto errout_with_buffers;
}
@@ -261,10 +323,14 @@ int modlib_load(FAR struct mod_loadinfo_s *loadinfo)
#if defined(CONFIG_ARCH_USE_TEXT_HEAP)
loadinfo->textalloc = (uintptr_t)
up_textheap_memalign(loadinfo->textalign,
loadinfo->textsize);
loadinfo->textsize +
loadinfo->datasize +
loadinfo->segpad);
#else
loadinfo->textalloc = (uintptr_t)lib_memalign(loadinfo->textalign,
loadinfo->textsize);
loadinfo->textsize +
loadinfo->datasize +
loadinfo->segpad);
#endif
if (!loadinfo->textalloc)
{
@@ -276,14 +342,9 @@ int modlib_load(FAR struct mod_loadinfo_s *loadinfo)
if (loadinfo->datasize > 0)
{
loadinfo->datastart = (uintptr_t)lib_memalign(loadinfo->dataalign,
loadinfo->datasize);
if (!loadinfo->datastart)
{
berr("ERROR: Failed to allocate memory for the module data\n");
ret = -ENOMEM;
goto errout_with_buffers;
}
loadinfo->datastart = loadinfo->textalloc +
loadinfo->textsize +
loadinfo->segpad;
}
/* Load ELF section data into memory */
@@ -1,5 +1,5 @@
/****************************************************************************
* libs/libc/modlib/modlib_loadshdrs.c
* libs/libc/modlib/modlib_loadhdrs.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@@ -42,10 +42,10 @@
****************************************************************************/
/****************************************************************************
* Name: modlib_loadshdrs
* Name: modlib_loadhdrs
*
* Description:
* Loads section headers into memory.
* Loads program and section headers into memory.
*
* Returned Value:
* 0 (OK) is returned on success and a negated errno is returned on
@@ -53,12 +53,14 @@
*
****************************************************************************/
int modlib_loadshdrs(FAR struct mod_loadinfo_s *loadinfo)
int modlib_loadhdrs(FAR struct mod_loadinfo_s *loadinfo)
{
size_t shdrsize;
size_t phdrsize;
int ret;
DEBUGASSERT(loadinfo->shdr == NULL);
DEBUGASSERT(loadinfo->phdr == NULL);
/* Verify that there are sections */
@@ -68,6 +70,14 @@ int modlib_loadshdrs(FAR struct mod_loadinfo_s *loadinfo)
return -EINVAL;
}
/* Verify that there are program headers */
if (loadinfo->ehdr.e_phnum < 1)
{
berr("ERROR: No program headers(?)\n");
return -EINVAL;
}
/* Get the total size of the section header table */
shdrsize = (size_t)loadinfo->ehdr.e_shentsize *
@@ -78,6 +88,16 @@ int modlib_loadshdrs(FAR struct mod_loadinfo_s *loadinfo)
return -ESPIPE;
}
/* Get the total size of the program header table */
phdrsize = (size_t)loadinfo->ehdr.e_phentsize *
(size_t)loadinfo->ehdr.e_phnum;
if (loadinfo->ehdr.e_phoff + phdrsize > loadinfo->filelen)
{
berr("ERROR: Insufficent space in file for program header table\n");
return -ESPIPE;
}
/* Allocate memory to hold a working copy of the sector header table */
loadinfo->shdr = (FAR FAR Elf_Shdr *)lib_malloc(shdrsize);
@@ -97,5 +117,27 @@ int modlib_loadshdrs(FAR struct mod_loadinfo_s *loadinfo)
berr("ERROR: Failed to read section header table: %d\n", ret);
}
/* Allocate memory to hold a working copy of the program header table */
loadinfo->phdr = (FAR FAR Elf_Phdr *)lib_malloc(phdrsize);
if (!loadinfo->shdr)
{
lib_free((FAR void *)loadinfo->shdr);
berr("ERROR: Failed to allocate the program header table. Size: %ld\n",
(long)phdrsize);
return -ENOMEM;
}
/* Read the program header table into memory */
ret = modlib_read(loadinfo, (FAR uint8_t *)loadinfo->phdr, phdrsize,
loadinfo->ehdr.e_phoff);
if (ret < 0)
{
berr("ERROR: Failed to read program header table: %d\n", ret);
lib_free((FAR void *)loadinfo->phdr);
lib_free((FAR void *)loadinfo->shdr);
}
return ret;
}
+191 -10
View File
@@ -33,6 +33,7 @@
#include <nuttx/lib/modlib.h>
#include "libc.h"
#include "modlib/modlib.h"
/****************************************************************************
@@ -55,6 +56,12 @@ struct mod_exportinfo_s
FAR const struct symtab_s *symbol; /* Symbol info returned (if found) */
};
struct epTable_s
{
uint8_t *epName; /* Name of global symbol */
void *epAddr; /* Address of global symbol */
};
/****************************************************************************
* Private Functions
****************************************************************************/
@@ -76,7 +83,7 @@ struct mod_exportinfo_s
****************************************************************************/
static int modlib_symname(FAR struct mod_loadinfo_s *loadinfo,
FAR const Elf_Sym *sym)
FAR const Elf_Sym *sym, Elf_Off sh_offset)
{
FAR uint8_t *buffer;
off_t offset;
@@ -94,7 +101,7 @@ static int modlib_symname(FAR struct mod_loadinfo_s *loadinfo,
return -ESRCH;
}
offset = loadinfo->shdr[loadinfo->strtabidx].sh_offset + sym->st_name;
offset = sh_offset + sym->st_name;
/* Loop until we get the entire symbol name into memory */
@@ -145,6 +152,8 @@ static int modlib_symname(FAR struct mod_loadinfo_s *loadinfo,
berr("ERROR: mod_reallocbuffer failed: %d\n", ret);
return ret;
}
offset += CONFIG_MODLIB_BUFFERINCR;
}
/* We will not get here */
@@ -258,9 +267,8 @@ int modlib_findsymtab(FAR struct mod_loadinfo_s *loadinfo)
****************************************************************************/
int modlib_readsym(FAR struct mod_loadinfo_s *loadinfo, int index,
FAR Elf_Sym *sym)
FAR Elf_Sym *sym, FAR Elf_Shdr *symtab)
{
FAR Elf_Shdr *symtab = &loadinfo->shdr[loadinfo->symtabidx];
off_t offset;
/* Verify that the symbol table index lies within symbol table */
@@ -288,9 +296,10 @@ int modlib_readsym(FAR struct mod_loadinfo_s *loadinfo, int index,
* in the st_value field of the symbol table entry.
*
* Input Parameters:
* modp - Module state information
* loadinfo - Load state information
* sym - Symbol table entry (value might be undefined)
* modp - Module state information
* loadinfo - Load state information
* sym - Symbol table entry (value might be undefined)
* sh_offset - Offset of strtab
*
* Returned Value:
* 0 (OK) is returned on success and a negated errno is returned on
@@ -305,7 +314,8 @@ int modlib_readsym(FAR struct mod_loadinfo_s *loadinfo, int index,
****************************************************************************/
int modlib_symvalue(FAR struct module_s *modp,
FAR struct mod_loadinfo_s *loadinfo, FAR Elf_Sym *sym)
FAR struct mod_loadinfo_s *loadinfo, FAR Elf_Sym *sym,
Elf_Off sh_offset)
{
FAR const struct symtab_s *symbol;
struct mod_exportinfo_s exportinfo;
@@ -335,7 +345,7 @@ int modlib_symvalue(FAR struct module_s *modp,
{
/* Get the name of the undefined symbol */
ret = modlib_symname(loadinfo, sym);
ret = modlib_symname(loadinfo, sym, sh_offset);
if (ret < 0)
{
/* There are a few relocations for a few architectures that do
@@ -406,7 +416,8 @@ int modlib_symvalue(FAR struct module_s *modp,
{
secbase = loadinfo->shdr[sym->st_shndx].sh_addr;
binfo("Other: %08" PRIxPTR "+%08" PRIxPTR "=%08" PRIxPTR "\n",
binfo("Other[%d]: %08" PRIxPTR "+%08" PRIxPTR "=%08" PRIxPTR "\n",
sym->st_shndx,
(uintptr_t)sym->st_value, secbase,
(uintptr_t)(sym->st_value + secbase));
@@ -417,3 +428,173 @@ int modlib_symvalue(FAR struct module_s *modp,
return OK;
}
/****************************************************************************
* Name: modlib_insertsymtab
*
* Description:
* Insert a symbol into the modules exportinfo array.
*
* Input Parameters:
* modp - Module state information
* loadinfo - Load state information
* shdr - Symbol table section header
* sym - Symbol table entry
*
* Returned Value:
* 0 (OK) is returned on success and a negated errno is returned on
* failure.
*
* EINVAL - There is something inconsistent in the symbol table
* (should only happen if the file is corrupted).
*
****************************************************************************/
int modlib_insertsymtab(FAR struct module_s *modp,
struct mod_loadinfo_s *loadinfo,
FAR Elf_Shdr *shdr, FAR Elf_Sym *sym)
{
FAR struct symtab_s *symbol;
FAR Elf_Shdr *strTab = &loadinfo->shdr[shdr->sh_link];
int ret = 0;
int i;
int j;
int nSym;
int symCount;
if (modp->modinfo.exports != NULL)
{
bwarn("Module export information already present - replacing");
modlib_freesymtab((FAR void *) modp);
}
/* Count the "live" symbols */
nSym = shdr->sh_size / sizeof(Elf_Sym);
for (i = 0, symCount = 0; i < nSym; i++)
{
if (sym[i].st_name != 0)
symCount++;
}
if (symCount > 0)
{
modp->modinfo.exports = symbol =
loadinfo->exported =
lib_malloc(sizeof(*symbol) * symCount);
if (modp->modinfo.exports)
{
/* Build out module's symbol table */
modp->modinfo.nexports = symCount;
for (i = 0, j = 0; i < nSym; i++)
{
if (sym[i].st_name != 0)
{
ret = modlib_symname(loadinfo, &sym[i], strTab->sh_offset);
if (ret < 0)
{
lib_free((FAR void *) modp->modinfo.exports);
modp->modinfo.exports = NULL;
return ret;
}
symbol[j].sym_name = strdup((char *) loadinfo->iobuffer);
symbol[j].sym_value = (FAR const void *) sym[i].st_value;
j++;
}
}
}
else
{
berr("Unable to get memory for exported symbols table");
ret = -ENOMEM;
}
}
return ret;
}
/****************************************************************************
* Name: findEP
*
* Description:
* Binary search comparison function
*
* Input Parameters:
* c1 - Comparand 1
* c2 - Comparand 2
*
****************************************************************************/
static int findEP(const void *c1, const void *c2)
{
const struct epTable_s *m1 = (struct epTable_s *) c1;
const struct epTable_s *m2 = (struct epTable_s *) c2;
return strcmp((FAR const char *)m1->epName, (FAR const char *)m2->epName);
}
/****************************************************************************
* Name: modlib_findglobal
*
* Description:
* Find a symbol in our library entry point table
*
* Input Parameters:
* modp - Module state information
*
****************************************************************************/
void *modlib_findglobal(FAR struct module_s *modp,
struct mod_loadinfo_s *loadinfo,
FAR Elf_Shdr *shdr, FAR Elf_Sym *sym)
{
FAR Elf_Shdr *strTab = &loadinfo->shdr[shdr->sh_link];
int ret;
struct epTable_s key;
struct epTable_s *res;
extern struct epTable_s globalTable[];
extern int nGlobals;
ret = modlib_symname(loadinfo, sym, strTab->sh_offset);
if (ret < 0)
return NULL;
key.epName = loadinfo->iobuffer;
res = bsearch(&key, globalTable, nGlobals,
sizeof(struct epTable_s), findEP);
if (res != NULL)
{
return res->epAddr;
}
else
{
return NULL;
}
}
/****************************************************************************
* Name: modlib_freesymtab
*
* Description:
* Free a symbol table
*
* Input Parameters:
* modp - Module state information
*
****************************************************************************/
void modlib_freesymtab(FAR struct module_s *modp)
{
FAR const struct symtab_s *symbol;
if ((symbol = modp->modinfo.exports))
{
for (int i = 0; i < modp->modinfo.nexports; i++)
{
lib_free((FAR void *) symbol[i].sym_name);
}
lib_free((FAR void *) symbol);
}
}
+6
View File
@@ -88,6 +88,12 @@ int modlib_freebuffers(struct mod_loadinfo_s *loadinfo)
loadinfo->shdr = NULL;
}
if (loadinfo->phdr != NULL)
{
lib_free((FAR void *)loadinfo->phdr);
loadinfo->phdr = NULL;
}
if (loadinfo->iobuffer != NULL)
{
lib_free((FAR void *)loadinfo->iobuffer);
+5 -2
View File
@@ -84,8 +84,11 @@ int modlib_verifyheader(FAR const Elf_Ehdr *ehdr)
if (ehdr->e_type != ET_REL)
{
berr("ERROR: Not a relocatable file: e_type=%d\n", ehdr->e_type);
return -EINVAL;
if (ehdr->e_type != ET_DYN)
{
berr("ERROR: Not a relocatable file: e_type=%d\n", ehdr->e_type);
return -EINVAL;
}
}
/* Verify that this file works with the currently configured architecture */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff