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
24FILE_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 */
52static int elf_load_segment ( struct image *image, const Elf_Phdr *phdr,
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 */
86static 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,
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 */
157int elf_segments ( struct image *image, const Elf_Ehdr *ehdr,
158 int ( * process ) ( struct image *image,
159 const Elf_Phdr *phdr,
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 */
206int 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}
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned long physaddr_t
Definition stdint.h:20
unsigned char uint8_t
Definition stdint.h:10
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" retur dest)
Definition string.h:151
#define max(x, y)
Definition ath.h:41
int elf_load(struct image *image, physaddr_t *entry, physaddr_t *max)
Load ELF image into memory.
Definition elf.c:206
static int elf_load_segment(struct image *image, const Elf_Phdr *phdr, physaddr_t dest)
Load ELF segment into memory.
Definition elf.c:52
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
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
ELF headers.
#define EI_MAG2
Definition elf.h:45
#define ELFMAG0
Definition elf.h:52
#define ELFMAG3
Definition elf.h:55
#define EI_MAG1
Definition elf.h:44
#define EI_CLASS
Definition elf.h:47
#define ELFMAG1
Definition elf.h:53
#define PT_LOAD
Definition elf.h:79
#define ELFMAG2
Definition elf.h:54
#define EI_MAG0
Definition elf.h:43
#define EI_MAG3
Definition elf.h:46
Error codes.
#define DBGC(...)
Definition compiler.h:505
uint32_t buffer
Buffer index (or NETVSC_RNDIS_NO_BUFFER)
Definition netvsc.h:5
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define ENOEXEC
Exec format error.
Definition errno.h:520
Executable images.
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
ELF image format.
Elf32_Off Elf_Off
Definition elf.h:19
Elf32_Ehdr Elf_Ehdr
Definition elf.h:17
Elf32_Phdr Elf_Phdr
Definition elf.h:18
#define ELFCLASS
Definition elf.h:20
Access to external ("user") memory.
uint32_t end
Ending offset.
Definition netvsc.h:7
int prep_segment(void *segment, size_t filesz, size_t memsz)
Prepare segment for loading.
Definition segment.c:61
Executable image segments.
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition string.c:115
Elf32_Off e_phoff
Definition elf.h:31
Elf32_Half e_phnum
Definition elf.h:36
Elf32_Addr e_entry
Definition elf.h:30
unsigned char e_ident[EI_NIDENT]
Definition elf.h:26
Elf32_Half e_phentsize
Definition elf.h:35
Elf32_Addr p_vaddr
Definition elf.h:70
Elf32_Word p_type
Definition elf.h:68
Elf32_Off p_offset
Definition elf.h:69
Elf32_Word p_filesz
Definition elf.h:72
Elf32_Word p_memsz
Definition elf.h:73
Elf32_Addr p_paddr
Definition elf.h:71
An executable image.
Definition image.h:24
const void * data
Read-only data.
Definition image.h:51
char * name
Name.
Definition image.h:38
size_t len
Length of raw file image.
Definition image.h:56
A process.
Definition process.h:18