diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2012-10-24 23:40:31 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2012-10-24 23:40:31 +0000 |
commit | e2018e4d3085929dfc124fe41ed4b87e7eecc57d (patch) | |
tree | 714baa74493bc9615430f984d8caab4a5646dc76 /nuttx/binfmt | |
parent | 8a2348d18d16427d0787d3614aa90ab20e4b4eda (diff) | |
download | px4-firmware-e2018e4d3085929dfc124fe41ed4b87e7eecc57d.tar.gz px4-firmware-e2018e4d3085929dfc124fe41ed4b87e7eecc57d.tar.bz2 px4-firmware-e2018e4d3085929dfc124fe41ed4b87e7eecc57d.zip |
A little more ELF loader logic
git-svn-id: http://svn.code.sf.net/p/nuttx/code/trunk@5253 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/binfmt')
-rw-r--r-- | nuttx/binfmt/libelf/libelf.h | 13 | ||||
-rw-r--r-- | nuttx/binfmt/libelf/libelf_bind.c | 1 | ||||
-rw-r--r-- | nuttx/binfmt/libelf/libelf_init.c | 72 | ||||
-rw-r--r-- | nuttx/binfmt/libelf/libelf_load.c | 147 | ||||
-rw-r--r-- | nuttx/binfmt/libelf/libelf_read.c | 1 | ||||
-rw-r--r-- | nuttx/binfmt/libelf/libelf_unload.c | 17 | ||||
-rw-r--r-- | nuttx/binfmt/libelf/libelf_verify.c | 42 |
7 files changed, 217 insertions, 76 deletions
diff --git a/nuttx/binfmt/libelf/libelf.h b/nuttx/binfmt/libelf/libelf.h index 80d971bca..ed352865c 100644 --- a/nuttx/binfmt/libelf/libelf.h +++ b/nuttx/binfmt/libelf/libelf.h @@ -42,6 +42,8 @@ #include <nuttx/config.h> +#include <elf.h> + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -50,4 +52,15 @@ * 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 */ diff --git a/nuttx/binfmt/libelf/libelf_bind.c b/nuttx/binfmt/libelf/libelf_bind.c index 87afe79c9..74b713b9e 100644 --- a/nuttx/binfmt/libelf/libelf_bind.c +++ b/nuttx/binfmt/libelf/libelf_bind.c @@ -46,7 +46,6 @@ #include <assert.h> #include <debug.h> -#include <arpa/inet.h> #include <nuttx/binfmt/elf.h> #include <nuttx/binfmt/symtab.h> diff --git a/nuttx/binfmt/libelf/libelf_init.c b/nuttx/binfmt/libelf/libelf_init.c index 71b6b9227..b024f2d19 100644 --- a/nuttx/binfmt/libelf/libelf_init.c +++ b/nuttx/binfmt/libelf/libelf_init.c @@ -47,7 +47,6 @@ #include <debug.h> #include <errno.h> -#include <arpa/inet.h> #include <nuttx/binfmt/elf.h> /**************************************************************************** @@ -95,11 +94,7 @@ int elf_init(FAR const char *filename, FAR struct elf_loadinfo_s *loadinfo) { - uint32_t datastart; - uint32_t dataend; - uint32_t bssstart; - uint32_t bssend; - int ret; + int ret; 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; } - /* 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) { bdbg("Failed to read ELF header: %d\n", 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 */ - 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 - * EVERY binary. Returning -ENOEXEC simply informs the system that - * the file is not an ELF file. Besides, if there is something worth - * complaining about, nelf_verifyheader() has already - * done so. + /* This may not be an error because we will be called to attempt loading + * EVERY binary. If elf_verifyheader() does not recognize the ELF header, + * it will -ENOEXEC whcih simply informs the system that the file is not an + * ELF file. elf_verifyheader() will return other errors if the ELF header + * is not correctly formed. */ - bdbg("Bad ELF header\n"); - return -ENOEXEC; + bdbg("Bad ELF header: %d\n", ret); + return ret; } - /* Save all of the input values in the loadinfo structure - * 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; + return OK; } diff --git a/nuttx/binfmt/libelf/libelf_load.c b/nuttx/binfmt/libelf/libelf_load.c index 26785f6b1..41bafe04e 100644 --- a/nuttx/binfmt/libelf/libelf_load.c +++ b/nuttx/binfmt/libelf/libelf_load.c @@ -40,14 +40,15 @@ #include <nuttx/config.h> #include <sys/types.h> -#include <sys/mman.h> +#include <sys/stat.h> + #include <stdint.h> #include <stdlib.h> +#include <unistd.h> #include <elf.h> #include <debug.h> #include <errno.h> -#include <arpa/inet.h> #include <nuttx/binfmt/elf.h> /**************************************************************************** @@ -67,6 +68,148 @@ ****************************************************************************/ /**************************************************************************** + * 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 ****************************************************************************/ diff --git a/nuttx/binfmt/libelf/libelf_read.c b/nuttx/binfmt/libelf/libelf_read.c index 377030174..35b9090f9 100644 --- a/nuttx/binfmt/libelf/libelf_read.c +++ b/nuttx/binfmt/libelf/libelf_read.c @@ -47,7 +47,6 @@ #include <debug.h> #include <errno.h> -#include <arpa/inet.h> #include <nuttx/binfmt/elf.h> /**************************************************************************** diff --git a/nuttx/binfmt/libelf/libelf_unload.c b/nuttx/binfmt/libelf/libelf_unload.c index 9a198fc78..217a1981e 100644 --- a/nuttx/binfmt/libelf/libelf_unload.c +++ b/nuttx/binfmt/libelf/libelf_unload.c @@ -76,20 +76,19 @@ 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->ispace) + if (loadinfo->alloc) { - kfree((void*)loadinfo->ispace, loadinfo->isize); - loadinfo->ispace = 0; + kfree((void*)loadinfo->alloc); + loadinfo->alloc = NULL; + loadinfo->allocsize = 0; } - if (loadinfo->dspace) + if (loadinfo->shdrs) { - kfree((void*)loadinfo->dspace); - loadinfo->dspace = 0; + kfree((void*)loadinfo->shdrs); + loadinfo->shdrs = 0; } return OK; diff --git a/nuttx/binfmt/libelf/libelf_verify.c b/nuttx/binfmt/libelf/libelf_verify.c index 9139700b3..0e0dd8e1a 100644 --- a/nuttx/binfmt/libelf/libelf_verify.c +++ b/nuttx/binfmt/libelf/libelf_verify.c @@ -42,7 +42,7 @@ #include <string.h> #include <debug.h> #include <errno.h> -#include <arpa/inet.h> + #include <nuttx/binfmt/elf.h> /**************************************************************************** @@ -53,6 +53,8 @@ * Private Constant Data ****************************************************************************/ +static const char g_elfmagic[EI_MAGIC_SIZE] = { 0x7f, 'E', 'L', 'F' } + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -72,17 +74,47 @@ * 0 (OK) is returned on success and a negated errno is returned on * 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!"); return -ENOEXEC; } -#warning "Missing Logic" - return -ENOSYS; + /* Verify that the magic number indicates an ELF file */ + + 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; } |