From 00ad1f0f4a741dc977eb4e3cfd6aee0dcc99acf3 Mon Sep 17 00:00:00 2001 From: patacongo Date: Wed, 24 Oct 2012 23:40:31 +0000 Subject: [PATCH] A little more ELF loader logic git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5253 42af7a65-404d-4744-a932-0658087f49c3 --- binfmt/libelf/libelf.h | 13 +++ binfmt/libelf/libelf_bind.c | 1 - binfmt/libelf/libelf_init.c | 72 ++++------------- binfmt/libelf/libelf_load.c | 147 +++++++++++++++++++++++++++++++++- binfmt/libelf/libelf_read.c | 1 - binfmt/libelf/libelf_unload.c | 17 ++-- binfmt/libelf/libelf_verify.c | 42 ++++++++-- include/elf.h | 9 ++- include/nuttx/binfmt/elf.h | 38 ++------- 9 files changed, 228 insertions(+), 112 deletions(-) diff --git a/binfmt/libelf/libelf.h b/binfmt/libelf/libelf.h index 80d971bca2..ed352865c6 100644 --- a/binfmt/libelf/libelf.h +++ b/binfmt/libelf/libelf.h @@ -42,6 +42,8 @@ #include +#include + /**************************************************************************** * 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/binfmt/libelf/libelf_bind.c b/binfmt/libelf/libelf_bind.c index 87afe79c9f..74b713b9e3 100644 --- a/binfmt/libelf/libelf_bind.c +++ b/binfmt/libelf/libelf_bind.c @@ -46,7 +46,6 @@ #include #include -#include #include #include diff --git a/binfmt/libelf/libelf_init.c b/binfmt/libelf/libelf_init.c index 71b6b92272..b024f2d19e 100644 --- a/binfmt/libelf/libelf_init.c +++ b/binfmt/libelf/libelf_init.c @@ -47,7 +47,6 @@ #include #include -#include #include /**************************************************************************** @@ -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/binfmt/libelf/libelf_load.c b/binfmt/libelf/libelf_load.c index 26785f6b1c..41bafe04e1 100644 --- a/binfmt/libelf/libelf_load.c +++ b/binfmt/libelf/libelf_load.c @@ -40,14 +40,15 @@ #include #include -#include +#include + #include #include +#include #include #include #include -#include #include /**************************************************************************** @@ -66,6 +67,148 @@ * 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 ****************************************************************************/ diff --git a/binfmt/libelf/libelf_read.c b/binfmt/libelf/libelf_read.c index 3770301747..35b9090f98 100644 --- a/binfmt/libelf/libelf_read.c +++ b/binfmt/libelf/libelf_read.c @@ -47,7 +47,6 @@ #include #include -#include #include /**************************************************************************** diff --git a/binfmt/libelf/libelf_unload.c b/binfmt/libelf/libelf_unload.c index 9a198fc780..217a1981ef 100644 --- a/binfmt/libelf/libelf_unload.c +++ b/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/binfmt/libelf/libelf_verify.c b/binfmt/libelf/libelf_verify.c index 9139700b34..0e0dd8e1ae 100644 --- a/binfmt/libelf/libelf_verify.c +++ b/binfmt/libelf/libelf_verify.c @@ -42,7 +42,7 @@ #include #include #include -#include + #include /**************************************************************************** @@ -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; } diff --git a/include/elf.h b/include/elf.h index 31818249fa..dbc615dcd0 100644 --- a/include/elf.h +++ b/include/elf.h @@ -86,16 +86,17 @@ /* Ehe ELF identifier */ #define EI_MAG0 0 /* File identification */ -#define EI_MAG1 1 /* File identification */ -#define EI_MAG2 2 /* File identification */ -#define EI_MAG3 3 /* File identification */ +#define EI_MAG1 1 /* " " " " */ +#define EI_MAG2 2 /* " " " " */ +#define EI_MAG3 3 /* " " " " */ #define EI_CLASS 4 /* File class */ #define EI_DATA 5 /* Data encoding */ #define EI_VERSION 6 /* File version */ #define EI_PAD 7 /* Start of padding bytes */ #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 */ diff --git a/include/nuttx/binfmt/elf.h b/include/nuttx/binfmt/elf.h index 8937790b13..95db7d16fd 100644 --- a/include/nuttx/binfmt/elf.h +++ b/include/nuttx/binfmt/elf.h @@ -60,38 +60,12 @@ struct elf_loadinfo_s { - /* Instruction Space (ISpace): This region contains the ELF file header - * plus everything from the text section. Ideally, will have only one mmap'ed - * text section instance in the system for each module. - */ - - uint32_t ispace; /* Address where hdr/text is loaded */ - 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; + uintptr_t alloc; /* Allocated memory with the ELF file is loaded */ + size_t allocsize; /* Size of the memory allocation */ + off_t filelen; /* Length of the entire ELF file */ + int filfd; /* Descriptor for the file being loaded */ + Elf32_Ehdr ehdr; /* Buffered ELF file header */ + FAR Elf32_Shdr *shdr; /* Buffered ELF section headers */ }; /****************************************************************************