1 /* elf.c - load ELF files */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
22 #include <grub/elfload.h>
23 #include <grub/file.h>
24 #include <grub/misc.h>
27 /* Check if EHDR is a valid ELF header. */
29 grub_elf_check_header (grub_elf_t elf
)
31 Elf32_Ehdr
*e
= &elf
->ehdr
.ehdr32
;
33 if (e
->e_ident
[EI_MAG0
] != ELFMAG0
34 || e
->e_ident
[EI_MAG1
] != ELFMAG1
35 || e
->e_ident
[EI_MAG2
] != ELFMAG2
36 || e
->e_ident
[EI_MAG3
] != ELFMAG3
37 || e
->e_ident
[EI_VERSION
] != EV_CURRENT
38 || e
->e_version
!= EV_CURRENT
)
39 return grub_error (GRUB_ERR_BAD_OS
, "invalid arch independent ELF magic");
45 grub_elf_close (grub_elf_t elf
)
47 grub_file_t file
= elf
->file
;
49 grub_free (elf
->phdrs
);
53 grub_file_close (file
);
59 grub_elf_file (grub_file_t file
)
63 elf
= grub_zalloc (sizeof (*elf
));
69 if (grub_file_seek (elf
->file
, 0) == (grub_off_t
) -1)
72 if (grub_file_read (elf
->file
, &elf
->ehdr
, sizeof (elf
->ehdr
))
73 != sizeof (elf
->ehdr
))
76 grub_error (GRUB_ERR_READ_ERROR
, "cannot read ELF header");
80 if (grub_elf_check_header (elf
))
86 grub_free (elf
->phdrs
);
92 grub_elf_open (const char *name
)
97 file
= grub_file_open (name
);
101 elf
= grub_elf_file (file
);
103 grub_file_close (file
);
112 grub_elf_is_elf32 (grub_elf_t elf
)
114 return elf
->ehdr
.ehdr32
.e_ident
[EI_CLASS
] == ELFCLASS32
;
118 grub_elf32_load_phdrs (grub_elf_t elf
)
120 grub_ssize_t phdrs_size
;
122 phdrs_size
= elf
->ehdr
.ehdr32
.e_phnum
* elf
->ehdr
.ehdr32
.e_phentsize
;
124 grub_dprintf ("elf", "Loading program headers at 0x%llx, size 0x%lx.\n",
125 (unsigned long long) elf
->ehdr
.ehdr32
.e_phoff
,
126 (unsigned long) phdrs_size
);
128 elf
->phdrs
= grub_malloc (phdrs_size
);
132 if ((grub_file_seek (elf
->file
, elf
->ehdr
.ehdr32
.e_phoff
) == (grub_off_t
) -1)
133 || (grub_file_read (elf
->file
, elf
->phdrs
, phdrs_size
) != phdrs_size
))
136 return grub_error (GRUB_ERR_READ_ERROR
, "cannot read program headers");
139 return GRUB_ERR_NONE
;
143 grub_elf32_phdr_iterate (grub_elf_t elf
,
144 int NESTED_FUNC_ATTR (*hook
) (grub_elf_t
, Elf32_Phdr
*, void *),
151 if (grub_elf32_load_phdrs (elf
))
155 for (i
= 0; i
< elf
->ehdr
.ehdr32
.e_phnum
; i
++)
157 Elf32_Phdr
*phdr
= phdrs
+ i
;
159 "Segment %u: type 0x%x paddr 0x%lx memsz 0x%lx "
162 (unsigned long) phdr
->p_paddr
,
163 (unsigned long) phdr
->p_memsz
,
164 (unsigned long) phdr
->p_filesz
);
165 if (hook (elf
, phdr
, hook_arg
))
172 /* Calculate the amount of memory spanned by the segments. */
174 grub_elf32_size (grub_elf_t elf
, Elf32_Addr
*base
, grub_uint32_t
*max_align
)
176 Elf32_Addr segments_start
= (Elf32_Addr
) -1;
177 Elf32_Addr segments_end
= 0;
179 grub_uint32_t curr_align
= 1;
181 /* Run through the program headers to calculate the total memory size we
183 auto int NESTED_FUNC_ATTR
calcsize (grub_elf_t _elf
, Elf32_Phdr
*phdr
, void *_arg
);
184 int NESTED_FUNC_ATTR
calcsize (grub_elf_t _elf
__attribute__ ((unused
)),
186 void *_arg
__attribute__ ((unused
)))
188 /* Only consider loadable segments. */
189 if (phdr
->p_type
!= PT_LOAD
)
192 if (phdr
->p_paddr
< segments_start
)
193 segments_start
= phdr
->p_paddr
;
194 if (phdr
->p_paddr
+ phdr
->p_memsz
> segments_end
)
195 segments_end
= phdr
->p_paddr
+ phdr
->p_memsz
;
196 if (curr_align
< phdr
->p_align
)
197 curr_align
= phdr
->p_align
;
201 grub_elf32_phdr_iterate (elf
, calcsize
, 0);
208 grub_error (GRUB_ERR_BAD_OS
, "no program headers present");
212 if (segments_end
< segments_start
)
214 /* Very bad addresses. */
215 grub_error (GRUB_ERR_BAD_OS
, "bad program header load addresses");
220 *base
= segments_start
;
222 *max_align
= curr_align
;
223 return segments_end
- segments_start
;
226 /* Load every loadable segment into memory specified by `_load_hook'. */
228 grub_elf32_load (grub_elf_t _elf
, grub_elf32_load_hook_t _load_hook
,
229 grub_addr_t
*base
, grub_size_t
*size
)
231 grub_addr_t load_base
= (grub_addr_t
) -1ULL;
232 grub_size_t load_size
= 0;
235 auto int NESTED_FUNC_ATTR
grub_elf32_load_segment (grub_elf_t elf
, Elf32_Phdr
*phdr
, void *hook
);
236 int NESTED_FUNC_ATTR
grub_elf32_load_segment (grub_elf_t elf
, Elf32_Phdr
*phdr
, void *hook
)
238 grub_elf32_load_hook_t load_hook
= (grub_elf32_load_hook_t
) hook
;
239 grub_addr_t load_addr
;
242 load_addr
= phdr
->p_paddr
;
243 if (load_hook
&& load_hook (phdr
, &load_addr
, &do_load
))
249 if (load_addr
< load_base
)
250 load_base
= load_addr
;
252 grub_dprintf ("elf", "Loading segment at 0x%llx, size 0x%llx\n",
253 (unsigned long long) load_addr
,
254 (unsigned long long) phdr
->p_memsz
);
256 if (grub_file_seek (elf
->file
, phdr
->p_offset
) == (grub_off_t
) -1)
259 return grub_error (GRUB_ERR_BAD_OS
,
260 "invalid offset in program header");
266 read
= grub_file_read (elf
->file
, (void *) load_addr
, phdr
->p_filesz
);
267 if (read
!= (grub_ssize_t
) phdr
->p_filesz
)
269 /* XXX How can we free memory from `load_hook'? */
271 return grub_error (GRUB_ERR_BAD_OS
,
272 "couldn't read segment from file: "
273 "wanted 0x%lx bytes; read 0x%lx bytes",
274 phdr
->p_filesz
, read
);
278 if (phdr
->p_filesz
< phdr
->p_memsz
)
279 grub_memset ((void *) (long) (load_addr
+ phdr
->p_filesz
),
280 0, phdr
->p_memsz
- phdr
->p_filesz
);
282 load_size
+= phdr
->p_memsz
;
287 err
= grub_elf32_phdr_iterate (_elf
, grub_elf32_load_segment
, _load_hook
);
301 grub_elf_is_elf64 (grub_elf_t elf
)
303 return elf
->ehdr
.ehdr64
.e_ident
[EI_CLASS
] == ELFCLASS64
;
307 grub_elf64_load_phdrs (grub_elf_t elf
)
309 grub_ssize_t phdrs_size
;
311 phdrs_size
= elf
->ehdr
.ehdr64
.e_phnum
* elf
->ehdr
.ehdr64
.e_phentsize
;
313 grub_dprintf ("elf", "Loading program headers at 0x%llx, size 0x%lx.\n",
314 (unsigned long long) elf
->ehdr
.ehdr64
.e_phoff
,
315 (unsigned long) phdrs_size
);
317 elf
->phdrs
= grub_malloc (phdrs_size
);
321 if ((grub_file_seek (elf
->file
, elf
->ehdr
.ehdr64
.e_phoff
) == (grub_off_t
) -1)
322 || (grub_file_read (elf
->file
, elf
->phdrs
, phdrs_size
) != phdrs_size
))
325 return grub_error (GRUB_ERR_READ_ERROR
, "cannot read program headers");
328 return GRUB_ERR_NONE
;
332 grub_elf64_phdr_iterate (grub_elf_t elf
,
333 int NESTED_FUNC_ATTR (*hook
) (grub_elf_t
, Elf64_Phdr
*, void *),
340 if (grub_elf64_load_phdrs (elf
))
344 for (i
= 0; i
< elf
->ehdr
.ehdr64
.e_phnum
; i
++)
346 Elf64_Phdr
*phdr
= phdrs
+ i
;
348 "Segment %u: type 0x%x paddr 0x%lx memsz 0x%lx "
351 (unsigned long) phdr
->p_paddr
,
352 (unsigned long) phdr
->p_memsz
,
353 (unsigned long) phdr
->p_filesz
);
354 if (hook (elf
, phdr
, hook_arg
))
361 /* Calculate the amount of memory spanned by the segments. */
363 grub_elf64_size (grub_elf_t elf
, Elf64_Addr
*base
, grub_uint64_t
*max_align
)
365 Elf64_Addr segments_start
= (Elf64_Addr
) -1;
366 Elf64_Addr segments_end
= 0;
368 grub_uint64_t curr_align
= 1;
370 /* Run through the program headers to calculate the total memory size we
372 auto int NESTED_FUNC_ATTR
calcsize (grub_elf_t _elf
, Elf64_Phdr
*phdr
, void *_arg
);
373 int NESTED_FUNC_ATTR
calcsize (grub_elf_t _elf
__attribute__ ((unused
)),
375 void *_arg
__attribute__ ((unused
)))
377 /* Only consider loadable segments. */
378 if (phdr
->p_type
!= PT_LOAD
)
381 if (phdr
->p_paddr
< segments_start
)
382 segments_start
= phdr
->p_paddr
;
383 if (phdr
->p_paddr
+ phdr
->p_memsz
> segments_end
)
384 segments_end
= phdr
->p_paddr
+ phdr
->p_memsz
;
385 if (curr_align
< phdr
->p_align
)
386 curr_align
= phdr
->p_align
;
390 grub_elf64_phdr_iterate (elf
, calcsize
, 0);
397 grub_error (GRUB_ERR_BAD_OS
, "no program headers present");
401 if (segments_end
< segments_start
)
403 /* Very bad addresses. */
404 grub_error (GRUB_ERR_BAD_OS
, "bad program header load addresses");
409 *base
= segments_start
;
411 *max_align
= curr_align
;
412 return segments_end
- segments_start
;
415 /* Load every loadable segment into memory specified by `_load_hook'. */
417 grub_elf64_load (grub_elf_t _elf
, grub_elf64_load_hook_t _load_hook
,
418 grub_addr_t
*base
, grub_size_t
*size
)
420 grub_addr_t load_base
= (grub_addr_t
) -1ULL;
421 grub_size_t load_size
= 0;
424 auto int NESTED_FUNC_ATTR
grub_elf64_load_segment (grub_elf_t elf
, Elf64_Phdr
*phdr
,
426 int NESTED_FUNC_ATTR
grub_elf64_load_segment (grub_elf_t elf
, Elf64_Phdr
*phdr
, void *hook
)
428 grub_elf64_load_hook_t load_hook
= (grub_elf64_load_hook_t
) hook
;
429 grub_addr_t load_addr
;
432 load_addr
= phdr
->p_paddr
;
433 if (load_hook
&& load_hook (phdr
, &load_addr
, &do_load
))
439 if (load_addr
< load_base
)
440 load_base
= load_addr
;
442 grub_dprintf ("elf", "Loading segment at 0x%llx, size 0x%llx\n",
443 (unsigned long long) load_addr
,
444 (unsigned long long) phdr
->p_memsz
);
446 if (grub_file_seek (elf
->file
, phdr
->p_offset
) == (grub_off_t
) -1)
449 return grub_error (GRUB_ERR_BAD_OS
,
450 "invalid offset in program header");
456 read
= grub_file_read (elf
->file
, (void *) load_addr
, phdr
->p_filesz
);
457 if (read
!= (grub_ssize_t
) phdr
->p_filesz
)
459 /* XXX How can we free memory from `load_hook'? */
461 return grub_error (GRUB_ERR_BAD_OS
,
462 "couldn't read segment from file: "
463 "wanted 0x%lx bytes; read 0x%lx bytes",
464 phdr
->p_filesz
, read
);
468 if (phdr
->p_filesz
< phdr
->p_memsz
)
469 grub_memset ((void *) (long) (load_addr
+ phdr
->p_filesz
),
470 0, phdr
->p_memsz
- phdr
->p_filesz
);
472 load_size
+= phdr
->p_memsz
;
477 err
= grub_elf64_phdr_iterate (_elf
, grub_elf64_load_segment
, _load_hook
);