/* return < 0 if error, otherwise the number of bytes loaded in memory */ int load_elf(const char *filename, int64_t virt_to_phys_addend, uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr) { int fd, data_order, host_data_order, must_swab, ret; uint8_t e_ident[EI_NIDENT]; fd = open(filename, O_RDONLY | O_BINARY); if (fd < 0) { perror(filename); return -1; } if (read(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident)) goto fail; if (e_ident[0] != ELFMAG0 || e_ident[1] != ELFMAG1 || e_ident[2] != ELFMAG2 || e_ident[3] != ELFMAG3) goto fail; #ifdef WORDS_BIGENDIAN data_order = ELFDATA2MSB; #else data_order = ELFDATA2LSB; #endif must_swab = data_order != e_ident[EI_DATA]; #ifdef TARGET_WORDS_BIGENDIAN host_data_order = ELFDATA2MSB; #else host_data_order = ELFDATA2LSB; #endif if (host_data_order != e_ident[EI_DATA]) return -1; lseek(fd, 0, SEEK_SET); if (e_ident[EI_CLASS] == ELFCLASS64) { ret = load_elf64(fd, virt_to_phys_addend, must_swab, pentry, lowaddr, highaddr); } else { ret = load_elf32(fd, virt_to_phys_addend, must_swab, pentry, lowaddr, highaddr); } close(fd); return ret; fail: close(fd); return -1; }
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); }