mirror of
https://github.com/apache/nuttx.git
synced 2025-01-13 10:58:49 +08:00
A little more ELF loader logic
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5253 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
b8f437ef4b
commit
00ad1f0f4a
9 changed files with 228 additions and 112 deletions
|
@ -42,6 +42,8 @@
|
||||||
|
|
||||||
#include <nuttx/config.h>
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <elf.h>
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Pre-processor Definitions
|
* Pre-processor Definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
@ -50,4 +52,15 @@
|
||||||
* Public Types
|
* Public Types
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: arch_checkarch
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Given the ELF header in hdr, verify that the ELF file is appropriate
|
||||||
|
* for the current, configured architecture.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
bool arch_checkarch(const struct Elf32_Ehdr *hdr);
|
||||||
|
|
||||||
#endif /* __BINFMT_LIBELF_LIBELF_H */
|
#endif /* __BINFMT_LIBELF_LIBELF_H */
|
||||||
|
|
|
@ -46,7 +46,6 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <nuttx/binfmt/elf.h>
|
#include <nuttx/binfmt/elf.h>
|
||||||
#include <nuttx/binfmt/symtab.h>
|
#include <nuttx/binfmt/symtab.h>
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,6 @@
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <nuttx/binfmt/elf.h>
|
#include <nuttx/binfmt/elf.h>
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
@ -95,11 +94,7 @@
|
||||||
|
|
||||||
int elf_init(FAR const char *filename, FAR struct elf_loadinfo_s *loadinfo)
|
int elf_init(FAR const char *filename, FAR struct elf_loadinfo_s *loadinfo)
|
||||||
{
|
{
|
||||||
uint32_t datastart;
|
int ret;
|
||||||
uint32_t dataend;
|
|
||||||
uint32_t bssstart;
|
|
||||||
uint32_t bssend;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
bvdbg("filename: %s loadinfo: %p\n", filename, loadinfo);
|
bvdbg("filename: %s loadinfo: %p\n", filename, loadinfo);
|
||||||
|
|
||||||
|
@ -116,72 +111,33 @@ int elf_init(FAR const char *filename, FAR struct elf_loadinfo_s *loadinfo)
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read the ELF header from offset 0 */
|
/* Read the ELF ehdr from offset 0 */
|
||||||
|
|
||||||
ret = elf_read(loadinfo, (char*)&loadinfo->header, sizeof(Elf32_Ehdr), 0);
|
ret = elf_read(loadinfo, (char*)&loadinfo->ehdr, sizeof(Elf32_Ehdr), 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
bdbg("Failed to read ELF header: %d\n", ret);
|
bdbg("Failed to read ELF header: %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
elf_dumpbuffer("ELF header", (FAR const uint8_t*)&loadinfo->header, sizeof(Elf32_Ehdr));
|
elf_dumpbuffer("ELF header", (FAR const uint8_t*)&loadinfo->ehdr, sizeof(Elf32_Ehdr));
|
||||||
|
|
||||||
/* Verify the ELF header */
|
/* Verify the ELF header */
|
||||||
|
|
||||||
if (elf_verifyheader(&loadinfo->header) != 0)
|
ret = elf_verifyheader(&loadinfo->ehdr);
|
||||||
|
if (ret <0)
|
||||||
{
|
{
|
||||||
/* This is not an error because we will be called to attempt loading
|
/* This may not be an error because we will be called to attempt loading
|
||||||
* EVERY binary. Returning -ENOEXEC simply informs the system that
|
* EVERY binary. If elf_verifyheader() does not recognize the ELF header,
|
||||||
* the file is not an ELF file. Besides, if there is something worth
|
* it will -ENOEXEC whcih simply informs the system that the file is not an
|
||||||
* complaining about, nelf_verifyheader() has already
|
* ELF file. elf_verifyheader() will return other errors if the ELF header
|
||||||
* done so.
|
* is not correctly formed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bdbg("Bad ELF header\n");
|
bdbg("Bad ELF header: %d\n", ret);
|
||||||
return -ENOEXEC;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Save all of the input values in the loadinfo structure
|
return OK;
|
||||||
* and extract some additional information from the xflat
|
|
||||||
* header. Note that the information in the xflat header is in
|
|
||||||
* network order.
|
|
||||||
*/
|
|
||||||
|
|
||||||
datastart = ntohl(loadinfo->header.h_datastart);
|
|
||||||
dataend = ntohl(loadinfo->header.h_dataend);
|
|
||||||
bssstart = dataend;
|
|
||||||
bssend = ntohl(loadinfo->header.h_bssend);
|
|
||||||
|
|
||||||
/* And put this information into the loadinfo structure as well.
|
|
||||||
*
|
|
||||||
* Note that:
|
|
||||||
*
|
|
||||||
* isize = the address range from 0 up to datastart.
|
|
||||||
* datasize = the address range from datastart up to dataend
|
|
||||||
* bsssize = the address range from dataend up to bssend.
|
|
||||||
*/
|
|
||||||
|
|
||||||
loadinfo->entryoffs = ntohl(loadinfo->header.h_entry);
|
|
||||||
loadinfo->isize = datastart;
|
|
||||||
|
|
||||||
loadinfo->datasize = dataend - datastart;
|
|
||||||
loadinfo->bsssize = bssend - dataend;
|
|
||||||
loadinfo->stacksize = ntohl(loadinfo->header.h_stacksize);
|
|
||||||
|
|
||||||
/* This is the initial dspace size. We'll re-calculate this later
|
|
||||||
* after the memory has been allocated.
|
|
||||||
*/
|
|
||||||
|
|
||||||
loadinfo->dsize = bssend - datastart;
|
|
||||||
|
|
||||||
/* Get the offset to the start of the relocations (we'll relocate
|
|
||||||
* this later).
|
|
||||||
*/
|
|
||||||
|
|
||||||
loadinfo->relocstart = ntohl(loadinfo->header.h_relocstart);
|
|
||||||
loadinfo->reloccount = ntohs(loadinfo->header.h_reloccount);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,14 +40,15 @@
|
||||||
#include <nuttx/config.h>
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <elf.h>
|
#include <elf.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <nuttx/binfmt/elf.h>
|
#include <nuttx/binfmt/elf.h>
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
@ -66,6 +67,148 @@
|
||||||
* Private Functions
|
* Private Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: elf_filelen
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Get the size of the ELF file
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* 0 (OK) is returned on success and a negated errno is returned on
|
||||||
|
* failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static inline int elf_filelen(FAR struct elf_loadinfo_s *loadinfo)
|
||||||
|
{
|
||||||
|
struct stat buf;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Get the file stats */
|
||||||
|
|
||||||
|
ret = fstat(loadinfo->filfd, &buf);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
int errval = errno;
|
||||||
|
bdbg("Failed to fstat file: %d\n", errval);
|
||||||
|
return -errval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify that it is a regular file */
|
||||||
|
|
||||||
|
if (!S_ISREG(buf.st_mode))
|
||||||
|
{
|
||||||
|
bdbg("Not a regular file. mode: %d\n", buf.st_mode);
|
||||||
|
return -errval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Verify that the file is readable */
|
||||||
|
|
||||||
|
/* Return the size of the file in the loadinfo structure */
|
||||||
|
|
||||||
|
loadinfo->filelen = buf.st_size;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: elf_loadshdrs
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Loads section headers into memory.
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* 0 (OK) is returned on success and a negated errno is returned on
|
||||||
|
* failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static inline int elf_loadshdrs(FAR struct elf_loadinfo_s *loadinfo)
|
||||||
|
{
|
||||||
|
size_t shdrsize;
|
||||||
|
ssize_t bytesread;
|
||||||
|
uint8_t buffer;
|
||||||
|
off_t offset;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
DEBUGASSERT(loadinfo->shdrs == NULL);
|
||||||
|
|
||||||
|
/* Verify that there are sections */
|
||||||
|
|
||||||
|
if (loadinfo->e_shum < 1)
|
||||||
|
{
|
||||||
|
bdbg("No section(?)\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the total size of the section header table */
|
||||||
|
|
||||||
|
shdrsize = (size_t)loadinfo->ehdr.e_shentsize * (size_t)loadinfo->e_shum;
|
||||||
|
if(loadinfo->e_shoff + shdrsize > loadinfo->filelen)
|
||||||
|
{
|
||||||
|
bdbg("Insufficent space in file for section header table\n");
|
||||||
|
return -ESPIPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate memory to hold a working copy of the sector header table */
|
||||||
|
|
||||||
|
loadinfo->shdrs = (FAR Elf32_Shdr*)kmalloc(shdrsize);
|
||||||
|
if (!loadinfo->shdrs)
|
||||||
|
{
|
||||||
|
bdbg("Failed to allocate the section header table. Size: %ld\n", (long)shdrsize);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Seek to the start of the section header table */
|
||||||
|
|
||||||
|
offset = lseek(loadinfo->filfd, loadinfo->e_shoff, SEEK_SET);
|
||||||
|
if (offset == (off_t)-1)
|
||||||
|
{
|
||||||
|
int errval = errno;
|
||||||
|
bdbg("See to %ld failed: %d\n", (long)loadinfo->e_shoff, errval);
|
||||||
|
ret = -errval;
|
||||||
|
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;
|
||||||
|
|
||||||
|
errout_with_alloc:
|
||||||
|
kfree(loadinfo->shdrs);
|
||||||
|
loadinfo->shdrs = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
|
@ -47,7 +47,6 @@
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <nuttx/binfmt/elf.h>
|
#include <nuttx/binfmt/elf.h>
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
|
|
@ -76,20 +76,19 @@
|
||||||
|
|
||||||
int elf_unload(struct elf_loadinfo_s *loadinfo)
|
int elf_unload(struct elf_loadinfo_s *loadinfo)
|
||||||
{
|
{
|
||||||
/* Reset the contents of the info structure. */
|
/* Release the all allocated memory */
|
||||||
|
|
||||||
/* Release the memory segments */
|
if (loadinfo->alloc)
|
||||||
|
|
||||||
if (loadinfo->ispace)
|
|
||||||
{
|
{
|
||||||
kfree((void*)loadinfo->ispace, loadinfo->isize);
|
kfree((void*)loadinfo->alloc);
|
||||||
loadinfo->ispace = 0;
|
loadinfo->alloc = NULL;
|
||||||
|
loadinfo->allocsize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loadinfo->dspace)
|
if (loadinfo->shdrs)
|
||||||
{
|
{
|
||||||
kfree((void*)loadinfo->dspace);
|
kfree((void*)loadinfo->shdrs);
|
||||||
loadinfo->dspace = 0;
|
loadinfo->shdrs = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <nuttx/binfmt/elf.h>
|
#include <nuttx/binfmt/elf.h>
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
@ -53,6 +53,8 @@
|
||||||
* Private Constant Data
|
* Private Constant Data
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
static const char g_elfmagic[EI_MAGIC_SIZE] = { 0x7f, 'E', 'L', 'F' }
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Functions
|
* Private Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
@ -72,17 +74,47 @@
|
||||||
* 0 (OK) is returned on success and a negated errno is returned on
|
* 0 (OK) is returned on success and a negated errno is returned on
|
||||||
* failure.
|
* failure.
|
||||||
*
|
*
|
||||||
|
* -ENOEXEC : Not an ELF file
|
||||||
|
* -EINVALID : Not a relocatable ELF file or not supported by the current,
|
||||||
|
* configured architecture.
|
||||||
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
int elf_verifyheader(const Elf32_Ehdr *header)
|
int elf_verifyheader(const Elf32_Ehdr *ehdr)
|
||||||
{
|
{
|
||||||
if (!header)
|
if (!ehdr)
|
||||||
{
|
{
|
||||||
bdbg("NULL ELF header!");
|
bdbg("NULL ELF header!");
|
||||||
return -ENOEXEC;
|
return -ENOEXEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
#warning "Missing Logic"
|
/* Verify that the magic number indicates an ELF file */
|
||||||
return -ENOSYS;
|
|
||||||
|
if (memcmp(ehdr->e_ident, g_elfmagic, EI_MAGIC_SIZE) != 0)
|
||||||
|
{
|
||||||
|
bvdbg("Not ELF magic {%02x, %02x, %02x, %02x}\n",
|
||||||
|
ehdr->e_ident[0], ehdr->e_ident[1], ehdr->e_ident[2], ehdr->e_ident[3]);
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify that this is a relocatable file */
|
||||||
|
|
||||||
|
if (ehdr->e_type != ET_REL)
|
||||||
|
{
|
||||||
|
bdbg("Not a relocatable file: e_type=%d\n", ehdr->e_type);
|
||||||
|
return -EINVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify that this file works with the currently configured architecture */
|
||||||
|
|
||||||
|
if (arch_checkarch(ehdr))
|
||||||
|
{
|
||||||
|
bdbg("Not a supported architecture\n");
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Looks good so far... we still might find some problems later. */
|
||||||
|
|
||||||
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,16 +86,17 @@
|
||||||
/* Ehe ELF identifier */
|
/* Ehe ELF identifier */
|
||||||
|
|
||||||
#define EI_MAG0 0 /* File identification */
|
#define EI_MAG0 0 /* File identification */
|
||||||
#define EI_MAG1 1 /* File identification */
|
#define EI_MAG1 1 /* " " " " */
|
||||||
#define EI_MAG2 2 /* File identification */
|
#define EI_MAG2 2 /* " " " " */
|
||||||
#define EI_MAG3 3 /* File identification */
|
#define EI_MAG3 3 /* " " " " */
|
||||||
#define EI_CLASS 4 /* File class */
|
#define EI_CLASS 4 /* File class */
|
||||||
#define EI_DATA 5 /* Data encoding */
|
#define EI_DATA 5 /* Data encoding */
|
||||||
#define EI_VERSION 6 /* File version */
|
#define EI_VERSION 6 /* File version */
|
||||||
#define EI_PAD 7 /* Start of padding bytes */
|
#define EI_PAD 7 /* Start of padding bytes */
|
||||||
#define EI_NIDENT 16 /* Size of eident[] */
|
#define EI_NIDENT 16 /* Size of eident[] */
|
||||||
|
|
||||||
#define EI_MAGIC { 0x7f, 'E', 'L', 'F' }
|
#define EI_MAGIC_SIZE 4
|
||||||
|
#define EI_MAGIC {0x7f, 'E', 'L', 'F'}
|
||||||
|
|
||||||
/* Values for EI_CLASS */
|
/* Values for EI_CLASS */
|
||||||
|
|
||||||
|
|
|
@ -60,38 +60,12 @@
|
||||||
|
|
||||||
struct elf_loadinfo_s
|
struct elf_loadinfo_s
|
||||||
{
|
{
|
||||||
/* Instruction Space (ISpace): This region contains the ELF file header
|
uintptr_t alloc; /* Allocated memory with the ELF file is loaded */
|
||||||
* plus everything from the text section. Ideally, will have only one mmap'ed
|
size_t allocsize; /* Size of the memory allocation */
|
||||||
* text section instance in the system for each module.
|
off_t filelen; /* Length of the entire ELF file */
|
||||||
*/
|
int filfd; /* Descriptor for the file being loaded */
|
||||||
|
Elf32_Ehdr ehdr; /* Buffered ELF file header */
|
||||||
uint32_t ispace; /* Address where hdr/text is loaded */
|
FAR Elf32_Shdr *shdr; /* Buffered ELF section headers */
|
||||||
uint32_t entryoffs; /* Offset from ispace to entry point */
|
|
||||||
uint32_t isize; /* Size of ispace. */
|
|
||||||
|
|
||||||
/* Data Space (DSpace): This region contains all information that in referenced
|
|
||||||
* as data (other than the stack which is separately allocated). There will be
|
|
||||||
* a unique instance of DSpace (and stack) for each instance of a process.
|
|
||||||
*/
|
|
||||||
|
|
||||||
FAR struct dspace_s *dspace; /* Allocated D-Space (data/bss/etc) */
|
|
||||||
uint32_t datasize; /* Size of data segment in dspace */
|
|
||||||
uint32_t bsssize; /* Size of bss segment in dspace */
|
|
||||||
uint32_t stacksize; /* Size of stack (not allocated) */
|
|
||||||
uint32_t dsize; /* Size of dspace (may be large than parts) */
|
|
||||||
|
|
||||||
/* This is temporary memory where relocation records will be loaded. */
|
|
||||||
|
|
||||||
uint32_t relocstart; /* Start of array of struct flat_reloc */
|
|
||||||
uint16_t reloccount; /* Number of elements in reloc array */
|
|
||||||
|
|
||||||
/* File descriptors */
|
|
||||||
|
|
||||||
int filfd; /* Descriptor for the file being loaded */
|
|
||||||
|
|
||||||
/* This is a copy of the ELF header */
|
|
||||||
|
|
||||||
Elf32_Ehdr header;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
|
Loading…
Reference in a new issue