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 $
28 * $DragonFly: src/sys/boot/common/load_elf.c,v 1.2 2003/06/17 04:28:16 dillon Exp $
31 #include <sys/param.h>
33 #include <sys/reboot.h>
34 #include <sys/linker.h>
36 #include <machine/bootinfo.h>
37 #include <machine/elf.h>
42 #include "bootstrap.h"
44 static int elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t loadaddr, Elf_Ehdr *ehdr, int kernel, caddr_t firstpage, int firstlen);
46 char *elf_kerneltype = "elf kernel";
47 char *elf_moduletype = "elf module";
50 * Attempt to load the file (file) as an ELF module. It will be stored at
51 * (dest), and a pointer to a module structure describing the loaded object
52 * will be saved in (result).
55 elf_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result)
57 struct loaded_module *mp, *kmp;
69 * Open the image, read and validate the ELF header
71 if (filename == NULL) /* can't handle nameless */
73 if ((fd = open(filename, O_RDONLY)) == -1)
75 firstpage = malloc(PAGE_SIZE);
76 if (firstpage == NULL)
78 firstlen = read(fd, firstpage, PAGE_SIZE);
79 if (firstlen <= sizeof(ehdr)) {
80 err = EFTYPE; /* could be EIO, but may be small file */
83 ehdr = (Elf_Ehdr *)firstpage;
90 if (ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */
91 ehdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
92 ehdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */
93 ehdr->e_version != EV_CURRENT ||
94 ehdr->e_machine != ELF_TARG_MACH) { /* Machine ? */
101 * Check to see what sort of module we are.
103 kmp = mod_findmodule(NULL, NULL);
104 if (ehdr->e_type == ET_DYN) {
105 /* Looks like a kld module */
107 printf("elf_loadmodule: can't load module before kernel\n");
111 if (strcmp(elf_kerneltype, kmp->m_type)) {
112 printf("elf_loadmodule: can't load module with kernel type '%s'\n", kmp->m_type);
116 /* Looks OK, got ahead */
119 /* Page-align the load address */
120 pad = (u_int)dest & PAGE_MASK;
122 pad = PAGE_SIZE - pad;
125 } else if (ehdr->e_type == ET_EXEC) {
126 /* Looks like a kernel */
128 printf("elf_loadmodule: kernel already loaded\n");
133 * Calculate destination address based on kernel entrypoint
135 dest = (vm_offset_t) ehdr->e_entry;
137 printf("elf_loadmodule: not a kernel (maybe static binary?)\n");
149 * Ok, we think we should handle this.
151 mp = mod_allocmodule();
153 printf("elf_loadmodule: cannot allocate module info\n");
158 setenv("kernelname", filename, 1);
159 s = strrchr(filename, '/');
161 mp->m_name = strdup(s + 1);
163 mp->m_name = strdup(filename);
164 mp->m_type = strdup(kernel ? elf_kerneltype : elf_moduletype);
168 printf("%s entry at %p\n", filename, (void *) dest);
170 printf("%s ", filename);
173 mp->m_size = elf_loadimage(mp, fd, dest, ehdr, kernel, firstpage, firstlen);
174 if (mp->m_size == 0 || mp->m_addr == 0)
177 /* save exec header as metadata */
178 mod_addmetadata(mp, MODINFOMD_ELFHDR, sizeof(*ehdr), ehdr);
180 /* Load OK, return module pointer */
181 *result = (struct loaded_module *)mp;
197 * With the file (fd) open on the image, and (ehdr) containing
198 * the Elf header, load the image at (off)
201 elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t off,
202 Elf_Ehdr *ehdr, int kernel, caddr_t firstpage, int firstlen)
208 vm_offset_t firstaddr;
209 vm_offset_t lastaddr;
214 vm_offset_t ssym, esym;
228 firstaddr = lastaddr = 0;
231 off = - (off & 0xff000000u); /* i386 relocates after locore */
233 off = 0; /* alpha is direct mapped for kernels */
237 if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr)) > firstlen) {
238 printf("elf_loadimage: program header not within first page\n");
241 phdr = (Elf_Phdr *)(firstpage + ehdr->e_phoff);
243 for (i = 0; i < ehdr->e_phnum; i++) {
244 /* We want to load PT_LOAD segments only.. */
245 if (phdr[i].p_type != PT_LOAD)
249 printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx",
250 (long)phdr[i].p_filesz, (long)phdr[i].p_offset,
251 (long)(phdr[i].p_vaddr + off),
252 (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
254 if ((phdr[i].p_flags & PF_W) == 0) {
255 printf("text=0x%lx ", (long)phdr[i].p_filesz);
257 printf("data=0x%lx", (long)phdr[i].p_filesz);
258 if (phdr[i].p_filesz < phdr[i].p_memsz)
259 printf("+0x%lx", (long)(phdr[i].p_memsz -phdr[i].p_filesz));
264 if (firstlen > phdr[i].p_offset) {
265 fpcopy = firstlen - phdr[i].p_offset;
266 archsw.arch_copyin(firstpage + phdr[i].p_offset,
267 phdr[i].p_vaddr + off, fpcopy);
269 if (phdr[i].p_filesz > fpcopy) {
270 if (lseek(fd, phdr[i].p_offset + fpcopy, SEEK_SET) == -1) {
271 printf("\nelf_loadexec: cannot seek\n");
274 if (archsw.arch_readin(fd, phdr[i].p_vaddr + off + fpcopy,
275 phdr[i].p_filesz - fpcopy) != phdr[i].p_filesz - fpcopy) {
276 printf("\nelf_loadexec: archsw.readin failed\n");
280 /* clear space from oversized segments; eg: bss */
281 if (phdr[i].p_filesz < phdr[i].p_memsz) {
283 printf(" (bss: 0x%lx-0x%lx)",
284 (long)(phdr[i].p_vaddr + off + phdr[i].p_filesz),
285 (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
288 /* no archsw.arch_bzero */
289 buf = malloc(PAGE_SIZE);
290 bzero(buf, PAGE_SIZE);
291 resid = phdr[i].p_memsz - phdr[i].p_filesz;
292 dest = phdr[i].p_vaddr + off + phdr[i].p_filesz;
294 chunk = min(PAGE_SIZE, resid);
295 archsw.arch_copyin(buf, dest, chunk);
305 if (firstaddr == 0 || firstaddr > (phdr[i].p_vaddr + off))
306 firstaddr = phdr[i].p_vaddr + off;
307 if (lastaddr == 0 || lastaddr < (phdr[i].p_vaddr + off + phdr[i].p_memsz))
308 lastaddr = phdr[i].p_vaddr + off + phdr[i].p_memsz;
310 lastaddr = roundup(lastaddr, sizeof(long));
313 * Now grab the symbol tables. This isn't easy if we're reading a
314 * .gz file. I think the rule is going to have to be that you must
315 * strip a file to remove symbols before gzipping it so that we do not
316 * try to lseek() on it.
318 chunk = ehdr->e_shnum * ehdr->e_shentsize;
319 if (chunk == 0 || ehdr->e_shoff == 0)
321 shdr = malloc(chunk);
324 if (lseek(fd, ehdr->e_shoff, SEEK_SET) == -1) {
325 printf("\nelf_loadimage: cannot lseek() to section headers");
328 if (read(fd, shdr, chunk) != chunk) {
329 printf("\nelf_loadimage: read section headers failed");
334 for (i = 0; i < ehdr->e_shnum; i++) {
335 if (shdr[i].sh_type != SHT_SYMTAB)
337 for (j = 0; j < ehdr->e_phnum; j++) {
338 if (phdr[j].p_type != PT_LOAD)
340 if (shdr[i].sh_offset >= phdr[j].p_offset &&
341 (shdr[i].sh_offset + shdr[i].sh_size <=
342 phdr[j].p_offset + phdr[j].p_filesz)) {
343 shdr[i].sh_offset = 0;
348 if (shdr[i].sh_offset == 0 || shdr[i].sh_size == 0)
349 continue; /* alread loaded in a PT_LOAD above */
350 /* Save it for loading below */
352 symstrindex = shdr[i].sh_link;
354 if (symtabindex < 0 || symstrindex < 0)
357 /* Ok, committed to a load. */
362 for (i = symtabindex; i >= 0; i = symstrindex) {
366 switch(shdr[i].sh_type) {
367 case SHT_SYMTAB: /* Symbol table */
370 case SHT_STRTAB: /* String table */
379 size = shdr[i].sh_size;
380 archsw.arch_copyin(&size, lastaddr, sizeof(size));
381 lastaddr += sizeof(long);
384 printf("\n%s: 0x%lx@0x%lx -> 0x%lx-0x%lx", secname,
385 shdr[i].sh_size, shdr[i].sh_offset,
386 lastaddr, lastaddr + shdr[i].sh_size);
388 if (i == symstrindex)
390 printf("0x%lx+0x%lx", (long)sizeof(size), size);
393 if (lseek(fd, shdr[i].sh_offset, SEEK_SET) == -1) {
394 printf("\nelf_loadimage: could not seek for symbols - skipped!");
399 if (archsw.arch_readin(fd, lastaddr, shdr[i].sh_size) !=
401 printf("\nelf_loadimage: could not read symbols - skipped!");
406 /* Reset offsets relative to ssym */
407 lastaddr += shdr[i].sh_size;
408 lastaddr = roundup(lastaddr, sizeof(long));
409 if (i == symtabindex)
411 else if (i == symstrindex)
419 mod_addmetadata(mp, MODINFOMD_SSYM, sizeof(ssym), &ssym);
420 mod_addmetadata(mp, MODINFOMD_ESYM, sizeof(esym), &esym);
425 ret = lastaddr - firstaddr;
426 mp->m_addr = firstaddr;
428 for (i = 0; i < ehdr->e_phnum; i++) {
429 if (phdr[i].p_type == PT_DYNAMIC) {
430 dp = (Elf_Dyn *)(phdr[i].p_vaddr);
431 mod_addmetadata(mp, MODINFOMD_DYNAMIC, sizeof(dp), &dp);
437 if (kernel) /* kernel must not depend on anything */
441 for (i = 0; i < ehdr->e_phnum; i++) {
442 if (phdr[i].p_type == PT_DYNAMIC) {
443 ndp = phdr[i].p_filesz / sizeof(Elf_Dyn);
444 dp = malloc(phdr[i].p_filesz);
445 archsw.arch_copyout(phdr[i].p_vaddr + off, dp, phdr[i].p_filesz);
448 if (dp == NULL || ndp == 0)
452 for (i = 0; i < ndp; i++) {
453 if (dp[i].d_tag == NULL)
455 switch (dp[i].d_tag) {
457 strtab = (char *)(dp[i].d_un.d_ptr + off);
460 strsz = dp[i].d_un.d_val;
466 if (strtab == NULL || strsz == 0)
469 for (i = 0; i < ndp; i++) {
470 if (dp[i].d_tag == NULL)
472 if (dp[i].d_tag != DT_NEEDED)
474 j = dp[i].d_un.d_ptr;
475 if (j < 1 || j > (strsz - 2))
476 continue; /* bad symbol name index */
477 s = strdupout((vm_offset_t)&strtab[j]);
478 mod_addmetadata(mp, MODINFOMD_DEPLIST, strlen(s) + 1, s);