diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2014-08-24 11:54:14 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2014-08-24 11:54:14 -0600 |
commit | 3db6a65a749d241ce39e0028951b48f814e09dd4 (patch) | |
tree | e70d159d637d57ee436b6d204018d666517f7c37 /nuttx/binfmt/libelf | |
parent | 112e979b453108400d12c5825d0ed05336142e56 (diff) | |
download | px4-nuttx-3db6a65a749d241ce39e0028951b48f814e09dd4.tar.gz px4-nuttx-3db6a65a749d241ce39e0028951b48f814e09dd4.tar.bz2 px4-nuttx-3db6a65a749d241ce39e0028951b48f814e09dd4.zip |
addrenv interface changes: up_addrenv_create() may need to create .text and .bss/.data separately because of differing access privileges (read/execute vs read/write). And, as a consequence, up_addrenv_vaddr() needs to be split into up_addrenv_vtext(0 and up_addrenv_vdata().
Diffstat (limited to 'nuttx/binfmt/libelf')
-rw-r--r-- | nuttx/binfmt/libelf/libelf.h | 22 | ||||
-rw-r--r-- | nuttx/binfmt/libelf/libelf_addrenv.c | 62 | ||||
-rw-r--r-- | nuttx/binfmt/libelf/libelf_bind.c | 2 | ||||
-rw-r--r-- | nuttx/binfmt/libelf/libelf_ctors.c | 5 | ||||
-rw-r--r-- | nuttx/binfmt/libelf/libelf_dtors.c | 5 | ||||
-rw-r--r-- | nuttx/binfmt/libelf/libelf_load.c | 61 |
6 files changed, 107 insertions, 50 deletions
diff --git a/nuttx/binfmt/libelf/libelf.h b/nuttx/binfmt/libelf/libelf.h index d407a31ae..8763e0808 100644 --- a/nuttx/binfmt/libelf/libelf.h +++ b/nuttx/binfmt/libelf/libelf.h @@ -1,7 +1,7 @@ /**************************************************************************** * binfmt/libelf/libelf.h * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2012, 2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <gnutt@nuttx.org> * * Redistribution and use in source and binary forms, with or without @@ -264,23 +264,27 @@ int elf_loaddtors(FAR struct elf_loadinfo_s *loadinfo); * Name: elf_addrenv_alloc * * Description: - * Allocate memory for the ELF image (elfalloc). If CONFIG_ARCH_ADDRENV=n, - * elfalloc will be allocated using kzalloc(). If CONFIG_ARCH_ADDRENV-y, then - * elfalloc will be allocated using up_addrenv_create(). In either case, - * there will be a unique instance of elfalloc (and stack) for each - * instance of a process. + * Allocate memory for the ELF image (textalloc and dataalloc). If + * CONFIG_ARCH_ADDRENV=n, textalloc will be allocated using kzalloc() and + * dataalloc will be a offset from textalloc. If CONFIG_ARCH_ADDRENV-y, then + * textalloc and dataalloc will be allocated using up_addrenv_create(). In + * either case, there will be a unique instance of textalloc and dataalloc + * (and stack) for each instance of a process. * * Input Parameters: * loadinfo - Load state information - * envsize - The size (in bytes) of the address environment needed for the - * ELF image. + * textsize - The size (in bytes) of the .text address environment needed + * for the ELF image (read/execute). + * datasize - The size (in bytes) of the .bss/.data address environment + * needed for the ELF image (read/write). * * Returned Value: * Zero (OK) on success; a negated errno value on failure. * ****************************************************************************/ -int elf_addrenv_alloc(FAR struct elf_loadinfo_s *loadinfo, size_t envsize); +int elf_addrenv_alloc(FAR struct elf_loadinfo_s *loadinfo, size_t textsize, + size_t datasize); /**************************************************************************** * Name: elf_addrenv_select diff --git a/nuttx/binfmt/libelf/libelf_addrenv.c b/nuttx/binfmt/libelf/libelf_addrenv.c index ea400a325..b112d869f 100644 --- a/nuttx/binfmt/libelf/libelf_addrenv.c +++ b/nuttx/binfmt/libelf/libelf_addrenv.c @@ -67,31 +67,36 @@ * Name: elf_addrenv_alloc * * Description: - * Allocate memory for the ELF image (elfalloc). If CONFIG_ARCH_ADDRENV=n, - * elfalloc will be allocated using kuzalloc(). If CONFIG_ARCH_ADDRENV-y, then - * elfalloc will be allocated using up_addrenv_create(). In either case, - * there will be a unique instance of elfalloc (and stack) for each - * instance of a process. + * Allocate memory for the ELF image (textalloc and dataalloc). If + * CONFIG_ARCH_ADDRENV=n, textalloc will be allocated using kzalloc() and + * dataalloc will be a offset from textalloc. If CONFIG_ARCH_ADDRENV-y, then + * textalloc and dataalloc will be allocated using up_addrenv_create(). In + * either case, there will be a unique instance of textalloc and dataalloc + * (and stack) for each instance of a process. * * Input Parameters: * loadinfo - Load state information - * envsize - The size (in bytes) of the address environment needed for the - * ELF image. + * textsize - The size (in bytes) of the .text address environment needed + * for the ELF image (read/execute). + * datasize - The size (in bytes) of the .bss/.data address environment + * needed for the ELF image (read/write). * * Returned Value: * Zero (OK) on success; a negated errno value on failure. * ****************************************************************************/ -int elf_addrenv_alloc(FAR struct elf_loadinfo_s *loadinfo, size_t envsize) +int elf_addrenv_alloc(FAR struct elf_loadinfo_s *loadinfo, size_t textsize, + size_t datasize) { #ifdef CONFIG_ARCH_ADDRENV - FAR void *vaddr; + FAR void *vtext; + FAR void *vdata; int ret; /* Create an address environment for the new ELF task */ - ret = up_addrenv_create(envsize, &loadinfo->addrenv); + ret = up_addrenv_create(textsize, datasize, &loadinfo->addrenv); if (ret < 0) { bdbg("ERROR: up_addrenv_create failed: %d\n", ret); @@ -104,24 +109,33 @@ int elf_addrenv_alloc(FAR struct elf_loadinfo_s *loadinfo, size_t envsize) * selected. */ - ret = up_addrenv_vaddr(loadinfo->addrenv, &vaddr); + ret = up_addrenv_vtext(loadinfo->addrenv, &vtext); if (ret < 0) { - bdbg("ERROR: up_addrenv_vaddr failed: %d\n", ret); + bdbg("ERROR: up_addrenv_vtext failed: %d\n", ret); return ret; } - loadinfo->elfalloc = (uintptr_t)vaddr; + ret = up_addrenv_vdata(loadinfo->addrenv, textsize, &vdata); + if (ret < 0) + { + bdbg("ERROR: up_adup_addrenv_vdatadrenv_vtext failed: %d\n", ret); + return ret; + } + + loadinfo->textalloc = (uintptr_t)vaddr; + loadinfo->dataalloc = (uintptr_t)vdata; return OK; #else /* Allocate memory to hold the ELF image */ - loadinfo->elfalloc = (uintptr_t)kuzalloc(envsize); - if (!loadinfo->elfalloc) + loadinfo->textalloc = (uintptr_t)kuzalloc(textsize + datasize); + if (!loadinfo->textalloc) { return -ENOMEM; } + loadinfo->dataalloc = loadinfo->textalloc + textsize; return OK; #endif } @@ -159,18 +173,22 @@ void elf_addrenv_free(FAR struct elf_loadinfo_s *loadinfo) /* Clear out all indications of the allocated address environment */ - loadinfo->elfalloc = 0; - loadinfo->elfsize = 0; - loadinfo->addrenv = 0; + loadinfo->textalloc = 0; + loadinfo->dataalloc = 0; + loadinfo->textsize = 0; + loadinfo->datasize = 0; + loadinfo->addrenv = 0; #else /* If there is an allocation for the ELF image, free it */ - if (loadinfo->elfalloc != 0) + if (loadinfo->textalloc != 0) { - kufree((FAR void *)loadinfo->elfalloc); - loadinfo->elfalloc = 0; + kufree((FAR void *)loadinfo->textalloc); } - loadinfo->elfsize = 0; + loadinfo->textalloc = 0; + loadinfo->dataalloc = 0; + loadinfo->textsize = 0; + loadinfo->datasize = 0; #endif } diff --git a/nuttx/binfmt/libelf/libelf_bind.c b/nuttx/binfmt/libelf/libelf_bind.c index 9fd0fb73d..4d3d27f04 100644 --- a/nuttx/binfmt/libelf/libelf_bind.c +++ b/nuttx/binfmt/libelf/libelf_bind.c @@ -326,7 +326,7 @@ int elf_bind(FAR struct elf_loadinfo_s *loadinfo, /* Flush the instruction cache before starting the newly loaded module */ #ifdef CONFIG_ELF_ICACHE - arch_flushicache((FAR void*)loadinfo->elfalloc, loadinfo->elfsize); + arch_flushicache((FAR void*)loadinfo->textalloc, loadinfo->textsize); #endif return ret; diff --git a/nuttx/binfmt/libelf/libelf_ctors.c b/nuttx/binfmt/libelf/libelf_ctors.c index 0dfe64449..6cf35a62a 100644 --- a/nuttx/binfmt/libelf/libelf_ctors.c +++ b/nuttx/binfmt/libelf/libelf_ctors.c @@ -192,9 +192,10 @@ int elf_loadctors(FAR struct elf_loadinfo_s *loadinfo) FAR uintptr_t *ptr = (uintptr_t *)((FAR void *)(&loadinfo->ctors)[i]); bvdbg("ctor %d: %08lx + %08lx = %08lx\n", - i, *ptr, loadinfo->elfalloc, *ptr + loadinfo->elfalloc); + i, *ptr, (unsigned long)loadinfo->txtalloc, + (unsigned long)(*ptr + loadinfo->txtalloc)); - *ptr += loadinfo->elfalloc; + *ptr += loadinfo->txtalloc; } } else diff --git a/nuttx/binfmt/libelf/libelf_dtors.c b/nuttx/binfmt/libelf/libelf_dtors.c index 5cbba4851..e42ba6abf 100644 --- a/nuttx/binfmt/libelf/libelf_dtors.c +++ b/nuttx/binfmt/libelf/libelf_dtors.c @@ -192,9 +192,10 @@ int elf_loaddtors(FAR struct elf_loadinfo_s *loadinfo) FAR uintptr_t *ptr = (uintptr_t *)((FAR void *)(&loadinfo->dtors)[i]); bvdbg("dtor %d: %08lx + %08lx = %08lx\n", - i, *ptr, loadinfo->elfalloc, *ptr + loadinfo->elfalloc); + i, *ptr, (unsigned long)loadinfo->textalloc, + (unsigned long)(*ptr + loadinfo->textalloc)); - *ptr += loadinfo->elfalloc; + *ptr += loadinfo->textalloc; } } else diff --git a/nuttx/binfmt/libelf/libelf_load.c b/nuttx/binfmt/libelf/libelf_load.c index 600f85805..9f33abb40 100644 --- a/nuttx/binfmt/libelf/libelf_load.c +++ b/nuttx/binfmt/libelf/libelf_load.c @@ -88,12 +88,15 @@ static void elf_elfsize(struct elf_loadinfo_s *loadinfo) { - size_t elfsize; + size_t textsize; + size_t datasize; int i; /* Accumulate the size each section into memory that is marked SHF_ALLOC */ - elfsize = 0; + textsize = 0; + datasize = 0; + for (i = 0; i < loadinfo->ehdr.e_shnum; i++) { FAR Elf32_Shdr *shdr = &loadinfo->shdr[i]; @@ -104,13 +107,25 @@ static void elf_elfsize(struct elf_loadinfo_s *loadinfo) if ((shdr->sh_flags & SHF_ALLOC) != 0) { - elfsize += ELF_ALIGNUP(shdr->sh_size); + /* SHF_WRITE indicates that the section address space is write- + * able + */ + + if ((shdr->sh_flags & SHF_WRITE) != 0) + { + datasize += ELF_ALIGNUP(shdr->sh_size); + } + else + { + textsize += ELF_ALIGNUP(shdr->sh_size); + } } } /* Save the allocation size */ - loadinfo->elfsize = elfsize; + loadinfo->textsize = textsize; + loadinfo->datasize = datasize; } /**************************************************************************** @@ -129,13 +144,15 @@ static void elf_elfsize(struct elf_loadinfo_s *loadinfo) static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) { - FAR uint8_t *dest; + FAR uint8_t *text; + FAR uint8_t *data; + FAR uint8_t **pptr; int ret; int i; /* Allocate (and zero) memory for the ELF file. */ - ret = elf_addrenv_alloc(loadinfo, loadinfo->elfsize); + ret = elf_addrenv_alloc(loadinfo, loadinfo->textsize, loadinfo->datasize); if (ret < 0) { bdbg("ERROR: elf_addrenv_alloc() failed: %d\n", ret); @@ -145,7 +162,8 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) /* Read each section into memory that is marked SHF_ALLOC + SHT_NOBITS */ bvdbg("Loaded sections:\n"); - dest = (FAR uint8_t*)loadinfo->elfalloc; + text = (FAR uint8_t*)loadinfo->textalloc; + data = (FAR uint8_t*)loadinfo->dataalloc; for (i = 0; i < loadinfo->ehdr.e_shnum; i++) { @@ -165,8 +183,21 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) if (shdr->sh_type != SHT_NOBITS) { - /* If CONFIG_ARCH_ADDRENV=y, then 'dest' lies in a virtual address space - * that may not be in place now. elf_addrenv_select() will + /* SHF_WRITE indicates that the section address space is write- + * able + */ + + if ((shdr->sh_flags & SHF_WRITE) != 0) + { + pptr = &data; + } + else + { + pptr = &text; + } + + /* If CONFIG_ARCH_ADDRENV=y, then 'text' lies in a virtual address + * space that may not be in place now. elf_addrenv_select() will * temporarily instantiate that address space. */ @@ -179,9 +210,9 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) } #endif - /* Read the section data from sh_offset to dest */ + /* Read the section data from sh_offset to the memory region */ - ret = elf_read(loadinfo, dest, shdr->sh_size, shdr->sh_offset); + ret = elf_read(loadinfo, *pptr, shdr->sh_size, shdr->sh_offset); if (ret < 0) { bdbg("Failed to read section %d: %d\n", i, ret); @@ -202,12 +233,14 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) /* Update sh_addr to point to copy in memory */ - bvdbg("%d. %08x->%08x\n", i, (long)shdr->sh_addr, (long)dest); - shdr->sh_addr = (uintptr_t)dest; + bvdbg("%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 */ - dest += ELF_ALIGNUP(shdr->sh_size); + *pptr += ELF_ALIGNUP(shdr->sh_size); } return OK; |