Example #1
0
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;
}