iPXE
elf.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 /**
27  * @file
28  *
29  * ELF image format
30  *
31  * A "pure" ELF image is not a bootable image. There are various
32  * bootable formats based upon ELF (e.g. Multiboot), which share
33  * common ELF-related functionality.
34  */
35 
36 #include <string.h>
37 #include <errno.h>
38 #include <elf.h>
39 #include <ipxe/segment.h>
40 #include <ipxe/image.h>
41 #include <ipxe/uaccess.h>
42 #include <ipxe/elf.h>
43 
44 /**
45  * Load ELF segment into memory
46  *
47  * @v image ELF file
48  * @v phdr ELF program header
49  * @v dest Destination address
50  * @ret rc Return status code
51  */
52 static int elf_load_segment ( struct image *image, const Elf_Phdr *phdr,
53  physaddr_t dest ) {
54  void *buffer = phys_to_virt ( dest );
55  int rc;
56 
57  DBGC ( image, "ELF %s loading segment [%x,%x) to [%lx,%lx,%lx)\n",
58  image->name, phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ),
59  dest, ( dest + phdr->p_filesz ), ( dest + phdr->p_memsz ) );
60 
61  /* Verify and prepare segment */
62  if ( ( rc = prep_segment ( buffer, phdr->p_filesz,
63  phdr->p_memsz ) ) != 0 ) {
64  DBGC ( image, "ELF %s could not prepare segment: %s\n",
65  image->name, strerror ( rc ) );
66  return rc;
67  }
68 
69  /* Copy image to segment */
70  memcpy ( buffer, ( image->data + phdr->p_offset ), phdr->p_filesz );
71 
72  return 0;
73 }
74 
75 /**
76  * Process ELF segment
77  *
78  * @v image ELF file
79  * @v ehdr ELF executable header
80  * @v phdr ELF program header
81  * @v process Segment processor
82  * @ret entry Entry point, if found
83  * @ret max Maximum used address
84  * @ret rc Return status code
85  */
86 static int elf_segment ( struct image *image, const Elf_Ehdr *ehdr,
87  const Elf_Phdr *phdr,
88  int ( * process ) ( struct image *image,
89  const Elf_Phdr *phdr,
90  physaddr_t dest ),
91  physaddr_t *entry, physaddr_t *max ) {
94  unsigned long e_offset;
95  int rc;
96 
97  /* Do nothing for non-PT_LOAD segments */
98  if ( phdr->p_type != PT_LOAD )
99  return 0;
100 
101  /* Check segment lies within image */
102  if ( ( phdr->p_offset + phdr->p_filesz ) > image->len ) {
103  DBGC ( image, "ELF %s segment outside image\n", image->name );
104  return -ENOEXEC;
105  }
106 
107  /* Find start address: use physical address for preference,
108  * fall back to virtual address if no physical address
109  * supplied.
110  */
111  dest = phdr->p_paddr;
112  if ( ! dest )
113  dest = phdr->p_vaddr;
114  if ( ! dest ) {
115  DBGC ( image, "ELF %s segment loads to physical address 0\n",
116  image->name );
117  return -ENOEXEC;
118  }
119  end = ( dest + phdr->p_memsz );
120 
121  /* Update maximum used address, if applicable */
122  if ( end > *max )
123  *max = end;
124 
125  /* Process segment */
126  if ( ( rc = process ( image, phdr, dest ) ) != 0 )
127  return rc;
128 
129  /* Set execution address, if it lies within this segment */
130  if ( ( e_offset = ( ehdr->e_entry - dest ) ) < phdr->p_filesz ) {
131  *entry = ehdr->e_entry;
132  DBGC ( image, "ELF %s found physical entry point at %lx\n",
133  image->name, *entry );
134  } else if ( ( e_offset = ( ehdr->e_entry - phdr->p_vaddr ) )
135  < phdr->p_filesz ) {
136  if ( ! *entry ) {
137  *entry = ( dest + e_offset );
138  DBGC ( image, "ELF %s found virtual entry point at %lx"
139  " (virt %lx)\n", image->name, *entry,
140  ( ( unsigned long ) ehdr->e_entry ) );
141  }
142  }
143 
144  return 0;
145 }
146 
147 /**
148  * Process ELF segments
149  *
150  * @v image ELF file
151  * @v ehdr ELF executable header
152  * @v process Segment processor
153  * @ret entry Entry point, if found
154  * @ret max Maximum used address
155  * @ret rc Return status code
156  */
157 int elf_segments ( struct image *image, const Elf_Ehdr *ehdr,
158  int ( * process ) ( struct image *image,
159  const Elf_Phdr *phdr,
160  physaddr_t dest ),
161  physaddr_t *entry, physaddr_t *max ) {
162  const Elf_Phdr *phdr;
163  Elf_Off phoff;
164  unsigned int phnum;
165  int rc;
166 
167  /* Initialise maximum used address */
168  *max = 0;
169 
170  /* Invalidate entry point */
171  *entry = 0;
172 
173  /* Read and process ELF program headers */
174  for ( phoff = ehdr->e_phoff , phnum = ehdr->e_phnum ; phnum ;
175  phoff += ehdr->e_phentsize, phnum-- ) {
176  if ( ( image->len < phoff ) ||
177  ( ( image->len - phoff ) < sizeof ( *phdr ) ) ) {
178  DBGC ( image, "ELF %s program header %d outside "
179  "image\n", image->name, phnum );
180  return -ENOEXEC;
181  }
182  phdr = ( image->data + phoff );
183  if ( ( rc = elf_segment ( image, ehdr, phdr, process,
184  entry, max ) ) != 0 )
185  return rc;
186  }
187 
188  /* Check for a valid execution address */
189  if ( ! *entry ) {
190  DBGC ( image, "ELF %s entry point %lx outside image\n",
191  image->name, ( ( unsigned long ) ehdr->e_entry ) );
192  return -ENOEXEC;
193  }
194 
195  return 0;
196 }
197 
198 /**
199  * Load ELF image into memory
200  *
201  * @v image ELF file
202  * @ret entry Entry point
203  * @ret max Maximum used address
204  * @ret rc Return status code
205  */
206 int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max ) {
207  static const uint8_t e_ident[] = {
208  [EI_MAG0] = ELFMAG0,
209  [EI_MAG1] = ELFMAG1,
210  [EI_MAG2] = ELFMAG2,
211  [EI_MAG3] = ELFMAG3,
212  [EI_CLASS] = ELFCLASS,
213  };
214  const Elf_Ehdr *ehdr;
215  int rc;
216 
217  /* Read ELF header */
218  if ( image->len < sizeof ( *ehdr ) ) {
219  DBGC ( image, "ELF %s too short for ELF header\n",
220  image->name );
221  return -ENOEXEC;
222  }
223  ehdr = image->data;
224  if ( memcmp ( ehdr->e_ident, e_ident, sizeof ( e_ident ) ) != 0 ) {
225  DBGC ( image, "ELF %s has invalid signature\n", image->name );
226  return -ENOEXEC;
227  }
228 
229  /* Load ELF segments into memory */
230  if ( ( rc = elf_segments ( image, ehdr, elf_load_segment,
231  entry, max ) ) != 0 )
232  return rc;
233 
234  return 0;
235 }
A process.
Definition: process.h:17
Elf32_Addr p_paddr
Definition: elf.h:71
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
ELF header.
Definition: elf.h:25
#define max(x, y)
Definition: ath.h:40
#define PT_LOAD
Definition: elf.h:79
Error codes.
const void * data
Read-only data.
Definition: image.h:50
#define ELFMAG1
Definition: elf.h:53
#define ENOEXEC
Exec format error.
Definition: errno.h:519
#define DBGC(...)
Definition: compiler.h:505
Elf32_Half e_phentsize
Definition: elf.h:35
uint32_t buffer
Buffer index (or NETVSC_RNDIS_NO_BUFFER)
Definition: netvsc.h:16
An executable image.
Definition: image.h:23
static int elf_segment(struct image *image, const Elf_Ehdr *ehdr, const Elf_Phdr *phdr, int(*process)(struct image *image, const Elf_Phdr *phdr, physaddr_t dest), physaddr_t *entry, physaddr_t *max)
Process ELF segment.
Definition: elf.c:86
ELF image format.
int elf_segments(struct image *image, const Elf_Ehdr *ehdr, int(*process)(struct image *image, const Elf_Phdr *phdr, physaddr_t dest), physaddr_t *entry, physaddr_t *max)
Process ELF segments.
Definition: elf.c:157
Executable image segments.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
#define ELFMAG2
Definition: elf.h:54
Elf32_Word p_memsz
Definition: elf.h:73
Access to external ("user") memory.
int elf_load(struct image *image, physaddr_t *entry, physaddr_t *max)
Load ELF image into memory.
Definition: elf.c:206
Executable images.
Elf32_Addr p_vaddr
Definition: elf.h:70
Elf32_Word p_filesz
Definition: elf.h:72
Elf32_Off e_phoff
Definition: elf.h:31
unsigned char e_ident[EI_NIDENT]
Definition: elf.h:26
ELF headers.
#define EI_MAG2
Definition: elf.h:45
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
size_t len
Length of raw file image.
Definition: image.h:55
Elf32_Addr e_entry
Definition: elf.h:30
#define ELFCLASS
Definition: elf.h:20
unsigned char uint8_t
Definition: stdint.h:10
Elf32_Word p_type
Definition: elf.h:68
static int elf_load_segment(struct image *image, const Elf_Phdr *phdr, physaddr_t dest)
Load ELF segment into memory.
Definition: elf.c:52
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
#define EI_CLASS
Definition: elf.h:47
Elf32_Off p_offset
Definition: elf.h:69
unsigned long physaddr_t
Definition: stdint.h:20
#define ELFMAG3
Definition: elf.h:55
Elf32_Half e_phnum
Definition: elf.h:36
Elf32_Off Elf_Off
Definition: elf.h:19
if(len >=6 *4) __asm__ __volatile__("movsl" if(len >=5 *4) __asm__ __volatile__("movsl" if(len >=4 *4) __asm__ __volatile__("movsl" if(len >=3 *4) __asm__ __volatile__("movsl" if(len >=2 *4) __asm__ __volatile__("movsl" if(len >=1 *4) __asm__ __volatile__("movsl" if((len % 4) >=2) __asm__ __volatile__("movsw" if((len % 2) >=1) __asm__ __volatile__("movsb" return dest
Definition: string.h:150
uint32_t end
Ending offset.
Definition: netvsc.h:18
int prep_segment(void *segment, size_t filesz, size_t memsz)
Prepare segment for loading.
Definition: segment.c:61
#define EI_MAG3
Definition: elf.h:46
#define ELFMAG0
Definition: elf.h:52
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition: string.c:114
char * name
Name.
Definition: image.h:37
ELF program header.
Definition: elf.h:67
String functions.
#define EI_MAG1
Definition: elf.h:44
#define EI_MAG0
Definition: elf.h:43