libspe2 0.9a
elf_loader.c
Go to the documentation of this file.
00001 /*
00002  * libspe2 - A wrapper to allow direct execution of SPE binaries
00003  * Copyright (C) 2005 IBM Corp.
00004  *
00005  * This library is free software; you can redistribute it and/or modify it
00006  * under the terms of the GNU Lesser General Public License as published by
00007  * the Free Software Foundation; either version 2.1 of the License,
00008  * or (at your option) any later version.
00009  *
00010  *  This library is distributed in the hope that it will be useful, but
00011  *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
00012  *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
00013  *  License for more details.
00014  *
00015  *   You should have received a copy of the GNU Lesser General Public License
00016  *   along with this library; if not, write to the Free Software Foundation,
00017  *   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00018  */
00019 
00020 #include <elf.h>
00021 #include <errno.h>
00022 #include <fcntl.h>
00023 #include <malloc.h>
00024 #include <stdlib.h>
00025 #include <stdio.h>
00026 #include <string.h>
00027 #include <unistd.h>
00028 
00029 #include <sys/mman.h>
00030 #include <sys/types.h>
00031 #include <sys/stat.h>
00032 
00033 #include "elf_loader.h"
00034 #include "spebase.h"
00035 
00036 #ifdef DEBUG
00037 static void display_debug_output(Elf32_Ehdr *elf_start, Elf32_Shdr *sh);
00038 #endif /*DEBUG*/
00039 
00040 #define __PRINTF(fmt, args...) { fprintf(stderr,fmt , ## args); }
00041 #ifdef DEBUG
00042 #define DEBUG_PRINTF(fmt, args...) __PRINTF(fmt , ## args)
00043 #define TAG DEBUG_PRINTF("TAG: %d@%s\n", __LINE__, __FILE__);
00044 #else
00045 #define DEBUG_PRINTF(fmt, args...)
00046 #define TAG
00047 #endif
00048 
00049 static const unsigned char expected[EI_PAD] = {
00050         [EI_MAG0] = ELFMAG0,
00051         [EI_MAG1] = ELFMAG1,
00052         [EI_MAG2] = ELFMAG2,
00053         [EI_MAG3] = ELFMAG3,
00054         [EI_CLASS] = ELFCLASS32,
00055         [EI_DATA] = ELFDATA2MSB,
00056         [EI_VERSION] = EV_CURRENT,
00057         [EI_OSABI] = ELFOSABI_SYSV,
00058         [EI_ABIVERSION] = 0
00059 };
00060 
00061 static int
00062 check_spe_elf(Elf32_Ehdr *ehdr)
00063 {
00064         /* Validate ELF */
00065         if (memcmp (ehdr->e_ident, expected, EI_PAD) != 0)
00066           {
00067                   DEBUG_PRINTF ("invalid ELF header.\n");
00068                   DEBUG_PRINTF ("expected 0x%016llX != 0x%016llX\n",
00069                                 *(long long *) expected, *(long long *) (ehdr->e_ident));
00070                   errno = EINVAL;
00071                   return -errno;
00072           }
00073 
00074         /* Validate the machine type */
00075         if (ehdr->e_machine != 0x17)
00076           {
00077                   DEBUG_PRINTF ("not an SPE ELF object");
00078                   errno = EINVAL;
00079                   return -errno;
00080           }
00081 
00082         /* Validate ELF object type. */
00083         if (ehdr->e_type != ET_EXEC)
00084           {
00085                   DEBUG_PRINTF ("invalid SPE ELF type.\n");
00086                   DEBUG_PRINTF ("SPE type %d != %d\n", ehdr->e_type, ET_EXEC);
00087                   errno = EINVAL;
00088                   DEBUG_PRINTF ("parse_spu_elf(): errno=%d.\n", errno);
00089                   return -errno;
00090           }
00091 
00092         return 0;
00093 
00094 }
00098 int  
00099 _base_spe_verify_spe_elf_image(spe_program_handle_t *handle)
00100 {
00101         Elf32_Ehdr *ehdr;
00102         void *elf_start;
00103         
00104         elf_start = handle->elf_image;
00105         ehdr = (Elf32_Ehdr *)(handle->elf_image);
00106 
00107         return check_spe_elf(ehdr);
00108 }
00109 
00110 int
00111 _base_spe_parse_isolated_elf(spe_program_handle_t *handle,
00112                 uint64_t *addr, uint32_t *size)
00113 {
00114         Elf32_Ehdr *ehdr = (Elf32_Ehdr *)handle->elf_image;
00115         Elf32_Phdr *phdr;
00116 
00117         if (!ehdr) {
00118                 DEBUG_PRINTF("No ELF image has been loaded\n");
00119                 errno = EINVAL;
00120                 return -errno;
00121         }
00122 
00123         if (ehdr->e_phentsize != sizeof(*phdr)) {
00124                 DEBUG_PRINTF("Invalid program header format (phdr size=%d)\n",
00125                                 ehdr->e_phentsize);
00126                 errno = EINVAL;
00127                 return -errno;
00128         }
00129 
00130         if (ehdr->e_phnum != 1) {
00131                 DEBUG_PRINTF("Invalid program header count (%d), expected 1\n",
00132                                 ehdr->e_phnum);
00133                 errno = EINVAL;
00134                 return -errno;
00135         }
00136 
00137         phdr = (Elf32_Phdr *)(handle->elf_image + ehdr->e_phoff);
00138 
00139         if (phdr->p_type != PT_LOAD || phdr->p_memsz == 0) {
00140                 DEBUG_PRINTF("SPE program segment is not loadable (type=%x)\n",
00141                                 phdr->p_type);
00142                 errno = EINVAL;
00143                 return -errno;
00144         }
00145 
00146         if (addr)
00147                 *addr = (uint64_t)(unsigned long)
00148                         (handle->elf_image + phdr->p_offset);
00149 
00150         if (size)
00151                 *size = phdr->p_memsz;
00152 
00153         return 0;
00154 }
00155 
00156 static int
00157 overlay(Elf32_Phdr *ph, Elf32_Phdr *prev_ph)
00158 {
00159         /*
00160          * If our ph segment virtual address fits within that of the
00161          * previous ph, this is an overlay.
00162          */
00163         if (prev_ph && (ph->p_vaddr >= prev_ph->p_vaddr) &&
00164             (ph->p_vaddr < (prev_ph->p_vaddr + prev_ph->p_memsz)))
00165                 return 1;
00166         else
00167                 return 0;
00168 }
00169 
00170 static void
00171 copy_to_ld_buffer(spe_program_handle_t *handle, void *buffer, Elf32_Phdr
00172                   *ph, Elf32_Off toe_addr, long toe_size)
00173 {
00174         void *start = handle->elf_image;
00175 
00176         DEBUG_PRINTF("SPE_LOAD %p (0x%x) -> %p (0x%x) (%i bytes)\n",
00177                      buffer + ph->p_vaddr, ph->p_vaddr, start + ph->p_offset,
00178                      ph->p_offset, ph->p_filesz);
00179 
00180         /* toe segment comes from the shadow */
00181         if (ph->p_vaddr == toe_addr) {
00182                 /* still makes a copy if toe is buried with other
00183                  * sections */
00184                 if (toe_size != ph->p_filesz && ph->p_filesz) {
00185                         DEBUG_PRINTF("loading base copy\n");
00186                         memcpy(buffer + ph->p_vaddr, start + ph->p_offset,
00187                                ph->p_filesz);
00188                 }
00189 
00190                 /* overlay only the total toe section size */
00191                 DEBUG_PRINTF("loading toe %X %X\n", ph->p_offset, toe_addr);
00192                 memcpy(buffer + ph->p_vaddr, handle->toe_shadow, toe_size);
00193         } else if (ph->p_filesz) {
00194                 memcpy(buffer + ph->p_vaddr, start + ph->p_offset,
00195                        ph->p_filesz);
00196         }
00197         DEBUG_PRINTF("done ...\n");
00198 }
00199 
00200 int
00201 _base_spe_load_spe_elf (spe_program_handle_t *handle, void *ld_buffer, struct spe_ld_info *ld_info)
00202 {
00203         Elf32_Ehdr *ehdr;
00204         Elf32_Phdr *phdr;
00205         Elf32_Phdr *ph, *prev_ph;
00206 
00207         Elf32_Shdr *shdr;
00208         Elf32_Shdr *sh;
00209 
00210         Elf32_Off  toe_addr = 0;
00211         long    toe_size = 0;
00212 
00213         char* str_table = 0;
00214 
00215         int num_load_seg = 0;
00216         void *elf_start;
00217         int ret;
00218         
00219         DEBUG_PRINTF ("load_spe_elf(%p, %p)\n", handle, ld_buffer);
00220 
00221         elf_start = handle->elf_image;
00222 
00223         DEBUG_PRINTF ("load_spe_elf(%p, %p)\n", handle->elf_image, ld_buffer);
00224         ehdr = (Elf32_Ehdr *)(handle->elf_image);
00225 
00226         /* Check for a Valid SPE ELF Image (again) */
00227         if ((ret=check_spe_elf(ehdr)))
00228                 return ret;
00229 
00230         /* Start processing headers */
00231         phdr = (Elf32_Phdr *) ((char *) ehdr + ehdr->e_phoff);
00232         shdr = (Elf32_Shdr *) ((char *) ehdr + ehdr->e_shoff);
00233         str_table = (char*)ehdr + shdr[ehdr->e_shstrndx].sh_offset;
00234 
00235         /* traverse the sections to locate the toe segment */
00236         /* by specification, the toe sections are grouped together in a segment */
00237         for (sh = shdr; sh < &shdr[ehdr->e_shnum]; ++sh)
00238         {
00239                 DEBUG_PRINTF("section name: %s ( start: 0x%04x, size: 0x%04x)\n", str_table+sh->sh_name, sh->sh_offset, sh->sh_size );
00240                 if (strcmp(".toe", str_table+sh->sh_name) == 0) {
00241                         DEBUG_PRINTF("section offset: %d\n", sh->sh_offset);
00242                         toe_size += sh->sh_size;
00243                         if ((toe_addr == 0) || (toe_addr > sh->sh_addr))
00244                                 toe_addr = sh->sh_addr;
00245                 }
00246                 /* Disabled : Actually not needed, only good for testing
00247                 if (strcmp(".bss", str_table+sh->sh_name) == 0) {
00248                         DEBUG_PRINTF("zeroing .bss section:\n");
00249                         DEBUG_PRINTF("section offset: 0x%04x\n", sh->sh_offset);
00250                         DEBUG_PRINTF("section size: 0x%04x\n", sh->sh_size);
00251                         memset(ld_buffer + sh->sh_offset, 0, sh->sh_size);
00252                 }  */
00253                 
00254 #ifdef DEBUG
00255                 if (strcmp(".note.spu_name", str_table+sh->sh_name) == 0) 
00256                         display_debug_output(elf_start, sh);
00257 #endif /*DEBUG*/
00258         }
00259 
00260         /*
00261          * Load all PT_LOAD segments onto the SPE local store buffer.
00262          */
00263         DEBUG_PRINTF("Segments: 0x%x\n", ehdr->e_phnum);
00264         for (ph = phdr, prev_ph = NULL; ph < &phdr[ehdr->e_phnum]; ++ph) {
00265                 switch (ph->p_type) {
00266                 case PT_LOAD:
00267                         if (!overlay(ph, prev_ph)) {
00268                                 if (ph->p_filesz < ph->p_memsz) {
00269                                         DEBUG_PRINTF("padding loaded image with zeros:\n");
00270                                         DEBUG_PRINTF("start: 0x%04x\n", ph->p_vaddr + ph->p_filesz);
00271                                         DEBUG_PRINTF("length: 0x%04x\n", ph->p_memsz - ph->p_filesz);
00272                                         memset(ld_buffer + ph->p_vaddr + ph->p_filesz, 0, ph->p_memsz - ph->p_filesz);
00273                                 }
00274                                 copy_to_ld_buffer(handle, ld_buffer, ph,
00275                                                   toe_addr, toe_size);
00276                                 num_load_seg++;
00277                         }
00278                         break;
00279                 case PT_NOTE:
00280                         DEBUG_PRINTF("SPE_LOAD found PT_NOTE\n");
00281                         break;
00282                 }
00283         }
00284         if (num_load_seg == 0)
00285           {
00286                   DEBUG_PRINTF ("no segments to load");
00287                   errno = EINVAL;
00288                   return -errno;
00289           }
00290 
00291         /* Remember where the code wants to be started */
00292         ld_info->entry = ehdr->e_entry;
00293         DEBUG_PRINTF ("entry = 0x%x\n", ehdr->e_entry);
00294 
00295         return 0;
00296 
00297 }
00298 
00299 #ifdef DEBUG
00300 static void
00301 display_debug_output(Elf32_Ehdr *elf_start, Elf32_Shdr *sh)
00302 {
00303         typedef struct
00304         {
00305                 unsigned long namesz;
00306                 unsigned long descsz;
00307                 unsigned long type;
00308                 char name[8];
00309                 char lookupname[32];
00310         } ELF_NOTE;
00311 
00312         ELF_NOTE *note = (ELF_NOTE *)((void *)elf_start+sh->sh_offset);
00313         printf ("Loading SPE program : %s\n", note->lookupname);
00314         printf ("SPU LS Entry Addr   : 0x%05x\n", elf_start->e_entry);
00315 }
00316 #endif /*DEBUG*/
00317 
00318 static int
00319 toe_check_syms(Elf32_Ehdr *ehdr, Elf32_Shdr *sh)
00320 {
00321         Elf32_Sym  *sym, *sym_hdr, *sym_end;
00322         Elf32_Shdr *shdr;
00323         char *str_table;
00324         char *sym_name;
00325         int ret;
00326 
00327         shdr = (Elf32_Shdr*) ((char*) ehdr + ehdr->e_shoff);
00328         sym_hdr = (Elf32_Sym*) ((char*) ehdr + sh->sh_offset);
00329         sym_end = (Elf32_Sym*) ((char*) ehdr + sh->sh_offset + sh->sh_size);
00330         str_table = (char*)ehdr + shdr[sh->sh_link].sh_offset;
00331 
00332         ret = 0;
00333         for (sym = sym_hdr; sym < sym_end; sym++)
00334                 if (sym->st_name) {
00335                         sym_name = str_table + sym->st_name;
00336                         if ((strncmp(sym_name, "_EAR_", 5) == 0) &&
00337                             (strcmp(sym_name, "_EAR_") != 0)) {
00338                                 /*
00339                                  * We have a prefix of _EAR_ followed by
00340                                  * something else. This is not currently
00341                                  * (and might not ever be) supported: for
00342                                  * a _EAR_foo, it requires a lookup of foo
00343                                  * in the ppu ELF file.
00344                                  */
00345                                 fprintf(stderr, "Invalid _EAR_ symbol '%s'\n",
00346                                         sym_name);
00347                                 errno = EINVAL;
00348                                 ret = 1;
00349                         }
00350                 }
00351         return ret;
00352 }
00353 
00354 int _base_spe_toe_ear (spe_program_handle_t *speh)
00355 {
00356         Elf32_Ehdr *ehdr;
00357         Elf32_Shdr *shdr, *sh;
00358         char *str_table;
00359         char **ch;
00360         int ret;
00361         long toe_size;
00362 
00363         ehdr = (Elf32_Ehdr*) (speh->elf_image);
00364         shdr = (Elf32_Shdr*) ((char*) ehdr + ehdr->e_shoff);
00365         str_table = (char*)ehdr + shdr[ehdr->e_shstrndx].sh_offset;
00366 
00367         toe_size = 0;
00368         for (sh = shdr; sh < &shdr[ehdr->e_shnum]; ++sh)
00369                 if (strcmp(".toe", str_table + sh->sh_name) == 0)
00370                         toe_size += sh->sh_size;
00371 
00372         ret = 0;
00373         if (toe_size > 0) {
00374                 for (sh = shdr; sh < &shdr[ehdr->e_shnum]; ++sh)
00375                         if (sh->sh_type == SHT_SYMTAB || sh->sh_type ==
00376                             SHT_DYNSYM)
00377                                 ret = toe_check_syms(ehdr, sh);
00378                 if (!ret && toe_size != 16) {
00379                         /* Paranoia */
00380                         fprintf(stderr, "Unexpected toe size of %ld\n",
00381                                 toe_size);
00382                         errno = EINVAL;
00383                         ret = 1;
00384                 }
00385         }
00386         if (!ret && toe_size) {
00387                 /*
00388                  * Allocate toe_shadow, and fill it with elf_image.
00389                  */
00390                 speh->toe_shadow = malloc(toe_size);
00391                 if (speh->toe_shadow) {
00392                         ch = (char**) speh->toe_shadow;
00393                         if (sizeof(char*) == 8) {
00394                                 ch[0] = (char*) speh->elf_image;
00395                                 ch[1] = 0;
00396                         } else {
00397                                 ch[0] = 0;
00398                                 ch[1] = (char*) speh->elf_image;
00399                                 ch[2] = 0;
00400                                 ch[3] = 0;
00401                         }
00402                 } else {
00403                         errno = ENOMEM;
00404                         ret = 1;
00405                 }
00406         }
00407         return ret;
00408 }
00409