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.39 2008/10/14 10:11:14 raj Exp $
30 #include <sys/param.h>
32 #include <sys/linker.h>
33 #include <sys/module.h>
34 #include <sys/stdint.h>
36 #include <machine/elf.h>
41 #include "bootstrap.h"
43 #define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l)
45 #if defined(__i386__) && __ELF_WORD_SIZE == 64
48 #define ELF_TARG_CLASS ELFCLASS64
49 #define ELF_TARG_MACH EM_X86_64
52 typedef struct elf_file
{
74 static int __elfN(loadimage
)(struct preloaded_file
*mp
, elf_file_t ef
, u_int64_t loadaddr
);
75 static int __elfN(lookup_symbol
)(struct preloaded_file
*mp
, elf_file_t ef
, const char* name
, Elf_Sym
* sym
);
76 static int __elfN(reloc_ptr
)(struct preloaded_file
*mp
, elf_file_t ef
,
77 Elf_Addr p
, void *val
, size_t len
);
78 static int __elfN(parse_modmetadata
)(struct preloaded_file
*mp
, elf_file_t ef
);
79 static symaddr_fn
__elfN(symaddr
);
80 static char *fake_modname(const char *name
);
82 const char *__elfN(kerneltype
) = "elf kernel";
83 const char *__elfN(moduletype
) = "elf module";
85 u_int64_t
__elfN(relocation_offset
) = 0;
88 * Attempt to load the file (file) as an ELF module. It will be stored at
89 * (dest), and a pointer to a module structure describing the loaded object
90 * will be saved in (result).
93 __elfN(loadfile
)(char *filename
, u_int64_t dest
, struct preloaded_file
**result
)
95 struct preloaded_file
*fp
, *kfp
;
104 bzero(&ef
, sizeof(struct elf_file
));
107 * Open the image, read and validate the ELF header
109 if (filename
== NULL
) /* can't handle nameless */
111 if ((ef
.fd
= rel_open(filename
, &fullpath
, O_RDONLY
)) == -1)
113 ef
.firstpage
= malloc(PAGE_SIZE
);
114 if (ef
.firstpage
== NULL
) {
119 bytes_read
= read(ef
.fd
, ef
.firstpage
, PAGE_SIZE
);
120 ef
.firstlen
= (size_t)bytes_read
;
121 if (bytes_read
< 0 || ef
.firstlen
<= sizeof(Elf_Ehdr
)) {
122 err
= EFTYPE
; /* could be EIO, but may be small file */
125 ehdr
= ef
.ehdr
= (Elf_Ehdr
*)ef
.firstpage
;
128 if (!IS_ELF(*ehdr
)) {
132 if (ehdr
->e_ident
[EI_CLASS
] != ELF_TARG_CLASS
|| /* Layout ? */
133 ehdr
->e_ident
[EI_DATA
] != ELF_TARG_DATA
||
134 ehdr
->e_ident
[EI_VERSION
] != EV_CURRENT
|| /* Version ? */
135 ehdr
->e_version
!= EV_CURRENT
||
136 ehdr
->e_machine
!= ELF_TARG_MACH
) { /* Machine ? */
143 * Check to see what sort of module we are.
145 kfp
= file_findfile(NULL
, NULL
);
146 if (ehdr
->e_type
== ET_DYN
) {
147 /* Looks like a kld module */
149 printf("elf" __XSTRING(__ELF_WORD_SIZE
) "_loadfile: can't load module before kernel\n");
153 if (strcmp(__elfN(kerneltype
), kfp
->f_type
)) {
154 printf("elf" __XSTRING(__ELF_WORD_SIZE
) "_loadfile: can't load module with kernel type '%s'\n", kfp
->f_type
);
158 /* Looks OK, got ahead */
161 /* Page-align the load address */
162 pad
= (u_int
)dest
& PAGE_MASK
;
164 pad
= PAGE_SIZE
- pad
;
167 } else if (ehdr
->e_type
== ET_EXEC
) {
168 /* Looks like a kernel */
170 printf("elf" __XSTRING(__ELF_WORD_SIZE
) "_loadfile: kernel already loaded\n");
175 * Calculate destination address based on kernel entrypoint
177 dest
= ehdr
->e_entry
;
179 printf("elf" __XSTRING(__ELF_WORD_SIZE
) "_loadfile: not a kernel (maybe static binary?)\n");
191 * Ok, we think we should handle this.
195 printf("elf" __XSTRING(__ELF_WORD_SIZE
) "_loadfile: cannot allocate module info\n");
201 * Set the kernel name and module path correctly for the kernel's
202 * consumption. Always prepend a /boot if we don't have one.
208 const char *prefix
= "";
210 mptr
= malloc(strlen(fullpath
) * 2 + 10 + 16);
211 if (strncmp(fullpath
, "/boot/", 6) != 0)
213 sprintf(mptr
, "%s%s", prefix
, fullpath
);
214 setenv("kernelname", mptr
, 1);
216 fpend
= strrchr(mptr
, '/');
218 if (strcmp(mptr
, "/boot") == 0)
219 sprintf(mptr
, "/boot/modules");
221 /* Append modules.local for kernel if requested */
222 modlocal
= getenv("local_modules");
223 if (modlocal
!= NULL
&& strcmp(modlocal
, "YES") == 0)
224 strncat(mptr
, ";/boot/modules.local", strlen(fullpath
) * 2 + 26);
226 /* this will be moved to "module_path" on boot */
227 setenv("exported_module_path", mptr
, 1);
230 fp
->f_name
= strdup(filename
);
231 fp
->f_type
= strdup(ef
.kernel
? __elfN(kerneltype
) : __elfN(moduletype
));
235 printf("%s entry at 0x%jx\n", filename
, (uintmax_t)dest
);
237 printf("%s ", filename
);
240 fp
->f_size
= __elfN(loadimage
)(fp
, &ef
, dest
);
241 if (fp
->f_size
== 0 || fp
->f_addr
== 0)
244 /* save exec header as metadata */
245 file_addmetadata(fp
, MODINFOMD_ELFHDR
, sizeof(*ehdr
), ehdr
);
247 /* Load OK, return module pointer */
248 *result
= (struct preloaded_file
*)fp
;
266 * With the file (fd) open on the image, and (ehdr) containing
267 * the Elf header, load the image at (off)
270 __elfN(loadimage
)(struct preloaded_file
*fp
, elf_file_t ef
, u_int64_t off
)
275 Elf_Phdr
*phdr
, *php
;
278 vm_offset_t firstaddr
;
279 vm_offset_t lastaddr
;
294 firstaddr
= lastaddr
= 0;
297 #if defined(__x86_64__) || defined(__i386__)
298 #if __ELF_WORD_SIZE == 64
299 off
= - (off
& 0xffffffffff000000ull
);/* x86_64 relocates after locore */
301 off
= - (off
& 0xff000000u
); /* i386 relocates after locore */
304 off
= 0; /* other archs use direct mapped kernels */
306 __elfN(relocation_offset
) = off
;
310 if ((ehdr
->e_phoff
+ ehdr
->e_phnum
* sizeof(*phdr
)) > ef
->firstlen
) {
311 printf("elf" __XSTRING(__ELF_WORD_SIZE
) "_loadimage: program header not within first page\n");
314 phdr
= (Elf_Phdr
*)(ef
->firstpage
+ ehdr
->e_phoff
);
316 for (i
= 0; i
< ehdr
->e_phnum
; i
++) {
317 /* We want to load PT_LOAD segments only.. */
318 if (phdr
[i
].p_type
!= PT_LOAD
)
322 printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx",
323 (long)phdr
[i
].p_filesz
, (long)phdr
[i
].p_offset
,
324 (long)(phdr
[i
].p_vaddr
+ off
),
325 (long)(phdr
[i
].p_vaddr
+ off
+ phdr
[i
].p_memsz
- 1));
327 if ((phdr
[i
].p_flags
& PF_W
) == 0) {
328 printf("text=0x%lx ", (long)phdr
[i
].p_filesz
);
330 printf("data=0x%lx", (long)phdr
[i
].p_filesz
);
331 if (phdr
[i
].p_filesz
< phdr
[i
].p_memsz
)
332 printf("+0x%lx", (long)(phdr
[i
].p_memsz
-phdr
[i
].p_filesz
));
337 if (ef
->firstlen
> phdr
[i
].p_offset
) {
338 fpcopy
= ef
->firstlen
- phdr
[i
].p_offset
;
339 archsw
.arch_copyin(ef
->firstpage
+ phdr
[i
].p_offset
,
340 phdr
[i
].p_vaddr
+ off
, fpcopy
);
342 if (phdr
[i
].p_filesz
> fpcopy
) {
343 if (kern_pread(ef
->fd
, phdr
[i
].p_vaddr
+ off
+ fpcopy
,
344 phdr
[i
].p_filesz
- fpcopy
, phdr
[i
].p_offset
+ fpcopy
) != 0) {
345 printf("\nelf" __XSTRING(__ELF_WORD_SIZE
)
346 "_loadimage: read failed\n");
350 /* clear space from oversized segments; eg: bss */
351 if (phdr
[i
].p_filesz
< phdr
[i
].p_memsz
) {
353 printf(" (bss: 0x%lx-0x%lx)",
354 (long)(phdr
[i
].p_vaddr
+ off
+ phdr
[i
].p_filesz
),
355 (long)(phdr
[i
].p_vaddr
+ off
+ phdr
[i
].p_memsz
- 1));
358 kern_bzero(phdr
[i
].p_vaddr
+ off
+ phdr
[i
].p_filesz
,
359 phdr
[i
].p_memsz
- phdr
[i
].p_filesz
);
365 if (firstaddr
== 0 || firstaddr
> (phdr
[i
].p_vaddr
+ off
))
366 firstaddr
= phdr
[i
].p_vaddr
+ off
;
367 if (lastaddr
== 0 || lastaddr
< (phdr
[i
].p_vaddr
+ off
+ phdr
[i
].p_memsz
))
368 lastaddr
= phdr
[i
].p_vaddr
+ off
+ phdr
[i
].p_memsz
;
370 lastaddr
= roundup(lastaddr
, sizeof(long));
373 * Now grab the symbol tables. This isn't easy if we're reading a
374 * .gz file. I think the rule is going to have to be that you must
375 * strip a file to remove symbols before gzipping it so that we do not
376 * try to lseek() on it.
378 chunk
= ehdr
->e_shnum
* ehdr
->e_shentsize
;
379 if (chunk
== 0 || ehdr
->e_shoff
== 0)
381 shdr
= alloc_pread(ef
->fd
, ehdr
->e_shoff
, chunk
);
383 printf("\nelf" __XSTRING(__ELF_WORD_SIZE
)
384 "_loadimage: failed to read section headers");
389 for (i
= 0; i
< ehdr
->e_shnum
; i
++) {
390 if (shdr
[i
].sh_type
!= SHT_SYMTAB
)
392 for (j
= 0; j
< ehdr
->e_phnum
; j
++) {
393 if (phdr
[j
].p_type
!= PT_LOAD
)
395 if (shdr
[i
].sh_offset
>= phdr
[j
].p_offset
&&
396 (shdr
[i
].sh_offset
+ shdr
[i
].sh_size
<=
397 phdr
[j
].p_offset
+ phdr
[j
].p_filesz
)) {
398 shdr
[i
].sh_offset
= 0;
403 if (shdr
[i
].sh_offset
== 0 || shdr
[i
].sh_size
== 0)
404 continue; /* alread loaded in a PT_LOAD above */
405 /* Save it for loading below */
407 symstrindex
= shdr
[i
].sh_link
;
409 if (symtabindex
< 0 || symstrindex
< 0)
412 /* Ok, committed to a load. */
417 for (i
= symtabindex
; i
>= 0; i
= symstrindex
) {
421 switch(shdr
[i
].sh_type
) {
422 case SHT_SYMTAB
: /* Symbol table */
425 case SHT_STRTAB
: /* String table */
434 size
= shdr
[i
].sh_size
;
435 archsw
.arch_copyin(&size
, lastaddr
, sizeof(size
));
436 lastaddr
+= sizeof(size
);
439 printf("\n%s: 0x%jx@0x%jx -> 0x%jx-0x%jx", secname
,
440 (uintmax_t)shdr
[i
].sh_size
, (uintmax_t)shdr
[i
].sh_offset
,
441 (uintmax_t)lastaddr
, (uintmax_t)(lastaddr
+ shdr
[i
].sh_size
));
443 if (i
== symstrindex
)
445 printf("0x%lx+0x%lx", (long)sizeof(size
), (long)size
);
448 if (lseek(ef
->fd
, (off_t
)shdr
[i
].sh_offset
, SEEK_SET
) == -1) {
449 printf("\nelf" __XSTRING(__ELF_WORD_SIZE
) "_loadimage: could not seek for symbols - skipped!");
454 result
= archsw
.arch_readin(ef
->fd
, lastaddr
, shdr
[i
].sh_size
);
455 if (result
< 0 || (size_t)result
!= shdr
[i
].sh_size
) {
456 printf("\nelf" __XSTRING(__ELF_WORD_SIZE
) "_loadimage: could not read symbols - skipped!");
461 /* Reset offsets relative to ssym */
462 lastaddr
+= shdr
[i
].sh_size
;
463 lastaddr
= roundup(lastaddr
, sizeof(size
));
464 if (i
== symtabindex
)
466 else if (i
== symstrindex
)
474 file_addmetadata(fp
, MODINFOMD_SSYM
, sizeof(ssym
), &ssym
);
475 file_addmetadata(fp
, MODINFOMD_ESYM
, sizeof(esym
), &esym
);
480 ret
= lastaddr
- firstaddr
;
481 fp
->f_addr
= firstaddr
;
484 for (i
= 0; i
< ehdr
->e_phnum
; i
++) {
485 if (phdr
[i
].p_type
== PT_DYNAMIC
) {
488 file_addmetadata(fp
, MODINFOMD_DYNAMIC
, sizeof(adp
), &adp
);
493 if (php
== NULL
) /* this is bad, we cannot get to symbols or _DYNAMIC */
496 ndp
= php
->p_filesz
/ sizeof(Elf_Dyn
);
499 dp
= malloc(php
->p_filesz
);
502 archsw
.arch_copyout(php
->p_vaddr
+ off
, dp
, php
->p_filesz
);
505 for (i
= 0; i
< ndp
; i
++) {
506 if (dp
[i
].d_tag
== 0)
508 switch (dp
[i
].d_tag
) {
510 ef
->hashtab
= (Elf_Hashelt
*)(uintptr_t)(dp
[i
].d_un
.d_ptr
+ off
);
513 ef
->strtab
= (char *)(uintptr_t)(dp
[i
].d_un
.d_ptr
+ off
);
516 ef
->strsz
= dp
[i
].d_un
.d_val
;
519 ef
->symtab
= (Elf_Sym
*)(uintptr_t)(dp
[i
].d_un
.d_ptr
+ off
);
522 ef
->rel
= (Elf_Rel
*)(uintptr_t)(dp
[i
].d_un
.d_ptr
+ off
);
525 ef
->relsz
= dp
[i
].d_un
.d_val
;
528 ef
->rela
= (Elf_Rela
*)(uintptr_t)(dp
[i
].d_un
.d_ptr
+ off
);
531 ef
->relasz
= dp
[i
].d_un
.d_val
;
537 if (ef
->hashtab
== NULL
|| ef
->symtab
== NULL
||
538 ef
->strtab
== NULL
|| ef
->strsz
== 0)
540 COPYOUT(ef
->hashtab
, &ef
->nbuckets
, sizeof(ef
->nbuckets
));
541 COPYOUT(ef
->hashtab
+ 1, &ef
->nchains
, sizeof(ef
->nchains
));
542 ef
->buckets
= ef
->hashtab
+ 2;
543 ef
->chains
= ef
->buckets
+ ef
->nbuckets
;
544 if (__elfN(parse_modmetadata
)(fp
, ef
) == 0)
547 if (ef
->kernel
) /* kernel must not depend on anything */
558 static char invalid_name
[] = "bad";
561 fake_modname(const char *name
)
567 sp
= strrchr(name
, '/');
572 ep
= strrchr(name
, '.');
576 ep
= invalid_name
+ sizeof(invalid_name
) - 1;
579 ep
= name
+ strlen(name
);
581 fp
= malloc(len
+ 1);
589 #if defined(__i386__) && __ELF_WORD_SIZE == 64
590 struct mod_metadata64
{
591 int md_version
; /* structure version MDTV_* */
592 int md_type
; /* type of entry MDT_* */
593 u_int64_t md_data
; /* specific data */
594 u_int64_t md_cval
; /* common string label */
599 __elfN(parse_modmetadata
)(struct preloaded_file
*fp
, elf_file_t ef
)
601 struct mod_metadata md
;
602 #if defined(__i386__) && __ELF_WORD_SIZE == 64
603 struct mod_metadata64 md64
;
605 struct mod_depend
*mdepend
;
606 struct mod_version mver
;
609 int error
, modcnt
, minfolen
;
610 Elf_Addr v
, p
, p_stop
;
612 if (__elfN(lookup_symbol
)(fp
, ef
, "__start_set_modmetadata_set", &sym
) != 0)
614 p
= sym
.st_value
+ ef
->off
;
615 if (__elfN(lookup_symbol
)(fp
, ef
, "__stop_set_modmetadata_set", &sym
) != 0)
617 p_stop
= sym
.st_value
+ ef
->off
;
621 COPYOUT(p
, &v
, sizeof(v
));
622 error
= __elfN(reloc_ptr
)(fp
, ef
, p
, &v
, sizeof(v
));
623 if (error
== EOPNOTSUPP
)
627 #if defined(__i386__) && __ELF_WORD_SIZE == 64
628 COPYOUT(v
, &md64
, sizeof(md64
));
629 error
= __elfN(reloc_ptr
)(fp
, ef
, v
, &md64
, sizeof(md64
));
630 if (error
== EOPNOTSUPP
) {
631 md64
.md_cval
+= ef
->off
;
632 md64
.md_data
+= ef
->off
;
633 } else if (error
!= 0)
635 md
.md_version
= md64
.md_version
;
636 md
.md_type
= md64
.md_type
;
637 md
.md_cval
= (const char *)(uintptr_t)md64
.md_cval
;
638 md
.md_data
= (void *)(uintptr_t)md64
.md_data
;
640 COPYOUT(v
, &md
, sizeof(md
));
641 error
= __elfN(reloc_ptr
)(fp
, ef
, v
, &md
, sizeof(md
));
642 if (error
== EOPNOTSUPP
) {
643 md
.md_cval
+= ef
->off
;
644 md
.md_data
= (char *)md
.md_data
+ ef
->off
;
645 } else if (error
!= 0)
648 p
+= sizeof(Elf_Addr
);
651 if (ef
->kernel
) /* kernel must not depend on anything */
653 s
= strdupout((vm_offset_t
)md
.md_cval
);
654 minfolen
= sizeof(*mdepend
) + strlen(s
) + 1;
655 mdepend
= malloc(minfolen
);
658 COPYOUT((vm_offset_t
)md
.md_data
, mdepend
, sizeof(*mdepend
));
659 strcpy((char*)(mdepend
+ 1), s
);
661 file_addmetadata(fp
, MODINFOMD_DEPLIST
, minfolen
, mdepend
);
665 s
= strdupout((vm_offset_t
)md
.md_cval
);
666 COPYOUT((vm_offset_t
)md
.md_data
, &mver
, sizeof(mver
));
667 file_addmodule(fp
, s
, mver
.mv_version
, NULL
);
674 s
= fake_modname(fp
->f_name
);
675 file_addmodule(fp
, s
, 1, NULL
);
682 elf_hash(const char *name
)
684 const unsigned char *p
= (const unsigned char *) name
;
690 if ((g
= h
& 0xf0000000) != 0)
697 static const char __elfN(bad_symtable
)[] = "elf" __XSTRING(__ELF_WORD_SIZE
) "_lookup_symbol: corrupt symbol table\n";
699 __elfN(lookup_symbol
)(struct preloaded_file
*fp
, elf_file_t ef
, const char* name
,
707 hash
= elf_hash(name
);
708 COPYOUT(&ef
->buckets
[hash
% ef
->nbuckets
], &symnum
, sizeof(symnum
));
710 while (symnum
!= STN_UNDEF
) {
711 if (symnum
>= ef
->nchains
) {
712 printf(__elfN(bad_symtable
));
716 COPYOUT(ef
->symtab
+ symnum
, &sym
, sizeof(sym
));
717 if (sym
.st_name
== 0) {
718 printf(__elfN(bad_symtable
));
722 strp
= strdupout((vm_offset_t
)(ef
->strtab
+ sym
.st_name
));
723 if (strcmp(name
, strp
) == 0) {
725 if (sym
.st_shndx
!= SHN_UNDEF
||
726 (sym
.st_value
!= 0 &&
727 ELF_ST_TYPE(sym
.st_info
) == STT_FUNC
)) {
734 COPYOUT(&ef
->chains
[symnum
], &symnum
, sizeof(symnum
));
740 * Apply any intra-module relocations to the value. p is the load address
741 * of the value and val/len is the value to be modified. This does NOT modify
742 * the image in-place, because this is done by kern_linker later on.
744 * Returns EOPNOTSUPP if no relocation method is supplied.
747 __elfN(reloc_ptr
)(struct preloaded_file
*mp
, elf_file_t ef
,
748 Elf_Addr p
, void *val
, size_t len
)
756 * The kernel is already relocated, but we still want to apply
757 * offset adjustments.
762 for (n
= 0; n
< ef
->relsz
/ sizeof(r
); n
++) {
763 COPYOUT(ef
->rel
+ n
, &r
, sizeof(r
));
765 error
= __elfN(reloc
)(ef
, __elfN(symaddr
), &r
, ELF_RELOC_REL
,
766 ef
->off
, p
, val
, len
);
770 for (n
= 0; n
< ef
->relasz
/ sizeof(a
); n
++) {
771 COPYOUT(ef
->rela
+ n
, &a
, sizeof(a
));
773 error
= __elfN(reloc
)(ef
, __elfN(symaddr
), &a
, ELF_RELOC_RELA
,
774 ef
->off
, p
, val
, len
);
783 __elfN(symaddr
)(struct elf_file
*ef
, Elf_Size symidx
)
786 /* Symbol lookup by index not required here. */