2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3 * Copyright (c) 1998 Peter Wemm <peter@freebsd.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * $FreeBSD: src/sys/boot/common/load_elf.c,v 1.13.2.1 2000/12/28 13:12:35 ps Exp $
30 #include <sys/param.h>
32 #include <sys/reboot.h>
33 #include <sys/linker.h>
35 #include <machine/bootinfo.h>
36 #include <machine/elf.h>
41 #include "bootstrap.h"
43 static int elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t loadaddr, Elf_Ehdr *ehdr, int kernel, caddr_t firstpage, int firstlen);
45 char *elf_kerneltype = "elf kernel";
46 char *elf_moduletype = "elf module";
49 * Attempt to load the file (file) as an ELF module. It will be stored at
50 * (dest), and a pointer to a module structure describing the loaded object
51 * will be saved in (result).
54 elf_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result)
56 struct loaded_module *mp, *kmp;
68 * Open the image, read and validate the ELF header
70 if (filename == NULL) /* can't handle nameless */
72 if ((fd = open(filename, O_RDONLY)) == -1)
74 firstpage = malloc(PAGE_SIZE);
75 if (firstpage == NULL)
77 firstlen = read(fd, firstpage, PAGE_SIZE);
78 if (firstlen <= sizeof(ehdr)) {
79 err = EFTYPE; /* could be EIO, but may be small file */
82 ehdr = (Elf_Ehdr *)firstpage;
89 if (ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */
90 ehdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
91 ehdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */
92 ehdr->e_version != EV_CURRENT ||
93 ehdr->e_machine != ELF_TARG_MACH) { /* Machine ? */
100 * Check to see what sort of module we are.
102 kmp = mod_findmodule(NULL, NULL);
103 if (ehdr->e_type == ET_DYN) {
104 /* Looks like a kld module */
106 printf("elf_loadmodule: can't load module before kernel\n");
110 if (strcmp(elf_kerneltype, kmp->m_type)) {
111 printf("elf_loadmodule: can't load module with kernel type '%s'\n", kmp->m_type);
115 /* Looks OK, got ahead */
118 /* Page-align the load address */
119 pad = (u_int)dest & PAGE_MASK;
121 pad = PAGE_SIZE - pad;
124 } else if (ehdr->e_type == ET_EXEC) {
125 /* Looks like a kernel */
127 printf("elf_loadmodule: kernel already loaded\n");
132 * Calculate destination address based on kernel entrypoint
134 dest = (vm_offset_t) ehdr->e_entry;
136 printf("elf_loadmodule: not a kernel (maybe static binary?)\n");
148 * Ok, we think we should handle this.
150 mp = mod_allocmodule();
152 printf("elf_loadmodule: cannot allocate module info\n");
157 setenv("kernelname", filename, 1);
158 s = strrchr(filename, '/');
160 mp->m_name = strdup(s + 1);
162 mp->m_name = strdup(filename);
163 mp->m_type = strdup(kernel ? elf_kerneltype : elf_moduletype);
167 printf("%s entry at %p\n", filename, (void *) dest);
169 printf("%s ", filename);
172 mp->m_size = elf_loadimage(mp, fd, dest, ehdr, kernel, firstpage, firstlen);
173 if (mp->m_size == 0 || mp->m_addr == 0)
176 /* save exec header as metadata */
177 mod_addmetadata(mp, MODINFOMD_ELFHDR, sizeof(*ehdr), ehdr);
179 /* Load OK, return module pointer */
180 *result = (struct loaded_module *)mp;
196 * With the file (fd) open on the image, and (ehdr) containing
197 * the Elf header, load the image at (off)
200 elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t off,
201 Elf_Ehdr *ehdr, int kernel, caddr_t firstpage, int firstlen)
207 vm_offset_t firstaddr;
208 vm_offset_t lastaddr;
213 vm_offset_t ssym, esym;
227 firstaddr = lastaddr = 0;
230 off = - (off & 0xff000000u); /* i386 relocates after locore */
232 off = 0; /* alpha is direct mapped for kernels */
236 if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr)) > firstlen) {
237 printf("elf_loadimage: program header not within first page\n");
240 phdr = (Elf_Phdr *)(firstpage + ehdr->e_phoff);
242 for (i = 0; i < ehdr->e_phnum; i++) {
243 /* We want to load PT_LOAD segments only.. */
244 if (phdr[i].p_type != PT_LOAD)
248 printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx",
249 (long)phdr[i].p_filesz, (long)phdr[i].p_offset,
250 (long)(phdr[i].p_vaddr + off),
251 (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
253 if ((phdr[i].p_flags & PF_W) == 0) {
254 printf("text=0x%lx ", (long)phdr[i].p_filesz);
256 printf("data=0x%lx", (long)phdr[i].p_filesz);
257 if (phdr[i].p_filesz < phdr[i].p_memsz)
258 printf("+0x%lx", (long)(phdr[i].p_memsz -phdr[i].p_filesz));
263 if (firstlen > phdr[i].p_offset) {
264 fpcopy = firstlen - phdr[i].p_offset;
265 archsw.arch_copyin(firstpage + phdr[i].p_offset,
266 phdr[i].p_vaddr + off, fpcopy);
268 if (phdr[i].p_filesz > fpcopy) {
269 if (lseek(fd, phdr[i].p_offset + fpcopy, SEEK_SET) == -1) {
270 printf("\nelf_loadexec: cannot seek\n");
273 if (archsw.arch_readin(fd, phdr[i].p_vaddr + off + fpcopy,
274 phdr[i].p_filesz - fpcopy) != phdr[i].p_filesz - fpcopy) {
275 printf("\nelf_loadexec: archsw.readin failed\n");
279 /* clear space from oversized segments; eg: bss */
280 if (phdr[i].p_filesz < phdr[i].p_memsz) {
282 printf(" (bss: 0x%lx-0x%lx)",
283 (long)(phdr[i].p_vaddr + off + phdr[i].p_filesz),
284 (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
287 /* no archsw.arch_bzero */
288 buf = malloc(PAGE_SIZE);
289 bzero(buf, PAGE_SIZE);
290 resid = phdr[i].p_memsz - phdr[i].p_filesz;
291 dest = phdr[i].p_vaddr + off + phdr[i].p_filesz;
293 chunk = min(PAGE_SIZE, resid);
294 archsw.arch_copyin(buf, dest, chunk);
304 if (firstaddr == 0 || firstaddr > (phdr[i].p_vaddr + off))
305 firstaddr = phdr[i].p_vaddr + off;
306 if (lastaddr == 0 || lastaddr < (phdr[i].p_vaddr + off + phdr[i].p_memsz))
307 lastaddr = phdr[i].p_vaddr + off + phdr[i].p_memsz;
309 lastaddr = roundup(lastaddr, sizeof(long));
312 * Now grab the symbol tables. This isn't easy if we're reading a
313 * .gz file. I think the rule is going to have to be that you must
314 * strip a file to remove symbols before gzipping it so that we do not
315 * try to lseek() on it.
317 chunk = ehdr->e_shnum * ehdr->e_shentsize;
318 if (chunk == 0 || ehdr->e_shoff == 0)
320 shdr = malloc(chunk);
323 if (lseek(fd, ehdr->e_shoff, SEEK_SET) == -1) {
324 printf("\nelf_loadimage: cannot lseek() to section headers");
327 if (read(fd, shdr, chunk) != chunk) {
328 printf("\nelf_loadimage: read section headers failed");
333 for (i = 0; i < ehdr->e_shnum; i++) {
334 if (shdr[i].sh_type != SHT_SYMTAB)
336 for (j = 0; j < ehdr->e_phnum; j++) {
337 if (phdr[j].p_type != PT_LOAD)
339 if (shdr[i].sh_offset >= phdr[j].p_offset &&
340 (shdr[i].sh_offset + shdr[i].sh_size <=
341 phdr[j].p_offset + phdr[j].p_filesz)) {
342 shdr[i].sh_offset = 0;
347 if (shdr[i].sh_offset == 0 || shdr[i].sh_size == 0)
348 continue; /* alread loaded in a PT_LOAD above */
349 /* Save it for loading below */
351 symstrindex = shdr[i].sh_link;
353 if (symtabindex < 0 || symstrindex < 0)
356 /* Ok, committed to a load. */
361 for (i = symtabindex; i >= 0; i = symstrindex) {
365 switch(shdr[i].sh_type) {
366 case SHT_SYMTAB: /* Symbol table */
369 case SHT_STRTAB: /* String table */
378 size = shdr[i].sh_size;
379 archsw.arch_copyin(&size, lastaddr, sizeof(size));
380 lastaddr += sizeof(long);
383 printf("\n%s: 0x%lx@0x%lx -> 0x%lx-0x%lx", secname,
384 shdr[i].sh_size, shdr[i].sh_offset,
385 lastaddr, lastaddr + shdr[i].sh_size);
387 if (i == symstrindex)
389 printf("0x%lx+0x%lx", (long)sizeof(size), size);
392 if (lseek(fd, shdr[i].sh_offset, SEEK_SET) == -1) {
393 printf("\nelf_loadimage: could not seek for symbols - skipped!");
398 if (archsw.arch_readin(fd, lastaddr, shdr[i].sh_size) !=
400 printf("\nelf_loadimage: could not read symbols - skipped!");
405 /* Reset offsets relative to ssym */
406 lastaddr += shdr[i].sh_size;
407 lastaddr = roundup(lastaddr, sizeof(long));
408 if (i == symtabindex)
410 else if (i == symstrindex)
418 mod_addmetadata(mp, MODINFOMD_SSYM, sizeof(ssym), &ssym);
419 mod_addmetadata(mp, MODINFOMD_ESYM, sizeof(esym), &esym);
424 ret = lastaddr - firstaddr;
425 mp->m_addr = firstaddr;
427 for (i = 0; i < ehdr->e_phnum; i++) {
428 if (phdr[i].p_type == PT_DYNAMIC) {
429 dp = (Elf_Dyn *)(phdr[i].p_vaddr);
430 mod_addmetadata(mp, MODINFOMD_DYNAMIC, sizeof(dp), &dp);
436 if (kernel) /* kernel must not depend on anything */
440 for (i = 0; i < ehdr->e_phnum; i++) {
441 if (phdr[i].p_type == PT_DYNAMIC) {
442 ndp = phdr[i].p_filesz / sizeof(Elf_Dyn);
443 dp = malloc(phdr[i].p_filesz);
444 archsw.arch_copyout(phdr[i].p_vaddr + off, dp, phdr[i].p_filesz);
447 if (dp == NULL || ndp == 0)
451 for (i = 0; i < ndp; i++) {
452 if (dp[i].d_tag == NULL)
454 switch (dp[i].d_tag) {
456 strtab = (char *)(dp[i].d_un.d_ptr + off);
459 strsz = dp[i].d_un.d_val;
465 if (strtab == NULL || strsz == 0)
468 for (i = 0; i < ndp; i++) {
469 if (dp[i].d_tag == NULL)
471 if (dp[i].d_tag != DT_NEEDED)
473 j = dp[i].d_un.d_ptr;
474 if (j < 1 || j > (strsz - 2))
475 continue; /* bad symbol name index */
476 s = strdupout((vm_offset_t)&strtab[j]);
477 mod_addmetadata(mp, MODINFOMD_DEPLIST, strlen(s) + 1, s);