mirror of
https://github.com/apache/nuttx.git
synced 2026-06-05 15:58:59 +08:00
A little more ELF loader logic
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5254 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
@@ -3,7 +3,29 @@
|
|||||||
# see misc/tools/kconfig-language.txt.
|
# see misc/tools/kconfig-language.txt.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
config ELF_ALIGN_LOG2
|
||||||
|
int "Log2 Section Alignment"
|
||||||
|
default 2
|
||||||
|
---help---
|
||||||
|
Align all sections to this Log2 value: 0->1, 1->2, 2->4, etc.
|
||||||
|
|
||||||
|
config ELF_CONSTRUCTORS
|
||||||
|
bool "C++ Static Constructor Support"
|
||||||
|
default n
|
||||||
|
depends on HAVE_CXX
|
||||||
|
---help---
|
||||||
|
Build in support for C++ constructors in ELF modules.
|
||||||
|
|
||||||
|
config ELF_SYMBOLS
|
||||||
|
bool "Export symbols from ELF modules"
|
||||||
|
default n
|
||||||
|
---help---
|
||||||
|
Allow symbols from one ELF module to be used by another. (NOT
|
||||||
|
fully implemented.
|
||||||
|
|
||||||
config ELF_DUMPBUFFER
|
config ELF_DUMPBUFFER
|
||||||
bool "Dump ELF buffers"
|
bool "Dump ELF buffers"
|
||||||
default n
|
default n
|
||||||
depends on DEBUG && DEBUG_VERBOSE
|
depends on DEBUG && DEBUG_VERBOSE
|
||||||
|
---help---
|
||||||
|
Dump various ELF buffers for debug purposes
|
||||||
|
|||||||
+188
-41
@@ -55,6 +55,11 @@
|
|||||||
* Pre-Processor Definitions
|
* Pre-Processor Definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#define ELF_ALIGN_MASK ((1 << CONFIG_ELF_ALIGN_LOG2) - 1)
|
||||||
|
#define ELF_ALIGNUP(a) (((unsigned long)(a) + ELF_ALIGN_MASK) & ~ELF_ALIGN_MASK)
|
||||||
|
#define ELF_ALIGNDOWN(a) ((unsigned long)(a) & ~ELF_ALIGN_MASK)
|
||||||
|
|
||||||
|
|
||||||
#ifndef MAX
|
#ifndef MAX
|
||||||
#define MAX(x,y) ((x) > (y) ? (x) : (y))
|
#define MAX(x,y) ((x) > (y) ? (x) : (y))
|
||||||
#endif
|
#endif
|
||||||
@@ -110,6 +115,69 @@ static inline int elf_filelen(FAR struct elf_loadinfo_s *loadinfo)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: elf_readfile
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Allocate memory for the file and read the section data into the
|
||||||
|
* allocated memory.
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* 0 (OK) is returned on success and a negated errno is returned on
|
||||||
|
* failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int elf_readfile(FAR struct elf_loadinfo_s *loadinfo, FAR void *buffer,
|
||||||
|
off_t offset, size_t nbytes)
|
||||||
|
{
|
||||||
|
FAR uint8_t *buffer;
|
||||||
|
ssize_t bytesread;
|
||||||
|
off_t result;
|
||||||
|
|
||||||
|
/* Seek to the start of the section header table */
|
||||||
|
|
||||||
|
result = lseek(loadinfo->filfd, offset, SEEK_SET);
|
||||||
|
if (result == (off_t)-1)
|
||||||
|
{
|
||||||
|
int errval = errno;
|
||||||
|
bdbg("Seel to %ld failed: %d\n", (long)offset, errval);
|
||||||
|
return -errval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now load the file data into memory */
|
||||||
|
|
||||||
|
buffer = (FAR uint8_t *)loadinfo->shdrs;
|
||||||
|
while (shdrsize > 0)
|
||||||
|
{
|
||||||
|
bytesread = read(loadinfo->filfd, buffer, shdrsize);
|
||||||
|
if (bytes < 0)
|
||||||
|
{
|
||||||
|
int errval = errno;
|
||||||
|
|
||||||
|
/* EINTR just means that we received a signal */
|
||||||
|
|
||||||
|
if (errno != EINTR)
|
||||||
|
{
|
||||||
|
bdbg("read() failed: %d\n", errval);
|
||||||
|
return -errval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (bytes == 0)
|
||||||
|
{
|
||||||
|
bdbg("Unexpected end of file\n");
|
||||||
|
return -ENODATA;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer += bytesread;
|
||||||
|
shdrsize -= bytesread;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: elf_loadshdrs
|
* Name: elf_loadshdrs
|
||||||
*
|
*
|
||||||
@@ -125,9 +193,6 @@ static inline int elf_filelen(FAR struct elf_loadinfo_s *loadinfo)
|
|||||||
static inline int elf_loadshdrs(FAR struct elf_loadinfo_s *loadinfo)
|
static inline int elf_loadshdrs(FAR struct elf_loadinfo_s *loadinfo)
|
||||||
{
|
{
|
||||||
size_t shdrsize;
|
size_t shdrsize;
|
||||||
ssize_t bytesread;
|
|
||||||
uint8_t buffer;
|
|
||||||
off_t offset;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
DEBUGASSERT(loadinfo->shdrs == NULL);
|
DEBUGASSERT(loadinfo->shdrs == NULL);
|
||||||
@@ -158,49 +223,15 @@ static inline int elf_loadshdrs(FAR struct elf_loadinfo_s *loadinfo)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Seek to the start of the section header table */
|
/* Read the section header table into memory */
|
||||||
|
|
||||||
offset = lseek(loadinfo->filfd, loadinfo->e_shoff, SEEK_SET);
|
ret = elf_readfile(loadinfo, loadinfo->shdrs, loadinfo->e_shoff, shdrsize);
|
||||||
if (offset == (off_t)-1)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
int errval = errno;
|
bdbg("Failed to read section header table: %d\n", ret);
|
||||||
bdbg("See to %ld failed: %d\n", (long)loadinfo->e_shoff, errval);
|
|
||||||
ret = -errval;
|
|
||||||
goto errout_with_alloc;
|
goto errout_with_alloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now load the section header table into the allocated memory */
|
|
||||||
|
|
||||||
buffer = loadinfo->shdrs;
|
|
||||||
while (shdrsize > 0)
|
|
||||||
{
|
|
||||||
bytesread = read(loadinfo->filfd, buffer, shdrsize);
|
|
||||||
if (bytes < 0)
|
|
||||||
{
|
|
||||||
int errval = errno;
|
|
||||||
|
|
||||||
/* EINTR just means that we received a signal */
|
|
||||||
|
|
||||||
if (errno != EINTR)
|
|
||||||
{
|
|
||||||
bdbg("read() failed: %d\n", errval);
|
|
||||||
ret = -errval;
|
|
||||||
goto errout_with_alloc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (bytes == 0)
|
|
||||||
{
|
|
||||||
bdbg("Unexpectged end of file\n");
|
|
||||||
ret = -ENODATA;
|
|
||||||
goto errout_with_alloc;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
buffer += bytesread;
|
|
||||||
shdrsize -= bytesread;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
|
|
||||||
errout_with_alloc:
|
errout_with_alloc:
|
||||||
@@ -209,6 +240,122 @@ errout_with_alloc:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: elf_allocsize
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Calculate total memory allocation for the ELF file.
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* 0 (OK) is returned on success and a negated errno is returned on
|
||||||
|
* failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void elf_allocsize(struct load_info *loadinfo)
|
||||||
|
{
|
||||||
|
size_t allocsize;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Accumulate the size each section into memory that is marked SHF_ALLOC */
|
||||||
|
|
||||||
|
allocsize = 0;
|
||||||
|
for (i = 0; i < loadinfo->ehdr.e_shnum; i++)
|
||||||
|
{
|
||||||
|
FAR Elf32_Shdr *shdr = &loadinfo->shdrs[i];
|
||||||
|
|
||||||
|
/* SHF_ALLOC indicates that the section requires memory during
|
||||||
|
* execution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((shdr->sh_flags & SHF_ALLOC) != 0)
|
||||||
|
{
|
||||||
|
allocsize += ELF_ALIGNUP(shdr->sh_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the allocation size */
|
||||||
|
|
||||||
|
loadinfo->allocize = allocsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: elf_loadfile
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Allocate memory for the file and read the section data into the
|
||||||
|
* allocated memory.
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* 0 (OK) is returned on success and a negated errno is returned on
|
||||||
|
* failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static inline int elf_loadfile(FAR struct load_info *loadinfo)
|
||||||
|
{
|
||||||
|
FAR uint8_t *dest;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Allocate (and zero) memory for the ELF file. */
|
||||||
|
|
||||||
|
loadinfo->alloc = kzalloc(loadinfo->allocsize);
|
||||||
|
if (!loadinfo->alloc)
|
||||||
|
{
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read each section into memory that is marked SHF_ALLOC + SHT_NOBITS */
|
||||||
|
|
||||||
|
bvdbg("Loaded sections:\n");
|
||||||
|
dest = (FAR uint8_t*)loadinfo->alloc;
|
||||||
|
|
||||||
|
for (i = 0; i < loadinfo->ehdr.e_shnum; i++)
|
||||||
|
{
|
||||||
|
FAR Elf32_Shdr *shdr = &loadinfo->shdrs[i];
|
||||||
|
|
||||||
|
/* SHF_ALLOC indicates that the section requires memory during
|
||||||
|
* execution */
|
||||||
|
|
||||||
|
if ((shdr->sh_flags & SHF_ALLOC) == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 dest */
|
||||||
|
|
||||||
|
ret = elf_readfile(loadinfo, dest, shdr->sh_offset, shdr->sh_size);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
bdbg("Failed to read section %d: %d\n", i, ret);
|
||||||
|
goto errout_with_alloc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update sh_addr to point to copy in image. */
|
||||||
|
|
||||||
|
shdr->sh_addr = (uintptr_t)dest;
|
||||||
|
bvdbg("%d. 0x%lx %s\n", (long)shdr->sh_addr, loadinfo->secstrings + shdr->sh_name);
|
||||||
|
|
||||||
|
/* Setup the memory pointer for the next time through the loop */
|
||||||
|
|
||||||
|
dest += ELF_ALIGNUP(shdr->sh_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
|
||||||
|
errout_with_alloc:
|
||||||
|
kfree(loadinfo->alloc);
|
||||||
|
loadinfo->alloc = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|||||||
@@ -49,6 +49,11 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Pre-processor Definitions
|
* Pre-processor Definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
/* Configuration ************************************************************/
|
||||||
|
|
||||||
|
#ifndef CONFIG_ELF_ALIGN_LOG2
|
||||||
|
# define CONFIG_ELF_ALIGN_LOG2 2
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Types
|
* Public Types
|
||||||
@@ -63,6 +68,9 @@ struct elf_loadinfo_s
|
|||||||
uintptr_t alloc; /* Allocated memory with the ELF file is loaded */
|
uintptr_t alloc; /* Allocated memory with the ELF file is loaded */
|
||||||
size_t allocsize; /* Size of the memory allocation */
|
size_t allocsize; /* Size of the memory allocation */
|
||||||
off_t filelen; /* Length of the entire ELF file */
|
off_t filelen; /* Length of the entire ELF file */
|
||||||
|
#ifdef CONFIG_ELF_CONSTRUCTORS
|
||||||
|
uintptr_t ctors; /* Static constructors */
|
||||||
|
#endif
|
||||||
int filfd; /* Descriptor for the file being loaded */
|
int filfd; /* Descriptor for the file being loaded */
|
||||||
Elf32_Ehdr ehdr; /* Buffered ELF file header */
|
Elf32_Ehdr ehdr; /* Buffered ELF file header */
|
||||||
FAR Elf32_Shdr *shdr; /* Buffered ELF section headers */
|
FAR Elf32_Shdr *shdr; /* Buffered ELF section headers */
|
||||||
|
|||||||
Reference in New Issue
Block a user