long load_elf (int fd, char *buf, int *n, int flags) { Elf32_Ehdr *ep; Elf32_Phdr *phtab = 0; Elf32_Shdr *shtab = 0; unsigned int nbytes; int i; Elf32_Off highest_load = 0; bootseg = 0; myflags=flags; #ifdef __mips__ tablebase = PHYS_TO_CACHED(memorysize); #else tablebase = memorysize; #endif #if NGZIP > 0 lseek(fd,*n,0); read(fd,buf,2); if(((unsigned char)buf[0]==0x1f) && ((unsigned char)buf[1]==0x8b))flags |=ZFLAG; else flags &=~ZFLAG; myflags=flags; lseek(fd,*n,0); if(myflags&ZFLAG){ gz_open(fd); *n = 0; gz_lseek (fd, 0, SEEK_SET); } #endif /* NGZIP */ ep = (Elf32_Ehdr *)buf; if (sizeof(*ep) > *n) { #if NGZIP > 0 if(myflags&ZFLAG) *n += gz_read (fd, buf+*n, sizeof(*ep)-*n); else #endif /* NGZIP */ { lseek(fd,*n,0); *n += read (fd, buf+*n, sizeof(*ep)-*n); } if (*n < sizeof(*ep)) { #if NGZIP > 0 if(myflags&ZFLAG) gz_close(fd); #endif /* NGZIP */ return -1; } } /* check header validity */ if (ep->e_ident[EI_MAG0] != ELFMAG0 || ep->e_ident[EI_MAG1] != ELFMAG1 || ep->e_ident[EI_MAG2] != ELFMAG2 || ep->e_ident[EI_MAG3] != ELFMAG3) { #if NGZIP > 0 if(myflags&ZFLAG) gz_close(fd); #endif /* NGZIP */ return (-1); } fprintf (stderr, "(elf)\n"); { char *nogood = (char *)0; if (ep->e_ident[EI_CLASS] == ELFCLASS64) return load_elf64(fd, buf, n, flags); if (ep->e_ident[EI_CLASS] != ELFCLASS32) nogood = "not 32-bit"; else if ( #if BYTE_ORDER == BIG_ENDIAN ep->e_ident[EI_DATA] != ELFDATA2MSB #endif #if BYTE_ORDER == LITTLE_ENDIAN ep->e_ident[EI_DATA] != ELFDATA2LSB #endif ) nogood = "incorrect endianess"; else if (ep->e_ident[EI_VERSION] != EV_CURRENT) nogood = "version not current"; else if ( #ifdef powerpc ep->e_machine != EM_PPC #else /* default is MIPS */ #define GREENHILLS_HACK #ifdef GREENHILLS_HACK ep->e_machine != 10 && #endif ep->e_machine != EM_MIPS #endif ) nogood = "incorrect machine type"; if (nogood) { fprintf (stderr, "Invalid ELF: %s\n", nogood); #if NGZIP > 0 if(myflags&ZFLAG) gz_close(fd); #endif /* NGZIP */ return -2; } } /* Is there a program header? */ if (ep->e_phoff == 0 || ep->e_phnum == 0 || ep->e_phentsize != sizeof(Elf32_Phdr)) { fprintf (stderr, "missing program header (not executable)\n"); #if NGZIP > 0 if(myflags&ZFLAG) gz_close(fd); #endif /* NGZIP */ return (-2); } /* Load program header */ #if _ORIG_CODE_ nbytes = ep->e_phnum * sizeof(Elf32_Phdr); #else /* XXX: We need to figure out why it works by adding 32!!!! */ nbytes = ep->e_phnum * sizeof(Elf32_Phdr)+32; #endif phtab = (Elf32_Phdr *) malloc (nbytes); if (!phtab) { fprintf (stderr,"\nnot enough memory to read program headers"); #if NGZIP > 0 if(myflags&ZFLAG) gz_close(fd); #endif /* NGZIP */ return (-2); } #if NGZIP > 0 if(myflags&ZFLAG){ if (gz_lseek (fd, ep->e_phoff, SEEK_SET) != ep->e_phoff || gz_read (fd, (void *)phtab, nbytes) != nbytes) { perror ("program header"); free (phtab); gz_close(fd); return (-2); } }else #endif /* NGZIP */ if (lseek (fd, ep->e_phoff, SEEK_SET) != ep->e_phoff || read (fd, (void *)phtab, nbytes) != nbytes) { perror ("program header"); free (phtab); return (-2); } /* * From now on we've got no guarantee about the file order, * even where the section header is. Hopefully most linkers * will put the section header after the program header, when * they know that the executable is not demand paged. We assume * that the symbol and string tables always follow the program * segments. */ /* read section table (if before first program segment) */ if (!(flags & NFLAG) && ep->e_shoff < phtab[0].p_offset) shtab = elfgetshdr (fd, ep); /* load program segments */ if (!(flags & YFLAG)) { /* We cope with a badly sorted program header, as produced by * older versions of the GNU linker, by loading the segments * in file offset order, not in program header order. */ while (1) { Elf32_Off lowest_offset = ~0; Elf32_Phdr *ph = 0; /* find nearest loadable segment */ for (i = 0; i < ep->e_phnum; i++) if (phtab[i].p_type == PT_LOAD && phtab[i].p_offset < lowest_offset) { ph = &phtab[i]; lowest_offset = ph->p_offset; } if (!ph) break; /* none found, finished */ /* load the segment */ if (ph->p_filesz) { #if NGZIP > 0 if(myflags&ZFLAG){ if (gz_lseek (fd, ph->p_offset, SEEK_SET) != ph->p_offset) { fprintf (stderr, "seek failed (corrupt object file?)\n"); if (shtab) free (shtab); free (phtab); gz_close(fd); return (-2); } }else #endif /* NGZIP */ if (lseek (fd, ph->p_offset, SEEK_SET) != ph->p_offset) { fprintf (stderr, "seek failed (corrupt object file?)\n"); if (shtab) free (shtab); free (phtab); return (-2); } if (bootread (fd, (void *)ph->p_vaddr, ph->p_filesz) != ph->p_filesz) { if (shtab) free (shtab); free (phtab); #if NGZIP > 0 if(myflags&ZFLAG) gz_close(fd); #endif /* NGZIP */ return (-2); } } if((ph->p_vaddr + ph->p_memsz) > highest_load) { highest_load = ph->p_vaddr + ph->p_memsz; } if (ph->p_filesz < ph->p_memsz) bootclear (fd, (void *)ph->p_vaddr + ph->p_filesz, ph->p_memsz - ph->p_filesz); ph->p_type = PT_NULL; /* remove from consideration */ } } if (flags & KFLAG) { highest_load = roundup(highest_load, sizeof(long)); tablebase = highest_load; } if (!(flags & NFLAG)) { /* read section table (if after last program segment) */ if (!shtab) shtab = elfgetshdr (fd, ep); if (shtab) { elfreadsyms (fd, ep, shtab, flags); free (shtab); } } free (phtab); #if NGZIP > 0 if(myflags&ZFLAG) gz_close(fd); #endif /* NGZIP */ return (ep->e_entry + dl_offset); }
static int elfload_internal(fileio_ctx_t *fsctx,void *ref, unsigned long *entrypt,int flags) { Elf32_Ehdr *ep; Elf32_Phdr *phtab = 0; Elf32_Shdr *shtab = 0; unsigned int nbytes; int i; int res; Elf32_Ehdr ehdr; ep = &ehdr; if (fs_read(fsctx,ref,(uint8_t *) ep,sizeof(*ep)) != sizeof(*ep)) { return CFE_ERR_IOERR; } /* check header validity */ if (ep->e_ident[EI_MAG0] != ELFMAG0 || ep->e_ident[EI_MAG1] != ELFMAG1 || ep->e_ident[EI_MAG2] != ELFMAG2 || ep->e_ident[EI_MAG3] != ELFMAG3) { return CFE_ERR_NOTELF; } if (ep->e_ident[EI_CLASS] != ELFCLASS32) return CFE_ERR_NOT32BIT; #ifdef __MIPSEB if (ep->e_ident[EI_DATA] != ELFDATA2MSB) return CFE_ERR_WRONGENDIAN; /* big endian */ #endif #ifdef __MIPSEL if (ep->e_ident[EI_DATA] != ELFDATA2LSB) return CFE_ERR_WRONGENDIAN; /* little endian */ #endif if (ep->e_ident[EI_VERSION] != EV_CURRENT) return CFE_ERR_BADELFVERS; if (ep->e_machine != EM_MIPS) return CFE_ERR_NOTMIPS; /* Is there a program header? */ if (ep->e_phoff == 0 || ep->e_phnum == 0 || ep->e_phentsize != sizeof(Elf32_Phdr)) { return CFE_ERR_BADELFFMT; } /* Load program header */ nbytes = ep->e_phnum * sizeof(Elf32_Phdr); phtab = (Elf32_Phdr *) KMALLOC(nbytes,0); if (!phtab) { return CFE_ERR_NOMEM; } if (fs_seek(fsctx,ref,ep->e_phoff,FILE_SEEK_BEGINNING) != ep->e_phoff || fs_read(fsctx,ref,(uint8_t *)phtab,nbytes) != nbytes) { KFREE(phtab); return CFE_ERR_IOERR; } /* * From now on we've got no guarantee about the file order, * even where the section header is. Hopefully most linkers * will put the section header after the program header, when * they know that the executable is not demand paged. We assume * that the symbol and string tables always follow the program * segments. */ /* read section table (if before first program segment) */ if (ep->e_shoff < phtab[0].p_offset) { shtab = elfgetshdr(fsctx,ref,ep); } /* load program segments */ /* We cope with a badly sorted program header, as produced by * older versions of the GNU linker, by loading the segments * in file offset order, not in program header order. */ while (1) { Elf32_Off lowest_offset = ~0; Elf32_Phdr *ph = 0; /* find nearest loadable segment */ for (i = 0; i < ep->e_phnum; i++) if ((phtab[i].p_type == PT_LOAD) && (phtab[i].p_offset < lowest_offset)) { ph = &phtab[i]; lowest_offset = ph->p_offset; } if (!ph) { break; /* none found, finished */ } /* load the segment */ if (ph->p_filesz) { if (fs_seek(fsctx,ref,ph->p_offset,FILE_SEEK_BEGINNING) != ph->p_offset) { if (shtab) KFREE(shtab); KFREE(phtab); return CFE_ERR_BADELFFMT; } res = readprogsegment(fsctx,ref, (void *)(intptr_t)(signed)ph->p_vaddr, ph->p_filesz,flags); if (res != ph->p_filesz) { if (shtab) KFREE(shtab); KFREE(phtab); return res; } } if (ph->p_filesz < ph->p_memsz) { res = readclearbss((void *)(intptr_t)(signed)ph->p_vaddr + ph->p_filesz, ph->p_memsz - ph->p_filesz,flags); if (res < 0) { if (shtab) KFREE(shtab); KFREE(phtab); return res; } } ph->p_type = PT_NULL; /* remove from consideration */ } KFREE(phtab); *entrypt = (intptr_t)(signed)ep->e_entry; /* return entry point */ return 0; }