boot system and buildkernel - Remove the thrice damned forth interpreter
[dragonfly.git] / sys / boot / common / load_elf.c
1 /*-
2  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3  * Copyright (c) 1998 Peter Wemm <peter@freebsd.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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.
14  *
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
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD: src/sys/boot/common/load_elf.c,v 1.39 2008/10/14 10:11:14 raj Exp $
28  */
29
30 #include <sys/param.h>
31 #include <sys/exec.h>
32 #include <sys/linker.h>
33 #include <sys/module.h>
34 #include <sys/stdint.h>
35 #include <string.h>
36 #include <machine/elf.h>
37 #include <stand.h>
38 #define FREEBSD_ELF
39 #include <link.h>
40
41 #include "bootstrap.h"
42
43 #define COPYOUT(s,d,l)  archsw.arch_copyout((vm_offset_t)(s), d, l)
44
45 #if defined(__i386__) && __ELF_WORD_SIZE == 64
46 #undef ELF_TARG_CLASS
47 #undef ELF_TARG_MACH
48 #define ELF_TARG_CLASS  ELFCLASS64
49 #define ELF_TARG_MACH   EM_X86_64
50 #endif
51
52 typedef struct elf_file {
53     Elf_Phdr    *ph;
54     Elf_Ehdr    *ehdr;
55     Elf_Sym     *symtab;
56     Elf_Hashelt *hashtab;
57     Elf_Hashelt nbuckets;
58     Elf_Hashelt nchains;
59     Elf_Hashelt *buckets;
60     Elf_Hashelt *chains;
61     Elf_Rel     *rel;
62     size_t      relsz;
63     Elf_Rela    *rela;
64     size_t      relasz;
65     char        *strtab;
66     size_t      strsz;
67     int         fd;
68     caddr_t     firstpage;
69     size_t      firstlen;
70     int         kernel;
71     u_int64_t   off;
72 } *elf_file_t;
73
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);
81
82 const char      *__elfN(kerneltype) = "elf kernel";
83 const char      *__elfN(moduletype) = "elf module";
84
85 u_int64_t       __elfN(relocation_offset) = 0;
86
87 /*
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).
91  */
92 int
93 __elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result)
94 {
95     struct preloaded_file       *fp, *kfp;
96     struct elf_file             ef;
97     Elf_Ehdr                    *ehdr;
98     int                         err;
99     u_int                       pad;
100     ssize_t                     bytes_read;
101     char                        *fullpath;
102
103     fp = NULL;
104     bzero(&ef, sizeof(struct elf_file));
105
106     /*
107      * Open the image, read and validate the ELF header 
108      */
109     if (filename == NULL)       /* can't handle nameless */
110         return(EFTYPE);
111     if ((ef.fd = rel_open(filename, &fullpath, O_RDONLY)) == -1)
112         return(errno);
113     ef.firstpage = malloc(PAGE_SIZE);
114     if (ef.firstpage == NULL) {
115         close(ef.fd);
116         free(fullpath);
117         return(ENOMEM);
118     }
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 */
123         goto oerr;
124     }
125     ehdr = ef.ehdr = (Elf_Ehdr *)ef.firstpage;
126
127     /* Is it ELF? */
128     if (!IS_ELF(*ehdr)) {
129         err = EFTYPE;
130         goto oerr;
131     }
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 ? */
137         err = EFTYPE;
138         goto oerr;
139     }
140
141
142     /*
143      * Check to see what sort of module we are.
144      */
145     kfp = file_findfile(NULL, NULL);
146     if (ehdr->e_type == ET_DYN) {
147         /* Looks like a kld module */
148         if (kfp == NULL) {
149             printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module before kernel\n");
150             err = EPERM;
151             goto oerr;
152         }
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);
155             err = EPERM;
156             goto oerr;
157         }
158         /* Looks OK, got ahead */
159         ef.kernel = 0;
160
161         /* Page-align the load address */
162         pad = (u_int)dest & PAGE_MASK;
163         if (pad != 0) {
164             pad = PAGE_SIZE - pad;
165             dest += pad;
166         }
167     } else if (ehdr->e_type == ET_EXEC) {
168         /* Looks like a kernel */
169         if (kfp != NULL) {
170             printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: kernel already loaded\n");
171             err = EPERM;
172             goto oerr;
173         }
174         /* 
175          * Calculate destination address based on kernel entrypoint     
176          */
177         dest = ehdr->e_entry;
178         if (dest == 0) {
179             printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: not a kernel (maybe static binary?)\n");
180             err = EPERM;
181             goto oerr;
182         }
183         ef.kernel = 1;
184
185     } else {
186         err = EFTYPE;
187         goto oerr;
188     }
189
190     /* 
191      * Ok, we think we should handle this.
192      */
193     fp = file_alloc();
194     if (fp == NULL) {
195             printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: cannot allocate module info\n");
196             err = EPERM;
197             goto out;
198     }
199
200     /*
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.
203      */
204     if (ef.kernel) {
205         char *mptr;
206         char *fpend;
207         const char *prefix = "";
208
209         mptr = malloc(strlen(fullpath) * 2 + 10 + 16);
210         if (strncmp(fullpath, "/boot/", 6) != 0)
211                 prefix = "/boot";
212         sprintf(mptr, "%s%s", prefix, fullpath);
213         setenv("kernelname", mptr, 1);
214
215         fpend = strrchr(mptr, '/');
216         *fpend = 0;
217         if (strcmp(mptr, "/boot") == 0)
218                 sprintf(mptr, "/boot/modules");
219         /* this will be moved to "module_path" on boot */
220         setenv("exported_module_path", mptr, 1);
221         free(mptr);
222     }
223     fp->f_name = strdup(filename);
224     fp->f_type = strdup(ef.kernel ? __elfN(kerneltype) : __elfN(moduletype));
225
226 #ifdef ELF_VERBOSE
227     if (ef.kernel)
228         printf("%s entry at 0x%jx\n", filename, (uintmax_t)dest);
229 #else
230     printf("%s ", filename);
231 #endif
232
233     fp->f_size = __elfN(loadimage)(fp, &ef, dest);
234     if (fp->f_size == 0 || fp->f_addr == 0)
235         goto ioerr;
236
237     /* save exec header as metadata */
238     file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*ehdr), ehdr);
239
240     /* Load OK, return module pointer */
241     *result = (struct preloaded_file *)fp;
242     err = 0;
243     goto out;
244     
245  ioerr:
246     err = EIO;
247  oerr:
248     file_discard(fp);
249  out:
250     if (ef.firstpage)
251         free(ef.firstpage);
252     close(ef.fd);
253     if (fullpath)
254         free(fullpath);
255     return(err);
256 }
257
258 /*
259  * With the file (fd) open on the image, and (ehdr) containing
260  * the Elf header, load the image at (off)
261  */
262 static int
263 __elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off)
264 {
265     int         i;
266     u_int       j;
267     Elf_Ehdr    *ehdr;
268     Elf_Phdr    *phdr, *php;
269     Elf_Shdr    *shdr;
270     int         ret;
271     vm_offset_t firstaddr;
272     vm_offset_t lastaddr;
273     size_t      chunk;
274     ssize_t     result;
275     Elf_Addr    ssym, esym;
276     Elf_Dyn     *dp;
277     Elf_Addr    adp;
278     int         ndp;
279     int         symstrindex;
280     int         symtabindex;
281     Elf_Size    size;
282     u_int       fpcopy;
283
284     dp = NULL;
285     shdr = NULL;
286     ret = 0;
287     firstaddr = lastaddr = 0;
288     ehdr = ef->ehdr;
289     if (ef->kernel) {
290 #ifdef __i386__
291 #if __ELF_WORD_SIZE == 64
292         off = - (off & 0xffffffffff000000ull);/* x86_64 relocates after locore */
293 #else
294         off = - (off & 0xff000000u);    /* i386 relocates after locore */
295 #endif
296 #elif defined(__powerpc__)
297         /*
298          * On the purely virtual memory machines like e500, the kernel is
299          * linked against its final VA range, which is most often not
300          * available at the loader stage, but only after kernel initializes
301          * and completes its VM settings. In such cases we cannot use p_vaddr
302          * field directly to load ELF segments, but put them at some
303          * 'load-time' locations.
304          */
305         if (off & 0xf0000000u) {
306             off = -(off & 0xf0000000u);
307             /*
308              * XXX the physical load address should not be hardcoded. Note
309              * that the Book-E kernel assumes that it's loaded at a 16MB
310              * boundary for now...
311              */
312             off += 0x01000000;
313             ehdr->e_entry += off;
314 #ifdef ELF_VERBOSE
315             printf("Converted entry 0x%08x\n", ehdr->e_entry);
316 #endif
317         } else
318             off = 0;
319 #elif defined(__arm__)
320         if (off & 0xf0000000u) {
321             off = -(off & 0xf0000000u);
322             ehdr->e_entry += off;
323 #ifdef ELF_VERBOSE
324             printf("Converted entry 0x%08x\n", ehdr->e_entry);
325 #endif
326         } else
327             off = 0;
328 #else
329         off = 0;                /* other archs use direct mapped kernels */
330 #endif
331         __elfN(relocation_offset) = off;
332     }
333     ef->off = off;
334
335     if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr)) > ef->firstlen) {
336         printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: program header not within first page\n");
337         goto out;
338     }
339     phdr = (Elf_Phdr *)(ef->firstpage + ehdr->e_phoff);
340
341     for (i = 0; i < ehdr->e_phnum; i++) {
342         /* We want to load PT_LOAD segments only.. */
343         if (phdr[i].p_type != PT_LOAD)
344             continue;
345
346 #ifdef ELF_VERBOSE
347         printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx",
348             (long)phdr[i].p_filesz, (long)phdr[i].p_offset,
349             (long)(phdr[i].p_vaddr + off),
350             (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
351 #else
352         if ((phdr[i].p_flags & PF_W) == 0) {
353             printf("text=0x%lx ", (long)phdr[i].p_filesz);
354         } else {
355             printf("data=0x%lx", (long)phdr[i].p_filesz);
356             if (phdr[i].p_filesz < phdr[i].p_memsz)
357                 printf("+0x%lx", (long)(phdr[i].p_memsz -phdr[i].p_filesz));
358             printf(" ");
359         }
360 #endif
361         fpcopy = 0;
362         if (ef->firstlen > phdr[i].p_offset) {
363             fpcopy = ef->firstlen - phdr[i].p_offset;
364             archsw.arch_copyin(ef->firstpage + phdr[i].p_offset,
365                                phdr[i].p_vaddr + off, fpcopy);
366         }
367         if (phdr[i].p_filesz > fpcopy) {
368             if (kern_pread(ef->fd, phdr[i].p_vaddr + off + fpcopy,
369                 phdr[i].p_filesz - fpcopy, phdr[i].p_offset + fpcopy) != 0) {
370                 printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
371                     "_loadimage: read failed\n");
372                 goto out;
373             }
374         }
375         /* clear space from oversized segments; eg: bss */
376         if (phdr[i].p_filesz < phdr[i].p_memsz) {
377 #ifdef ELF_VERBOSE
378             printf(" (bss: 0x%lx-0x%lx)",
379                 (long)(phdr[i].p_vaddr + off + phdr[i].p_filesz),
380                 (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
381 #endif
382
383             kern_bzero(phdr[i].p_vaddr + off + phdr[i].p_filesz,
384                 phdr[i].p_memsz - phdr[i].p_filesz);
385         }
386 #ifdef ELF_VERBOSE
387         printf("\n");
388 #endif
389
390         if (firstaddr == 0 || firstaddr > (phdr[i].p_vaddr + off))
391             firstaddr = phdr[i].p_vaddr + off;
392         if (lastaddr == 0 || lastaddr < (phdr[i].p_vaddr + off + phdr[i].p_memsz))
393             lastaddr = phdr[i].p_vaddr + off + phdr[i].p_memsz;
394     }
395     lastaddr = roundup(lastaddr, sizeof(long));
396
397     /*
398      * Now grab the symbol tables.  This isn't easy if we're reading a
399      * .gz file.  I think the rule is going to have to be that you must
400      * strip a file to remove symbols before gzipping it so that we do not
401      * try to lseek() on it.
402      */
403     chunk = ehdr->e_shnum * ehdr->e_shentsize;
404     if (chunk == 0 || ehdr->e_shoff == 0)
405         goto nosyms;
406     shdr = alloc_pread(ef->fd, ehdr->e_shoff, chunk);
407     if (shdr == NULL) {
408         printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
409             "_loadimage: failed to read section headers");
410         goto nosyms;
411     }
412     symtabindex = -1;
413     symstrindex = -1;
414     for (i = 0; i < ehdr->e_shnum; i++) {
415         if (shdr[i].sh_type != SHT_SYMTAB)
416             continue;
417         for (j = 0; j < ehdr->e_phnum; j++) {
418             if (phdr[j].p_type != PT_LOAD)
419                 continue;
420             if (shdr[i].sh_offset >= phdr[j].p_offset &&
421                 (shdr[i].sh_offset + shdr[i].sh_size <=
422                  phdr[j].p_offset + phdr[j].p_filesz)) {
423                 shdr[i].sh_offset = 0;
424                 shdr[i].sh_size = 0;
425                 break;
426             }
427         }
428         if (shdr[i].sh_offset == 0 || shdr[i].sh_size == 0)
429             continue;           /* alread loaded in a PT_LOAD above */
430         /* Save it for loading below */
431         symtabindex = i;
432         symstrindex = shdr[i].sh_link;
433     }
434     if (symtabindex < 0 || symstrindex < 0)
435         goto nosyms;
436
437     /* Ok, committed to a load. */
438 #ifndef ELF_VERBOSE
439     printf("syms=[");
440 #endif
441     ssym = lastaddr;
442     for (i = symtabindex; i >= 0; i = symstrindex) {
443 #ifdef ELF_VERBOSE
444         char    *secname;
445
446         switch(shdr[i].sh_type) {
447             case SHT_SYMTAB:            /* Symbol table */
448                 secname = "symtab";
449                 break;
450             case SHT_STRTAB:            /* String table */
451                 secname = "strtab";
452                 break;
453             default:
454                 secname = "WHOA!!";
455                 break;
456         }
457 #endif
458
459         size = shdr[i].sh_size;
460         archsw.arch_copyin(&size, lastaddr, sizeof(size));
461         lastaddr += sizeof(size);
462
463 #ifdef ELF_VERBOSE
464         printf("\n%s: 0x%jx@0x%jx -> 0x%jx-0x%jx", secname,
465             (uintmax_t)shdr[i].sh_size, (uintmax_t)shdr[i].sh_offset,
466             (uintmax_t)lastaddr, (uintmax_t)(lastaddr + shdr[i].sh_size));
467 #else
468         if (i == symstrindex)
469             printf("+");
470         printf("0x%lx+0x%lx", (long)sizeof(size), (long)size);
471 #endif
472
473         if (lseek(ef->fd, (off_t)shdr[i].sh_offset, SEEK_SET) == -1) {
474             printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not seek for symbols - skipped!");
475             lastaddr = ssym;
476             ssym = 0;
477             goto nosyms;
478         }
479         result = archsw.arch_readin(ef->fd, lastaddr, shdr[i].sh_size);
480         if (result < 0 || (size_t)result != shdr[i].sh_size) {
481             printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not read symbols - skipped!");
482             lastaddr = ssym;
483             ssym = 0;
484             goto nosyms;
485         }
486         /* Reset offsets relative to ssym */
487         lastaddr += shdr[i].sh_size;
488         lastaddr = roundup(lastaddr, sizeof(size));
489         if (i == symtabindex)
490             symtabindex = -1;
491         else if (i == symstrindex)
492             symstrindex = -1;
493     }
494     esym = lastaddr;
495 #ifndef ELF_VERBOSE
496     printf("]");
497 #endif
498
499     file_addmetadata(fp, MODINFOMD_SSYM, sizeof(ssym), &ssym);
500     file_addmetadata(fp, MODINFOMD_ESYM, sizeof(esym), &esym);
501
502 nosyms:
503     printf("\n");
504
505     ret = lastaddr - firstaddr;
506     fp->f_addr = firstaddr;
507
508     php = NULL;
509     for (i = 0; i < ehdr->e_phnum; i++) {
510         if (phdr[i].p_type == PT_DYNAMIC) {
511             php = phdr + i;
512             adp = php->p_vaddr;
513             file_addmetadata(fp, MODINFOMD_DYNAMIC, sizeof(adp), &adp);
514             break;
515         }
516     }
517
518     if (php == NULL)    /* this is bad, we cannot get to symbols or _DYNAMIC */
519         goto out;
520
521     ndp = php->p_filesz / sizeof(Elf_Dyn);
522     if (ndp == 0)
523         goto out;
524     dp = malloc(php->p_filesz);
525     if (dp == NULL)
526         goto out;
527     archsw.arch_copyout(php->p_vaddr + off, dp, php->p_filesz);
528
529     ef->strsz = 0;
530     for (i = 0; i < ndp; i++) {
531         if (dp[i].d_tag == 0)
532             break;
533         switch (dp[i].d_tag) {
534         case DT_HASH:
535             ef->hashtab = (Elf_Hashelt*)(uintptr_t)(dp[i].d_un.d_ptr + off);
536             break;
537         case DT_STRTAB:
538             ef->strtab = (char *)(uintptr_t)(dp[i].d_un.d_ptr + off);
539             break;
540         case DT_STRSZ:
541             ef->strsz = dp[i].d_un.d_val;
542             break;
543         case DT_SYMTAB:
544             ef->symtab = (Elf_Sym*)(uintptr_t)(dp[i].d_un.d_ptr + off);
545             break;
546         case DT_REL:
547             ef->rel = (Elf_Rel *)(uintptr_t)(dp[i].d_un.d_ptr + off);
548             break;
549         case DT_RELSZ:
550             ef->relsz = dp[i].d_un.d_val;
551             break;
552         case DT_RELA:
553             ef->rela = (Elf_Rela *)(uintptr_t)(dp[i].d_un.d_ptr + off);
554             break;
555         case DT_RELASZ:
556             ef->relasz = dp[i].d_un.d_val;
557             break;
558         default:
559             break;
560         }
561     }
562     if (ef->hashtab == NULL || ef->symtab == NULL ||
563         ef->strtab == NULL || ef->strsz == 0)
564         goto out;
565     COPYOUT(ef->hashtab, &ef->nbuckets, sizeof(ef->nbuckets));
566     COPYOUT(ef->hashtab + 1, &ef->nchains, sizeof(ef->nchains));
567     ef->buckets = ef->hashtab + 2;
568     ef->chains = ef->buckets + ef->nbuckets;
569     if (__elfN(parse_modmetadata)(fp, ef) == 0)
570         goto out;
571
572     if (ef->kernel)                     /* kernel must not depend on anything */
573         goto out;
574
575 out:
576     if (dp)
577         free(dp);
578     if (shdr)
579         free(shdr);
580     return ret;
581 }
582
583 static char invalid_name[] = "bad";
584
585 char *
586 fake_modname(const char *name)
587 {
588     const char *sp, *ep;
589     char *fp;
590     size_t len;
591
592     sp = strrchr(name, '/');
593     if (sp)
594         sp++;
595     else
596         sp = name;
597     ep = strrchr(name, '.');
598     if (ep) {
599             if (ep == name) {
600                 sp = invalid_name;
601                 ep = invalid_name + sizeof(invalid_name) - 1;
602             } 
603     } else
604         ep = name + strlen(name);
605     len = ep - sp;
606     fp = malloc(len + 1);
607     if (fp == NULL)
608         return NULL;
609     memcpy(fp, sp, len);
610     fp[len] = '\0';
611     return fp;
612 }
613
614 #if defined(__i386__) && __ELF_WORD_SIZE == 64
615 struct mod_metadata64 {
616         int             md_version;     /* structure version MDTV_* */  
617         int             md_type;        /* type of entry MDT_* */
618         u_int64_t       md_data;        /* specific data */
619         u_int64_t       md_cval;        /* common string label */
620 };
621 #endif
622
623 int
624 __elfN(parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef)
625 {
626     struct mod_metadata md;
627 #if defined(__i386__) && __ELF_WORD_SIZE == 64
628     struct mod_metadata64 md64;
629 #endif
630     struct mod_depend *mdepend;
631     struct mod_version mver;
632     Elf_Sym sym;
633     char *s;
634     int error, modcnt, minfolen;
635     Elf_Addr v, p, p_stop;
636
637     if (__elfN(lookup_symbol)(fp, ef, "__start_set_modmetadata_set", &sym) != 0)
638         return ENOENT;
639     p = sym.st_value + ef->off;
640     if (__elfN(lookup_symbol)(fp, ef, "__stop_set_modmetadata_set", &sym) != 0)
641         return ENOENT;
642     p_stop = sym.st_value + ef->off;
643
644     modcnt = 0;
645     while (p < p_stop) {
646         COPYOUT(p, &v, sizeof(v));
647         error = __elfN(reloc_ptr)(fp, ef, p, &v, sizeof(v));
648         if (error == EOPNOTSUPP)
649             v += ef->off;
650         else if (error != 0)
651             return (error);
652 #if defined(__i386__) && __ELF_WORD_SIZE == 64
653         COPYOUT(v, &md64, sizeof(md64));
654         error = __elfN(reloc_ptr)(fp, ef, v, &md64, sizeof(md64));
655         if (error == EOPNOTSUPP) {
656             md64.md_cval += ef->off;
657             md64.md_data += ef->off;
658         } else if (error != 0)
659             return (error);
660         md.md_version = md64.md_version;
661         md.md_type = md64.md_type;
662         md.md_cval = (const char *)(uintptr_t)md64.md_cval;
663         md.md_data = (void *)(uintptr_t)md64.md_data;
664 #else
665         COPYOUT(v, &md, sizeof(md));
666         error = __elfN(reloc_ptr)(fp, ef, v, &md, sizeof(md));
667         if (error == EOPNOTSUPP) {
668             md.md_cval += ef->off;
669             md.md_data += ef->off;
670         } else if (error != 0)
671             return (error);
672 #endif
673         p += sizeof(Elf_Addr);
674         switch(md.md_type) {
675           case MDT_DEPEND:
676             if (ef->kernel)             /* kernel must not depend on anything */
677               break;
678             s = strdupout((vm_offset_t)md.md_cval);
679             minfolen = sizeof(*mdepend) + strlen(s) + 1;
680             mdepend = malloc(minfolen);
681             if (mdepend == NULL)
682                 return ENOMEM;
683             COPYOUT((vm_offset_t)md.md_data, mdepend, sizeof(*mdepend));
684             strcpy((char*)(mdepend + 1), s);
685             free(s);
686             file_addmetadata(fp, MODINFOMD_DEPLIST, minfolen, mdepend);
687             free(mdepend);
688             break;
689           case MDT_VERSION:
690             s = strdupout((vm_offset_t)md.md_cval);
691             COPYOUT((vm_offset_t)md.md_data, &mver, sizeof(mver));
692             file_addmodule(fp, s, mver.mv_version, NULL);
693             free(s);
694             modcnt++;
695             break;
696         }
697     }
698     if (modcnt == 0) {
699         s = fake_modname(fp->f_name);
700         file_addmodule(fp, s, 1, NULL);
701         free(s);
702     }
703     return 0;
704 }
705
706 static unsigned long
707 elf_hash(const char *name)
708 {
709     const unsigned char *p = (const unsigned char *) name;
710     unsigned long h = 0;
711     unsigned long g;
712
713     while (*p != '\0') {
714         h = (h << 4) + *p++;
715         if ((g = h & 0xf0000000) != 0)
716             h ^= g >> 24;
717         h &= ~g;
718     }
719     return h;
720 }
721
722 static const char __elfN(bad_symtable)[] = "elf" __XSTRING(__ELF_WORD_SIZE) "_lookup_symbol: corrupt symbol table\n";
723 int
724 __elfN(lookup_symbol)(struct preloaded_file *fp, elf_file_t ef, const char* name,
725                   Elf_Sym *symp)
726 {
727     Elf_Hashelt symnum;
728     Elf_Sym sym;
729     char *strp;
730     unsigned long hash;
731
732     hash = elf_hash(name);
733     COPYOUT(&ef->buckets[hash % ef->nbuckets], &symnum, sizeof(symnum));
734
735     while (symnum != STN_UNDEF) {
736         if (symnum >= ef->nchains) {
737             printf(__elfN(bad_symtable));
738             return ENOENT;
739         }
740
741         COPYOUT(ef->symtab + symnum, &sym, sizeof(sym));
742         if (sym.st_name == 0) {
743             printf(__elfN(bad_symtable));
744             return ENOENT;
745         }
746
747         strp = strdupout((vm_offset_t)(ef->strtab + sym.st_name));
748         if (strcmp(name, strp) == 0) {
749             free(strp);
750             if (sym.st_shndx != SHN_UNDEF ||
751                 (sym.st_value != 0 &&
752                  ELF_ST_TYPE(sym.st_info) == STT_FUNC)) {
753                 *symp = sym;
754                 return 0;
755             }
756             return ENOENT;
757         }
758         free(strp);
759         COPYOUT(&ef->chains[symnum], &symnum, sizeof(symnum));
760     }
761     return ENOENT;
762 }
763
764 /*
765  * Apply any intra-module relocations to the value. p is the load address
766  * of the value and val/len is the value to be modified. This does NOT modify
767  * the image in-place, because this is done by kern_linker later on.
768  *
769  * Returns EOPNOTSUPP if no relocation method is supplied.
770  */
771 static int
772 __elfN(reloc_ptr)(struct preloaded_file *mp, elf_file_t ef,
773     Elf_Addr p, void *val, size_t len)
774 {
775         size_t n;
776         Elf_Rela a;
777         Elf_Rel r;
778         int error;
779
780         /*
781          * The kernel is already relocated, but we still want to apply
782          * offset adjustments.
783          */
784         if (ef->kernel)
785                 return (EOPNOTSUPP);
786
787         for (n = 0; n < ef->relsz / sizeof(r); n++) {
788                 COPYOUT(ef->rel + n, &r, sizeof(r));
789
790                 error = __elfN(reloc)(ef, __elfN(symaddr), &r, ELF_RELOC_REL,
791                     ef->off, p, val, len);
792                 if (error != 0)
793                         return (error);
794         }
795         for (n = 0; n < ef->relasz / sizeof(a); n++) {
796                 COPYOUT(ef->rela + n, &a, sizeof(a));
797
798                 error = __elfN(reloc)(ef, __elfN(symaddr), &a, ELF_RELOC_RELA,
799                     ef->off, p, val, len);
800                 if (error != 0)
801                         return (error);
802         }
803
804         return (0);
805 }
806
807 static Elf_Addr
808 __elfN(symaddr)(struct elf_file *ef, Elf_Size symidx)
809 {
810
811         /* Symbol lookup by index not required here. */
812         return (0);
813 }