diff options
Diffstat (limited to 'nuttx/binfmt/libnxflat/libnxflat_bind.c')
-rw-r--r-- | nuttx/binfmt/libnxflat/libnxflat_bind.c | 185 |
1 files changed, 154 insertions, 31 deletions
diff --git a/nuttx/binfmt/libnxflat/libnxflat_bind.c b/nuttx/binfmt/libnxflat/libnxflat_bind.c index ca348178d..816810a46 100644 --- a/nuttx/binfmt/libnxflat/libnxflat_bind.c +++ b/nuttx/binfmt/libnxflat/libnxflat_bind.c @@ -38,6 +38,7 @@ ****************************************************************************/ #include <nuttx/config.h> +#include <nuttx/compiler.h> #include <stdint.h> #include <string.h> @@ -47,8 +48,11 @@ #include <debug.h> #include <arpa/inet.h> -#include <nuttx/nxflat.h> -#include <nuttx/symtab.h> + +#include <nuttx/binfmt/nxflat.h> +#include <nuttx/binfmt/symtab.h> + +#include "libnxflat.h" /**************************************************************************** * Pre-processor Definitions @@ -229,8 +233,6 @@ static inline int nxflat_gotrelocs(FAR struct nxflat_loadinfo_s *loadinfo) hdr = (FAR struct nxflat_hdr_s*)loadinfo->ispace; - /* From this, we can get the list of relocation entries. */ - /* From this, we can get the offset to the list of relocation entries */ offset = ntohl(hdr->h_relocstart); @@ -247,11 +249,27 @@ static inline int nxflat_gotrelocs(FAR struct nxflat_loadinfo_s *loadinfo) DEBUGASSERT(offset + nrelocs * sizeof(struct nxflat_reloc_s) <= (loadinfo->isize + loadinfo->dsize)); - relocs = (FAR struct nxflat_reloc_s*) + relocs = (FAR struct nxflat_reloc_s *) (offset - loadinfo->isize + loadinfo->dspace->region); bvdbg("isize: %08lx dpsace: %p relocs: %p\n", (long)loadinfo->isize, loadinfo->dspace->region, relocs); + /* All relocations are performed within the D-Space allocation. If + * CONFIG_ADDRENV=y, then that D-Space allocation lies in an address + * environment that may not be in place. So, in that case, we must call + * nxflat_addrenv_select to temporarily instantiate that address space + * before the relocations can be performed. + */ + +#ifdef CONFIG_ADDRENV + ret = nxflat_addrenv_select(loadinfo); + if (ret < 0) + { + bdbg("ERROR: nxflat_addrenv_select() failed: %d\n", ret); + return ret; + } +#endif + /* Now, traverse the relocation list of and bind each GOT relocation. */ ret = OK; /* Assume success */ @@ -259,11 +277,16 @@ static inline int nxflat_gotrelocs(FAR struct nxflat_loadinfo_s *loadinfo) { /* Handle the relocation by the relocation type */ +#ifdef CONFIG_CAN_PASS_STRUCTS reloc = *relocs++; +#else + memcpy(&reloc, relocs, sizeof(struct nxflat_reloc_s)); + relocs++; +#endif + result = OK; switch (NXFLAT_RELOC_TYPE(reloc.r_info)) { - /* NXFLAT_RELOC_TYPE_REL32I Meaning: Object file contains a 32-bit offset * into I-Space at the offset. * Fixup: Add mapped I-Space address to the offset. @@ -329,6 +352,17 @@ static inline int nxflat_gotrelocs(FAR struct nxflat_loadinfo_s *loadinfo) nxflat_dumpbuffer("GOT", (FAR const uint8_t*)relocs, nrelocs * sizeof(struct nxflat_reloc_s)); } #endif + + /* Restore the original address environment */ + +#ifdef CONFIG_ADDRENV + ret = nxflat_addrenv_restore(loadinfo); + if (ret < 0) + { + bdbg("ERROR: nxflat_addrenv_restore() failed: %d\n", ret); + } +#endif + return ret; } @@ -346,16 +380,19 @@ static inline int nxflat_gotrelocs(FAR struct nxflat_loadinfo_s *loadinfo) ****************************************************************************/ static inline int nxflat_bindimports(FAR struct nxflat_loadinfo_s *loadinfo, - FAR const struct symtab_s *exports, - int nexports) + FAR const struct symtab_s *exports, + int nexports) { FAR struct nxflat_import_s *imports; FAR struct nxflat_hdr_s *hdr; - FAR const struct symtab_s *symbol; + FAR const struct symtab_s *symbol; char *symname; uint32_t offset; uint16_t nimports; +#ifdef CONFIG_ADDRENV + int ret; +#endif int i; /* The NXFLAT header is the first thing at the beginning of the ISpace. */ @@ -370,6 +407,22 @@ static inline int nxflat_bindimports(FAR struct nxflat_loadinfo_s *loadinfo, nimports = ntohs(hdr->h_importcount); bvdbg("Imports offset: %08x nimports: %d\n", offset, nimports); + /* The import[] table resides within the D-Space allocation. If + * CONFIG_ADDRENV=y, then that D-Space allocation lies in an address + * environment that may not be in place. So, in that case, we must call + * nxflat_addrenv_select to temporarily instantiate that address space + * before the import[] table can be modified. + */ + +#ifdef CONFIG_ADDRENV + ret = nxflat_addrenv_select(loadinfo); + if (ret < 0) + { + bdbg("ERROR: nxflat_addrenv_select() failed: %d\n", ret); + return ret; + } +#endif + /* Verify that this module requires imported symbols */ if (offset != 0 && nimports > 0) @@ -388,7 +441,7 @@ static inline int nxflat_bindimports(FAR struct nxflat_loadinfo_s *loadinfo, offset < loadinfo->isize + loadinfo->dsize); imports = (struct nxflat_import_s*) - (offset - loadinfo->isize + loadinfo->dspace->region); + (offset - loadinfo->isize + loadinfo->dspace->region); /* Now, traverse the list of imported symbols and attempt to bind * each symbol to the value exported by from the exported symbol @@ -396,41 +449,44 @@ static inline int nxflat_bindimports(FAR struct nxflat_loadinfo_s *loadinfo, */ for (i = 0; i < nimports; i++) - { - bvdbg("Import[%d] (%08p) offset: %08x func: %08x\n", - i, &imports[i], imports[i].i_funcname, imports[i].i_funcaddress); + { + bvdbg("Import[%d] (%08p) offset: %08x func: %08x\n", + i, &imports[i], imports[i].i_funcname, imports[i].i_funcaddress); - /* Get a pointer to the imported symbol name. The name itself - * lies in the TEXT segment. But the reference to the name - * lies in DATA segment. Therefore, the name reference should - * have been relocated when the module was loaded. - */ + /* Get a pointer to the imported symbol name. The name itself + * lies in the TEXT segment. But the reference to the name + * lies in DATA segment. Therefore, the name reference should + * have been relocated when the module was loaded. + */ offset = imports[i].i_funcname; DEBUGASSERT(offset < loadinfo->isize); - symname = (char*)(offset + loadinfo->ispace + sizeof(struct nxflat_hdr_s)); + symname = (char*)(offset + loadinfo->ispace + sizeof(struct nxflat_hdr_s)); - /* Find the exported symbol value for this this symbol name. */ + /* Find the exported symbol value for this this symbol name. */ #ifdef CONFIG_SYMTAB_ORDEREDBYNAME symbol = symtab_findorderedbyname(exports, symname, nexports); #else symbol = symtab_findbyname(exports, symname, nexports); #endif - if (!symbol) - { - bdbg("Exported symbol \"%s\" not found\n", symname); + if (!symbol) + { + bdbg("Exported symbol \"%s\" not found\n", symname); +#ifdef CONFIG_ADDRENV + (void)nxflat_addrenv_restore(loadinfo); +#endif return -ENOENT; - } + } - /* And put this into the module's import structure. */ + /* And put this into the module's import structure. */ - imports[i].i_funcaddress = (uint32_t)symbol->sym_value; + imports[i].i_funcaddress = (uint32_t)symbol->sym_value; - bvdbg("Bound import[%d] (%08p) to export '%s' (%08x)\n", - i, &imports[i], symname, imports[i].i_funcaddress); - } + bvdbg("Bound import[%d] (%08p) to export '%s' (%08x)\n", + i, &imports[i], symname, imports[i].i_funcaddress); + } } /* Dump the relocation import table */ @@ -441,7 +497,74 @@ static inline int nxflat_bindimports(FAR struct nxflat_loadinfo_s *loadinfo, nxflat_dumpbuffer("Imports", (FAR const uint8_t*)imports, nimports * sizeof(struct nxflat_import_s)); } #endif + + /* Restore the original address environment */ + +#ifdef CONFIG_ADDRENV + ret = nxflat_addrenv_restore(loadinfo); + if (ret < 0) + { + bdbg("ERROR: nxflat_addrenv_restore() failed: %d\n", ret); + } + + return ret; +#else + return OK; +#endif +} + +/**************************************************************************** + * Name: nxflat_clearbss + * + * Description: + * Clear uninitialized .bss memory + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +static inline int nxflat_clearbss(FAR struct nxflat_loadinfo_s *loadinfo) +{ +#ifdef CONFIG_ADDRENV + int ret; +#endif + + /* .bss resides within the D-Space allocation. If CONFIG_ADDRENV=y, then + * that D-Space allocation lies in an address environment that may not be + * in place. So, in that case, we must call nxflat_addrenv_select to + * temporarily instantiate that address space before the .bss can be + * accessed. + */ + +#ifdef CONFIG_ADDRENV + ret = nxflat_addrenv_select(loadinfo); + if (ret < 0) + { + bdbg("ERROR: nxflat_addrenv_select() failed: %d\n", ret); + return ret; + } +#endif + + /* Zero the BSS area */ + + memset((void*)(loadinfo->dspace->region + loadinfo->datasize), 0, + loadinfo->bsssize); + + /* Restore the original address environment */ + +#ifdef CONFIG_ADDRENV + ret = nxflat_addrenv_restore(loadinfo); + if (ret < 0) + { + bdbg("ERROR: nxflat_addrenv_restore() failed: %d\n", ret); + } + + return ret; +#else return OK; +#endif } /**************************************************************************** @@ -483,10 +606,10 @@ int nxflat_bind(FAR struct nxflat_loadinfo_s *loadinfo, * space in the loaded file. */ - memset((void*)(loadinfo->dspace->region + loadinfo->datasize), - 0, loadinfo->bsssize); + ret = nxflat_clearbss(loadinfo); } } + return ret; } |