static int nxflat_loadbinary(struct binary_s *binp) { struct nxflat_loadinfo_s loadinfo; /* Contains globals for libnxflat */ int ret; bvdbg("Loading file: %s\n", binp->filename); /* Initialize the xflat library to load the program binary. */ ret = nxflat_init(binp->filename, &loadinfo); nxflat_dumploadinfo(&loadinfo); if (ret != 0) { bdbg("Failed to initialize for load of NXFLT program: %d\n", ret); goto errout; } /* Load the program binary */ ret = nxflat_load(&loadinfo); nxflat_dumploadinfo(&loadinfo); if (ret != 0) { bdbg("Failed to load NXFLT program binary: %d\n", ret); goto errout_with_init; } /* Bind the program to the exported symbol table */ ret = nxflat_bind(&loadinfo, binp->exports, binp->nexports); if (ret != 0) { bdbg("Failed to bind symbols program binary: %d\n", ret); goto errout_with_load; } /* Return the load information */ binp->entrypt = (main_t)(loadinfo.ispace + loadinfo.entryoffs); binp->ispace = (void*)loadinfo.ispace; binp->dspace = (void*)loadinfo.dspace; binp->isize = loadinfo.isize; binp->stacksize = loadinfo.stacksize; nxflat_dumpbuffer("Entry code", (FAR const uint8_t*)binp->entrypt, MIN(binp->isize - loadinfo.entryoffs,512)); nxflat_uninit(&loadinfo); return OK; errout_with_load: nxflat_unload(&loadinfo); errout_with_init: nxflat_uninit(&loadinfo); errout: return ret; }
int nxflat_init(const char *filename, struct nxflat_loadinfo_s *loadinfo) { uint32_t datastart; uint32_t dataend; uint32_t bssstart; uint32_t bssend; int ret; bvdbg("filename: %s loadinfo: %p\n", filename, loadinfo); /* Clear the load info structure */ memset(loadinfo, 0, sizeof(struct nxflat_loadinfo_s)); /* Open the binary file */ loadinfo->filfd = open(filename, O_RDONLY); if (loadinfo->filfd < 0) { bdbg("Failed to open NXFLAT binary %s: %d\n", filename, ret); return -errno; } /* Read the NXFLAT header from offset 0 */ ret = nxflat_read(loadinfo, (char*)&loadinfo->header, sizeof(struct nxflat_hdr_s), 0); if (ret < 0) { bdbg("Failed to read NXFLAT header: %d\n", ret); return ret; } nxflat_dumpbuffer("NXFLAT header", (FAR const uint8_t*)&loadinfo->header, sizeof(struct nxflat_hdr_s)); /* Verify the NXFLAT header */ if (nxflat_verifyheader(&loadinfo->header) != 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 NXFLAT file. Besides, if there is something worth * complaining about, nnxflat_verifyheader() has already * done so. */ bdbg("Bad NXFLAT header\n"); return -ENOEXEC; } /* 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; }
static inline int nxflat_bindimports(FAR struct nxflat_loadinfo_s *loadinfo, 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; char *symname; uint32_t offset; uint16_t nimports; #ifdef CONFIG_ARCH_ADDRENV int ret; #endif int i; /* The NXFLAT header is the first thing at the beginning of the ISpace. */ hdr = (FAR struct nxflat_hdr_s *)loadinfo->ispace; /* From this, we can get the offset to the list of symbols imported by * this module and the number of symbols imported by this module. */ offset = ntohl(hdr->h_importsymbols); nimports = ntohs(hdr->h_importcount); binfo("Imports offset: %08x nimports: %d\n", offset, nimports); /* The import[] table resides within the D-Space allocation. If * CONFIG_ARCH_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_ARCH_ADDRENV ret = nxflat_addrenv_select(loadinfo); if (ret < 0) { berr("ERROR: nxflat_addrenv_select() failed: %d\n", ret); return ret; } #endif /* Verify that this module requires imported symbols */ if (offset != 0 && nimports > 0) { /* It does.. make sure that exported symbols are provided */ DEBUGASSERT(exports && nexports > 0); /* If non-zero, the value of the imported symbol list that we get * from the header is a file offset. We will have to convert this * to an offset into the DSpace segment to get the pointer to the * beginning of the imported symbol list. */ DEBUGASSERT(offset >= loadinfo->isize && offset < loadinfo->isize + loadinfo->dsize); imports = (FAR struct nxflat_import_s *) (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 * table. */ for (i = 0; i < nimports; i++) { binfo("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. */ offset = imports[i].i_funcname; DEBUGASSERT(offset < loadinfo->isize); symname = (FAR char *)(offset + loadinfo->ispace + sizeof(struct nxflat_hdr_s)); /* 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) { berr("Exported symbol \"%s\" not found\n", symname); #ifdef CONFIG_ARCH_ADDRENV (void)nxflat_addrenv_restore(loadinfo); #endif return -ENOENT; } /* And put this into the module's import structure. */ imports[i].i_funcaddress = (uint32_t)symbol->sym_value; binfo("Bound import[%d] (%08p) to export '%s' (%08x)\n", i, &imports[i], symname, imports[i].i_funcaddress); } } /* Dump the relocation import table */ #ifdef CONFIG_NXFLAT_DUMPBUFFER if (nimports > 0) { nxflat_dumpbuffer("Imports", (FAR const uint8_t *)imports, nimports * sizeof(struct nxflat_import_s)); } #endif /* Restore the original address environment */ #ifdef CONFIG_ARCH_ADDRENV ret = nxflat_addrenv_restore(loadinfo); if (ret < 0) { berr("ERROR: nxflat_addrenv_restore() failed: %d\n", ret); } return ret; #else return OK; #endif }
static inline int nxflat_gotrelocs(FAR struct nxflat_loadinfo_s *loadinfo) { FAR struct nxflat_reloc_s *relocs; FAR struct nxflat_reloc_s reloc; FAR struct nxflat_hdr_s *hdr; uint32_t offset; uint16_t nrelocs; int ret; int result; int i; /* The NXFLAT header is the first thing at the beginning of the ISpace. */ hdr = (FAR struct nxflat_hdr_s *)loadinfo->ispace; /* From this, we can get the offset to the list of relocation entries */ offset = ntohl(hdr->h_relocstart); nrelocs = ntohs(hdr->h_reloccount); binfo("offset: %08lx nrelocs: %d\n", (long)offset, nrelocs); /* The value of the relocation list that we get from the header is a * file offset. We will have to convert this to an offset into the * DSpace segment to get the pointer to the beginning of the relocation * list. */ DEBUGASSERT(offset >= loadinfo->isize); DEBUGASSERT(offset + nrelocs * sizeof(struct nxflat_reloc_s) <= (loadinfo->isize + loadinfo->dsize)); relocs = (FAR struct nxflat_reloc_s *) (offset - loadinfo->isize + loadinfo->dspace->region); binfo("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_ARCH_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_ARCH_ADDRENV ret = nxflat_addrenv_select(loadinfo); if (ret < 0) { berr("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 */ for (i = 0; i < nrelocs; i++) { /* 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. */ case NXFLAT_RELOC_TYPE_REL32I: { result = nxflat_bindrel32i(loadinfo, NXFLAT_RELOC_OFFSET(reloc.r_info)); } break; /* NXFLAT_RELOC_TYPE_REL32D Meaning: Object file contains a 32-bit offset * into D-Space at the offset. * Fixup: Add allocated D-Space address to the * offset. */ case NXFLAT_RELOC_TYPE_REL32D: { result = nxflat_bindrel32d(loadinfo, NXFLAT_RELOC_OFFSET(reloc.r_info)); } break; /* NXFLAT_RELOC_TYPE_REL32ID Meaning: Object file contains a 32-bit offset * into I-Space at the offset that will * unfortunately be references relative * to the GOT * Fixup: Add allocated the mapped I-Space * address MINUS the allocated D-Space * address to the offset. */ #ifdef NXFLAT_RELOC_TYPE_REL32ID case NXFLAT_RELOC_TYPE_REL32ID: { result = nxflat_bindrel32id(loadinfo, NXFLAT_RELOC_OFFSET(reloc.r_info)); } break; #endif default: { berr("ERROR: Unrecognized relocation type: %d\n", NXFLAT_RELOC_TYPE(reloc.r_info)); result = -EINVAL; } break; } /* Check for failures */ if (result < 0 && ret == OK) { ret = result; } } /* Dump the relocation got */ #ifdef CONFIG_NXFLAT_DUMPBUFFER if (ret == OK && nrelocs > 0) { relocs = (FAR struct nxflat_reloc_s *)(offset - loadinfo->isize + loadinfo->dspace->region); nxflat_dumpbuffer("GOT", (FAR const uint8_t *)relocs, nrelocs * sizeof(struct nxflat_reloc_s)); } #endif /* Restore the original address environment */ #ifdef CONFIG_ARCH_ADDRENV ret = nxflat_addrenv_restore(loadinfo); if (ret < 0) { berr("ERROR: nxflat_addrenv_restore() failed: %d\n", ret); } #endif return ret; }