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 ( ( image->len < phdr->p_offset ) ||
103 ( ( image->len - phdr->p_offset ) < phdr->p_filesz ) ) {
104 DBGC ( image, "ELF %s segment outside image\n", image->name );
105 return -ENOEXEC;
106 }
107
108 /* Find start address: use physical address for preference,
109 * fall back to virtual address if no physical address
110 * supplied.
111 */
112 dest = phdr->p_paddr;
113 if ( ! dest )
114 dest = phdr->p_vaddr;
115 if ( ! dest ) {
116 DBGC ( image, "ELF %s segment loads to physical address 0\n",
117 image->name );
118 return -ENOEXEC;
119 }
120 end = ( dest + phdr->p_memsz );
121
122 /* Update maximum used address, if applicable */
123 if ( end > *max )
124 *max = end;
125
126 /* Process segment */
127 if ( ( rc = process ( image, phdr, dest ) ) != 0 )
128 return rc;
129
130 /* Set execution address, if it lies within this segment */
131 if ( ( e_offset = ( ehdr->e_entry - dest ) ) < phdr->p_filesz ) {
132 *entry = ehdr->e_entry;
133 DBGC ( image, "ELF %s found physical entry point at %lx\n",
134 image->name, *entry );
135 } else if ( ( e_offset = ( ehdr->e_entry - phdr->p_vaddr ) )
136 < phdr->p_filesz ) {
137 if ( ! *entry ) {
138 *entry = ( dest + e_offset );
139 DBGC ( image, "ELF %s found virtual entry point at %lx"
140 " (virt %lx)\n", image->name, *entry,
141 ( ( unsigned long ) ehdr->e_entry ) );
142 }
143 }
144
145 return 0;
146}
147
148/**
149 * Process ELF segments
150 *
151 * @v image ELF file
152 * @v ehdr ELF executable header
153 * @v process Segment processor
154 * @ret entry Entry point, if found
155 * @ret max Maximum used address
156 * @ret rc Return status code
157 */
158int elf_segments ( struct image *image, const Elf_Ehdr *ehdr,
159 int ( * process ) ( struct image *image,
160 const Elf_Phdr *phdr,
162 physaddr_t *entry, physaddr_t *max ) {
163 const Elf_Phdr *phdr;
164 Elf_Off phoff;
165 unsigned int phnum;
166 int rc;
167
168 /* Initialise maximum used address */
169 *max = 0;
170
171 /* Invalidate entry point */
172 *entry = 0;
173
174 /* Read and process ELF program headers */
175 for ( phoff = ehdr->e_phoff , phnum = ehdr->e_phnum ; phnum ;
176 phoff += ehdr->e_phentsize, phnum-- ) {
177 if ( ( image->len < phoff ) ||
178 ( ( image->len - phoff ) < sizeof ( *phdr ) ) ) {
179 DBGC ( image, "ELF %s program header %d outside "
180 "image\n", image->name, phnum );
181 return -ENOEXEC;
182 }
183 phdr = ( image->data + phoff );
184 if ( ( rc = elf_segment ( image, ehdr, phdr, process,
185 entry, max ) ) != 0 )
186 return rc;
187 }
188
189 /* Check for a valid execution address */
190 if ( ! *entry ) {
191 DBGC ( image, "ELF %s entry point %lx outside image\n",
192 image->name, ( ( unsigned long ) ehdr->e_entry ) );
193 return -ENOEXEC;
194 }
195
196 return 0;
197}
198
199/**
200 * Load ELF image into memory
201 *
202 * @v image ELF file
203 * @ret entry Entry point
204 * @ret max Maximum used address
205 * @ret rc Return status code
206 */
207int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max ) {
208 static const uint8_t e_ident[] = {
209 [EI_MAG0] = ELFMAG0,
210 [EI_MAG1] = ELFMAG1,
211 [EI_MAG2] = ELFMAG2,
212 [EI_MAG3] = ELFMAG3,
213 [EI_CLASS] = ELFCLASS,
214 };
215 const Elf_Ehdr *ehdr;
216 int rc;
217
218 /* Read ELF header */
219 if ( image->len < sizeof ( *ehdr ) ) {
220 DBGC ( image, "ELF %s too short for ELF header\n",
221 image->name );
222 return -ENOEXEC;
223 }
224 ehdr = image->data;
225 if ( memcmp ( ehdr->e_ident, e_ident, sizeof ( e_ident ) ) != 0 ) {
226 DBGC ( image, "ELF %s has invalid signature\n", image->name );
227 return -ENOEXEC;
228 }
229
230 /* Load ELF segments into memory */
231 if ( ( rc = elf_segments ( image, ehdr, elf_load_segment,
232 entry, max ) ) != 0 )
233 return rc;
234
235 return 0;
236}
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:207
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:158
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:530
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:921
#define ENOEXEC
Exec format error.
Definition errno.h:563
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:63
A process.
Definition process.h:18