/* ELF object format functions. Copyright 1999, 2000, 2001 Johan Rydberg, jrydberg@opencores.org. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "tm.h" #include "trace.h" #include "objfmt-elf.h" #include "vm-kmem.h" /* Read ELF object file into memory, using READ_FN and WRITE_FN. Entry address for first thread is returned in ENTRYP. */ kern_return_t elf_load (void *handle, objfmt_read_fn read_fn, objfmt_write_fn write_fn, vm_offset_t *entryp) { Elf32_Phdr *phdr, *ph; Elf32_Ehdr x; vm_size_t actual, phsize; int i, result; /* Read the ELF header. */ result = (*read_fn) (handle, 0, &x, sizeof (Elf32_Ehdr), &actual); if (result || actual < sizeof (Elf32_Ehdr)) return KERN_INVALID_ARGUMENT; /* Check ELF magic value. */ if ((x.e_ident[EI_MAG0] != ELFMAG0) || (x.e_ident[EI_MAG1] != ELFMAG1) || (x.e_ident[EI_MAG2] != ELFMAG2) || (x.e_ident[EI_MAG3] != ELFMAG3)) return KERN_INVALID_ARGUMENT; /* Make sure the file is of the right architecture. */ #if __i386__ if (x.e_ident [EI_CLASS] != ELFCLASS32 || x.e_ident [EI_DATA] != ELFDATA2LSB || x.e_machine != EM_386) return KERN_INVALID_HOST; #elif __powerpc__ if (x.e_ident [EI_CLASS] != ELFCLASS32 || x.e_ident [EI_DATA] != ELFDATA2LSB || x.e_machine != EM_PPC) return KERN_INVALID_HOST; #else # error "unsupported host?" #endif /* Allocate memory for program headers. */ phsize = x.e_phnum * x.e_phentsize; phdr = (Elf32_Phdr *) kmem_malloc (phsize); assert (phdr); /* Read program headers. */ result = (*read_fn) (handle, x.e_phoff, phdr, phsize, &actual); if (result) return result; if (actual < phsize) return KERN_FAILURE; /* Load program sections. */ for (i = 0; i < x.e_phnum; i++) { ph = (Elf32_Phdr *) ((vm_offset_t) phdr + i * x.e_phentsize); if (ph->p_type == PT_LOAD) { vm_prot_t protection = 0; if (ph->p_flags & PF_R) protection |= VM_PROT_READ; if (ph->p_flags & PF_W) protection |= VM_PROT_WRITE; if (ph->p_flags & PF_X) protection |= VM_PROT_EXEC; result = (*write_fn) (handle, ph->p_offset, ph->p_filesz, ph->p_vaddr, ph->p_memsz, protection); assert (result == 0); } } kmem_mfree (phdr); *entryp = (vm_offset_t) x.e_entry; return 0; }