libspe2  0.9a
elf_loader.c
Go to the documentation of this file.
1 /*
2  * libspe2 - A wrapper to allow direct execution of SPE binaries
3  * Copyright (C) 2005 IBM Corp.
4  *
5  * This library is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation; either version 2.1 of the License,
8  * or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
13  * License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this library; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */
19 
20 #include <elf.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <malloc.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <unistd.h>
28 
29 #include <sys/mman.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 
33 #include "elf_loader.h"
34 #include "spebase.h"
35 
36 #ifdef DEBUG
37 static void display_debug_output(Elf32_Ehdr *elf_start, Elf32_Shdr *sh);
38 #endif /*DEBUG*/
39 
40 #define __PRINTF(fmt, args...) { fprintf(stderr,fmt , ## args); }
41 #ifdef DEBUG
42 #define DEBUG_PRINTF(fmt, args...) __PRINTF(fmt , ## args)
43 #define TAG DEBUG_PRINTF("TAG: %d@%s\n", __LINE__, __FILE__);
44 #else
45 #define DEBUG_PRINTF(fmt, args...)
46 #define TAG
47 #endif
48 
49 static const unsigned char expected[EI_PAD] = {
50  [EI_MAG0] = ELFMAG0,
51  [EI_MAG1] = ELFMAG1,
52  [EI_MAG2] = ELFMAG2,
53  [EI_MAG3] = ELFMAG3,
54  [EI_CLASS] = ELFCLASS32,
55  [EI_DATA] = ELFDATA2MSB,
56  [EI_VERSION] = EV_CURRENT,
57  [EI_OSABI] = ELFOSABI_SYSV,
58  [EI_ABIVERSION] = 0
59 };
60 
61 static int
62 check_spe_elf(Elf32_Ehdr *ehdr)
63 {
64  /* Validate ELF */
65  if (memcmp (ehdr->e_ident, expected, EI_PAD) != 0)
66  {
67  DEBUG_PRINTF ("invalid ELF header.\n");
68  DEBUG_PRINTF ("expected 0x%016llX != 0x%016llX\n",
69  *(long long *) expected, *(long long *) (ehdr->e_ident));
70  errno = EINVAL;
71  return -errno;
72  }
73 
74  /* Validate the machine type */
75  if (ehdr->e_machine != 0x17)
76  {
77  DEBUG_PRINTF ("not an SPE ELF object");
78  errno = EINVAL;
79  return -errno;
80  }
81 
82  /* Validate ELF object type. */
83  if (ehdr->e_type != ET_EXEC)
84  {
85  DEBUG_PRINTF ("invalid SPE ELF type.\n");
86  DEBUG_PRINTF ("SPE type %d != %d\n", ehdr->e_type, ET_EXEC);
87  errno = EINVAL;
88  DEBUG_PRINTF ("parse_spu_elf(): errno=%d.\n", errno);
89  return -errno;
90  }
91 
92  return 0;
93 
94 }
98 int
100 {
101  Elf32_Ehdr *ehdr;
102  void *elf_start;
103 
104  elf_start = handle->elf_image;
105  ehdr = (Elf32_Ehdr *)(handle->elf_image);
106 
107  return check_spe_elf(ehdr);
108 }
109 
110 int
112  uint64_t *addr, uint32_t *size)
113 {
114  Elf32_Ehdr *ehdr = (Elf32_Ehdr *)handle->elf_image;
115  Elf32_Phdr *phdr;
116 
117  if (!ehdr) {
118  DEBUG_PRINTF("No ELF image has been loaded\n");
119  errno = EINVAL;
120  return -errno;
121  }
122 
123  if (ehdr->e_phentsize != sizeof(*phdr)) {
124  DEBUG_PRINTF("Invalid program header format (phdr size=%d)\n",
125  ehdr->e_phentsize);
126  errno = EINVAL;
127  return -errno;
128  }
129 
130  if (ehdr->e_phnum != 1) {
131  DEBUG_PRINTF("Invalid program header count (%d), expected 1\n",
132  ehdr->e_phnum);
133  errno = EINVAL;
134  return -errno;
135  }
136 
137  phdr = (Elf32_Phdr *)(handle->elf_image + ehdr->e_phoff);
138 
139  if (phdr->p_type != PT_LOAD || phdr->p_memsz == 0) {
140  DEBUG_PRINTF("SPE program segment is not loadable (type=%x)\n",
141  phdr->p_type);
142  errno = EINVAL;
143  return -errno;
144  }
145 
146  if (addr)
147  *addr = (uint64_t)(unsigned long)
148  (handle->elf_image + phdr->p_offset);
149 
150  if (size)
151  *size = phdr->p_memsz;
152 
153  return 0;
154 }
155 
156 static int
157 overlay(Elf32_Phdr *ph, Elf32_Phdr *prev_ph)
158 {
159  /*
160  * If our ph segment virtual address fits within that of the
161  * previous ph, this is an overlay.
162  */
163  if (prev_ph && (ph->p_vaddr >= prev_ph->p_vaddr) &&
164  (ph->p_vaddr < (prev_ph->p_vaddr + prev_ph->p_memsz)))
165  return 1;
166  else
167  return 0;
168 }
169 
170 static void
171 copy_to_ld_buffer(spe_program_handle_t *handle, void *buffer, Elf32_Phdr
172  *ph, Elf32_Off toe_addr, long toe_size)
173 {
174  void *start = handle->elf_image;
175 
176  DEBUG_PRINTF("SPE_LOAD %p (0x%x) -> %p (0x%x) (%i bytes)\n",
177  buffer + ph->p_vaddr, ph->p_vaddr, start + ph->p_offset,
178  ph->p_offset, ph->p_filesz);
179 
180  /* toe segment comes from the shadow */
181  if (ph->p_vaddr == toe_addr) {
182  /* still makes a copy if toe is buried with other
183  * sections */
184  if (toe_size != ph->p_filesz && ph->p_filesz) {
185  DEBUG_PRINTF("loading base copy\n");
186  memcpy(buffer + ph->p_vaddr, start + ph->p_offset,
187  ph->p_filesz);
188  }
189 
190  /* overlay only the total toe section size */
191  DEBUG_PRINTF("loading toe %X %X\n", ph->p_offset, toe_addr);
192  memcpy(buffer + ph->p_vaddr, handle->toe_shadow, toe_size);
193  } else if (ph->p_filesz) {
194  memcpy(buffer + ph->p_vaddr, start + ph->p_offset,
195  ph->p_filesz);
196  }
197  DEBUG_PRINTF("done ...\n");
198 }
199 
200 int
201 _base_spe_load_spe_elf (spe_program_handle_t *handle, void *ld_buffer, struct spe_ld_info *ld_info)
202 {
203  Elf32_Ehdr *ehdr;
204  Elf32_Phdr *phdr;
205  Elf32_Phdr *ph, *prev_ph;
206 
207  Elf32_Shdr *shdr;
208  Elf32_Shdr *sh;
209 
210  Elf32_Off toe_addr = 0;
211  long toe_size = 0;
212 
213  char* str_table = 0;
214 
215  int num_load_seg = 0;
216  void *elf_start;
217  int ret;
218 
219  DEBUG_PRINTF ("load_spe_elf(%p, %p)\n", handle, ld_buffer);
220 
221  elf_start = handle->elf_image;
222 
223  DEBUG_PRINTF ("load_spe_elf(%p, %p)\n", handle->elf_image, ld_buffer);
224  ehdr = (Elf32_Ehdr *)(handle->elf_image);
225 
226  /* Check for a Valid SPE ELF Image (again) */
227  if ((ret=check_spe_elf(ehdr)))
228  return ret;
229 
230  /* Start processing headers */
231  phdr = (Elf32_Phdr *) ((char *) ehdr + ehdr->e_phoff);
232  shdr = (Elf32_Shdr *) ((char *) ehdr + ehdr->e_shoff);
233  str_table = (char*)ehdr + shdr[ehdr->e_shstrndx].sh_offset;
234 
235  /* traverse the sections to locate the toe segment */
236  /* by specification, the toe sections are grouped together in a segment */
237  for (sh = shdr; sh < &shdr[ehdr->e_shnum]; ++sh)
238  {
239  DEBUG_PRINTF("section name: %s ( start: 0x%04x, size: 0x%04x)\n", str_table+sh->sh_name, sh->sh_offset, sh->sh_size );
240  if (strcmp(".toe", str_table+sh->sh_name) == 0) {
241  DEBUG_PRINTF("section offset: %d\n", sh->sh_offset);
242  toe_size += sh->sh_size;
243  if ((toe_addr == 0) || (toe_addr > sh->sh_addr))
244  toe_addr = sh->sh_addr;
245  }
246  /* Disabled : Actually not needed, only good for testing
247  if (strcmp(".bss", str_table+sh->sh_name) == 0) {
248  DEBUG_PRINTF("zeroing .bss section:\n");
249  DEBUG_PRINTF("section offset: 0x%04x\n", sh->sh_offset);
250  DEBUG_PRINTF("section size: 0x%04x\n", sh->sh_size);
251  memset(ld_buffer + sh->sh_offset, 0, sh->sh_size);
252  } */
253 
254 #ifdef DEBUG
255  if (strcmp(".note.spu_name", str_table+sh->sh_name) == 0)
256  display_debug_output(elf_start, sh);
257 #endif /*DEBUG*/
258  }
259 
260  /*
261  * Load all PT_LOAD segments onto the SPE local store buffer.
262  */
263  DEBUG_PRINTF("Segments: 0x%x\n", ehdr->e_phnum);
264  for (ph = phdr, prev_ph = NULL; ph < &phdr[ehdr->e_phnum]; ++ph) {
265  switch (ph->p_type) {
266  case PT_LOAD:
267  if (!overlay(ph, prev_ph)) {
268  if (ph->p_filesz < ph->p_memsz) {
269  DEBUG_PRINTF("padding loaded image with zeros:\n");
270  DEBUG_PRINTF("start: 0x%04x\n", ph->p_vaddr + ph->p_filesz);
271  DEBUG_PRINTF("length: 0x%04x\n", ph->p_memsz - ph->p_filesz);
272  memset(ld_buffer + ph->p_vaddr + ph->p_filesz, 0, ph->p_memsz - ph->p_filesz);
273  }
274  copy_to_ld_buffer(handle, ld_buffer, ph,
275  toe_addr, toe_size);
276  num_load_seg++;
277  }
278  break;
279  case PT_NOTE:
280  DEBUG_PRINTF("SPE_LOAD found PT_NOTE\n");
281  break;
282  }
283  }
284  if (num_load_seg == 0)
285  {
286  DEBUG_PRINTF ("no segments to load");
287  errno = EINVAL;
288  return -errno;
289  }
290 
291  /* Remember where the code wants to be started */
292  ld_info->entry = ehdr->e_entry;
293  DEBUG_PRINTF ("entry = 0x%x\n", ehdr->e_entry);
294 
295  return 0;
296 
297 }
298 
299 #ifdef DEBUG
300 static void
301 display_debug_output(Elf32_Ehdr *elf_start, Elf32_Shdr *sh)
302 {
303  typedef struct
304  {
305  unsigned long namesz;
306  unsigned long descsz;
307  unsigned long type;
308  char name[8];
309  char lookupname[32];
310  } ELF_NOTE;
311 
312  ELF_NOTE *note = (ELF_NOTE *)((void *)elf_start+sh->sh_offset);
313  printf ("Loading SPE program : %s\n", note->lookupname);
314  printf ("SPU LS Entry Addr : 0x%05x\n", elf_start->e_entry);
315 }
316 #endif /*DEBUG*/
317 
318 static int
319 toe_check_syms(Elf32_Ehdr *ehdr, Elf32_Shdr *sh)
320 {
321  Elf32_Sym *sym, *sym_hdr, *sym_end;
322  Elf32_Shdr *shdr;
323  char *str_table;
324  char *sym_name;
325  int ret;
326 
327  shdr = (Elf32_Shdr*) ((char*) ehdr + ehdr->e_shoff);
328  sym_hdr = (Elf32_Sym*) ((char*) ehdr + sh->sh_offset);
329  sym_end = (Elf32_Sym*) ((char*) ehdr + sh->sh_offset + sh->sh_size);
330  str_table = (char*)ehdr + shdr[sh->sh_link].sh_offset;
331 
332  ret = 0;
333  for (sym = sym_hdr; sym < sym_end; sym++)
334  if (sym->st_name) {
335  sym_name = str_table + sym->st_name;
336  if ((strncmp(sym_name, "_EAR_", 5) == 0) &&
337  (strcmp(sym_name, "_EAR_") != 0)) {
338  /*
339  * We have a prefix of _EAR_ followed by
340  * something else. This is not currently
341  * (and might not ever be) supported: for
342  * a _EAR_foo, it requires a lookup of foo
343  * in the ppu ELF file.
344  */
345  fprintf(stderr, "Invalid _EAR_ symbol '%s'\n",
346  sym_name);
347  errno = EINVAL;
348  ret = 1;
349  }
350  }
351  return ret;
352 }
353 
355 {
356  Elf32_Ehdr *ehdr;
357  Elf32_Shdr *shdr, *sh;
358  char *str_table;
359  char **ch;
360  int ret;
361  long toe_size;
362 
363  ehdr = (Elf32_Ehdr*) (speh->elf_image);
364  shdr = (Elf32_Shdr*) ((char*) ehdr + ehdr->e_shoff);
365  str_table = (char*)ehdr + shdr[ehdr->e_shstrndx].sh_offset;
366 
367  toe_size = 0;
368  for (sh = shdr; sh < &shdr[ehdr->e_shnum]; ++sh)
369  if (strcmp(".toe", str_table + sh->sh_name) == 0)
370  toe_size += sh->sh_size;
371 
372  ret = 0;
373  if (toe_size > 0) {
374  for (sh = shdr; sh < &shdr[ehdr->e_shnum]; ++sh)
375  if (sh->sh_type == SHT_SYMTAB || sh->sh_type ==
376  SHT_DYNSYM)
377  ret = toe_check_syms(ehdr, sh);
378  if (!ret && toe_size != 16) {
379  /* Paranoia */
380  fprintf(stderr, "Unexpected toe size of %ld\n",
381  toe_size);
382  errno = EINVAL;
383  ret = 1;
384  }
385  }
386  if (!ret && toe_size) {
387  /*
388  * Allocate toe_shadow, and fill it with elf_image.
389  */
390  speh->toe_shadow = malloc(toe_size);
391  if (speh->toe_shadow) {
392  ch = (char**) speh->toe_shadow;
393  if (sizeof(char*) == 8) {
394  ch[0] = (char*) speh->elf_image;
395  ch[1] = 0;
396  } else {
397  ch[0] = 0;
398  ch[1] = (char*) speh->elf_image;
399  ch[2] = 0;
400  ch[3] = 0;
401  }
402  } else {
403  errno = ENOMEM;
404  ret = 1;
405  }
406  }
407  return ret;
408 }
409