1*22028508SToomas Soome /*-
2*22028508SToomas Soome * Copyright (c) 2004 Ian Dowse <iedowse@freebsd.org>
3*22028508SToomas Soome * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
4*22028508SToomas Soome * Copyright (c) 1998 Peter Wemm <peter@freebsd.org>
5*22028508SToomas Soome * All rights reserved.
6*22028508SToomas Soome *
7*22028508SToomas Soome * Redistribution and use in source and binary forms, with or without
8*22028508SToomas Soome * modification, are permitted provided that the following conditions
9*22028508SToomas Soome * are met:
10*22028508SToomas Soome * 1. Redistributions of source code must retain the above copyright
11*22028508SToomas Soome * notice, this list of conditions and the following disclaimer.
12*22028508SToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
13*22028508SToomas Soome * notice, this list of conditions and the following disclaimer in the
14*22028508SToomas Soome * documentation and/or other materials provided with the distribution.
15*22028508SToomas Soome *
16*22028508SToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*22028508SToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*22028508SToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*22028508SToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*22028508SToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*22028508SToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*22028508SToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*22028508SToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*22028508SToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*22028508SToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*22028508SToomas Soome * SUCH DAMAGE.
27*22028508SToomas Soome */
28*22028508SToomas Soome
29*22028508SToomas Soome #include <sys/cdefs.h>
30*22028508SToomas Soome __FBSDID("$FreeBSD$");
31*22028508SToomas Soome
32*22028508SToomas Soome #include <sys/param.h>
33*22028508SToomas Soome #include <sys/exec.h>
34*22028508SToomas Soome #include <sys/linker.h>
35*22028508SToomas Soome #include <sys/module.h>
36*22028508SToomas Soome #include <inttypes.h>
37*22028508SToomas Soome #include <string.h>
38*22028508SToomas Soome #include <machine/elf.h>
39*22028508SToomas Soome #include <stand.h>
40*22028508SToomas Soome #define FREEBSD_ELF
41*22028508SToomas Soome #include <link.h>
42*22028508SToomas Soome
43*22028508SToomas Soome #include "bootstrap.h"
44*22028508SToomas Soome
45*22028508SToomas Soome #define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l)
46*22028508SToomas Soome
47*22028508SToomas Soome #if defined(__i386__) && __ELF_WORD_SIZE == 64
48*22028508SToomas Soome #undef ELF_TARG_CLASS
49*22028508SToomas Soome #undef ELF_TARG_MACH
50*22028508SToomas Soome #define ELF_TARG_CLASS ELFCLASS64
51*22028508SToomas Soome #define ELF_TARG_MACH EM_X86_64
52*22028508SToomas Soome #endif
53*22028508SToomas Soome
54*22028508SToomas Soome typedef struct elf_file {
55*22028508SToomas Soome Elf_Ehdr hdr;
56*22028508SToomas Soome Elf_Shdr *e_shdr;
57*22028508SToomas Soome
58*22028508SToomas Soome int symtabindex; /* Index of symbol table */
59*22028508SToomas Soome int shstrindex; /* Index of section name string table */
60*22028508SToomas Soome
61*22028508SToomas Soome int fd;
62*22028508SToomas Soome vm_offset_t off;
63*22028508SToomas Soome } *elf_file_t;
64*22028508SToomas Soome
65*22028508SToomas Soome static int __elfN(obj_loadimage)(struct preloaded_file *mp, elf_file_t ef,
66*22028508SToomas Soome u_int64_t loadaddr);
67*22028508SToomas Soome static int __elfN(obj_lookup_set)(struct preloaded_file *mp, elf_file_t ef,
68*22028508SToomas Soome const char *name, Elf_Addr *startp, Elf_Addr *stopp, int *countp);
69*22028508SToomas Soome static int __elfN(obj_reloc_ptr)(struct preloaded_file *mp, elf_file_t ef,
70*22028508SToomas Soome Elf_Addr p, void *val, size_t len);
71*22028508SToomas Soome static int __elfN(obj_parse_modmetadata)(struct preloaded_file *mp,
72*22028508SToomas Soome elf_file_t ef);
73*22028508SToomas Soome static Elf_Addr __elfN(obj_symaddr)(struct elf_file *ef, Elf_Size symidx);
74*22028508SToomas Soome
75*22028508SToomas Soome const char *__elfN(obj_kerneltype) = "elf kernel";
76*22028508SToomas Soome const char *__elfN(obj_moduletype) = "elf obj module";
77*22028508SToomas Soome
78*22028508SToomas Soome /*
79*22028508SToomas Soome * Attempt to load the file (file) as an ELF module. It will be stored at
80*22028508SToomas Soome * (dest), and a pointer to a module structure describing the loaded object
81*22028508SToomas Soome * will be saved in (result).
82*22028508SToomas Soome */
83*22028508SToomas Soome int
__elfN(obj_loadfile)84*22028508SToomas Soome __elfN(obj_loadfile)(char *filename, u_int64_t dest,
85*22028508SToomas Soome struct preloaded_file **result)
86*22028508SToomas Soome {
87*22028508SToomas Soome struct preloaded_file *fp, *kfp;
88*22028508SToomas Soome struct elf_file ef;
89*22028508SToomas Soome Elf_Ehdr *hdr;
90*22028508SToomas Soome int err;
91*22028508SToomas Soome ssize_t bytes_read;
92*22028508SToomas Soome
93*22028508SToomas Soome fp = NULL;
94*22028508SToomas Soome bzero(&ef, sizeof(struct elf_file));
95*22028508SToomas Soome
96*22028508SToomas Soome /*
97*22028508SToomas Soome * Open the image, read and validate the ELF header
98*22028508SToomas Soome */
99*22028508SToomas Soome if (filename == NULL) /* can't handle nameless */
100*22028508SToomas Soome return(EFTYPE);
101*22028508SToomas Soome if ((ef.fd = open(filename, O_RDONLY)) == -1)
102*22028508SToomas Soome return(errno);
103*22028508SToomas Soome
104*22028508SToomas Soome hdr = &ef.hdr;
105*22028508SToomas Soome bytes_read = read(ef.fd, hdr, sizeof(*hdr));
106*22028508SToomas Soome if (bytes_read != sizeof(*hdr)) {
107*22028508SToomas Soome err = EFTYPE; /* could be EIO, but may be small file */
108*22028508SToomas Soome goto oerr;
109*22028508SToomas Soome }
110*22028508SToomas Soome
111*22028508SToomas Soome /* Is it ELF? */
112*22028508SToomas Soome if (!IS_ELF(*hdr)) {
113*22028508SToomas Soome err = EFTYPE;
114*22028508SToomas Soome goto oerr;
115*22028508SToomas Soome }
116*22028508SToomas Soome if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */
117*22028508SToomas Soome hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
118*22028508SToomas Soome hdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */
119*22028508SToomas Soome hdr->e_version != EV_CURRENT ||
120*22028508SToomas Soome hdr->e_machine != ELF_TARG_MACH || /* Machine ? */
121*22028508SToomas Soome hdr->e_type != ET_REL) {
122*22028508SToomas Soome err = EFTYPE;
123*22028508SToomas Soome goto oerr;
124*22028508SToomas Soome }
125*22028508SToomas Soome
126*22028508SToomas Soome if (hdr->e_shnum * hdr->e_shentsize == 0 || hdr->e_shoff == 0 ||
127*22028508SToomas Soome hdr->e_shentsize != sizeof(Elf_Shdr)) {
128*22028508SToomas Soome err = EFTYPE;
129*22028508SToomas Soome goto oerr;
130*22028508SToomas Soome }
131*22028508SToomas Soome
132*22028508SToomas Soome kfp = file_findfile(NULL, __elfN(obj_kerneltype));
133*22028508SToomas Soome if (kfp == NULL) {
134*22028508SToomas Soome printf("elf" __XSTRING(__ELF_WORD_SIZE)
135*22028508SToomas Soome "_obj_loadfile: can't load module before kernel\n");
136*22028508SToomas Soome err = EPERM;
137*22028508SToomas Soome goto oerr;
138*22028508SToomas Soome }
139*22028508SToomas Soome
140*22028508SToomas Soome if (archsw.arch_loadaddr != NULL)
141*22028508SToomas Soome dest = archsw.arch_loadaddr(LOAD_ELF, hdr, dest);
142*22028508SToomas Soome else
143*22028508SToomas Soome dest = roundup(dest, PAGE_SIZE);
144*22028508SToomas Soome
145*22028508SToomas Soome /*
146*22028508SToomas Soome * Ok, we think we should handle this.
147*22028508SToomas Soome */
148*22028508SToomas Soome fp = file_alloc();
149*22028508SToomas Soome if (fp == NULL) {
150*22028508SToomas Soome printf("elf" __XSTRING(__ELF_WORD_SIZE)
151*22028508SToomas Soome "_obj_loadfile: cannot allocate module info\n");
152*22028508SToomas Soome err = EPERM;
153*22028508SToomas Soome goto out;
154*22028508SToomas Soome }
155*22028508SToomas Soome fp->f_name = strdup(filename);
156*22028508SToomas Soome fp->f_type = strdup(__elfN(obj_moduletype));
157*22028508SToomas Soome
158*22028508SToomas Soome printf("%s ", filename);
159*22028508SToomas Soome
160*22028508SToomas Soome fp->f_size = __elfN(obj_loadimage)(fp, &ef, dest);
161*22028508SToomas Soome if (fp->f_size == 0 || fp->f_addr == 0)
162*22028508SToomas Soome goto ioerr;
163*22028508SToomas Soome
164*22028508SToomas Soome /* save exec header as metadata */
165*22028508SToomas Soome file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*hdr), hdr);
166*22028508SToomas Soome
167*22028508SToomas Soome /* Load OK, return module pointer */
168*22028508SToomas Soome *result = (struct preloaded_file *)fp;
169*22028508SToomas Soome err = 0;
170*22028508SToomas Soome goto out;
171*22028508SToomas Soome
172*22028508SToomas Soome ioerr:
173*22028508SToomas Soome err = EIO;
174*22028508SToomas Soome oerr:
175*22028508SToomas Soome file_discard(fp);
176*22028508SToomas Soome out:
177*22028508SToomas Soome close(ef.fd);
178*22028508SToomas Soome if (ef.e_shdr != NULL)
179*22028508SToomas Soome free(ef.e_shdr);
180*22028508SToomas Soome
181*22028508SToomas Soome return(err);
182*22028508SToomas Soome }
183*22028508SToomas Soome
184*22028508SToomas Soome /*
185*22028508SToomas Soome * With the file (fd) open on the image, and (ehdr) containing
186*22028508SToomas Soome * the Elf header, load the image at (off)
187*22028508SToomas Soome */
188*22028508SToomas Soome static int
__elfN(obj_loadimage)189*22028508SToomas Soome __elfN(obj_loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off)
190*22028508SToomas Soome {
191*22028508SToomas Soome Elf_Ehdr *hdr;
192*22028508SToomas Soome Elf_Shdr *shdr, *cshdr, *lshdr;
193*22028508SToomas Soome vm_offset_t firstaddr, lastaddr;
194*22028508SToomas Soome int i, nsym, res, ret, shdrbytes, symstrindex;
195*22028508SToomas Soome
196*22028508SToomas Soome ret = 0;
197*22028508SToomas Soome firstaddr = lastaddr = (vm_offset_t)off;
198*22028508SToomas Soome hdr = &ef->hdr;
199*22028508SToomas Soome ef->off = (vm_offset_t)off;
200*22028508SToomas Soome
201*22028508SToomas Soome /* Read in the section headers. */
202*22028508SToomas Soome shdrbytes = hdr->e_shnum * hdr->e_shentsize;
203*22028508SToomas Soome shdr = alloc_pread(ef->fd, (off_t)hdr->e_shoff, shdrbytes);
204*22028508SToomas Soome if (shdr == NULL) {
205*22028508SToomas Soome printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
206*22028508SToomas Soome "_obj_loadimage: read section headers failed\n");
207*22028508SToomas Soome goto out;
208*22028508SToomas Soome }
209*22028508SToomas Soome ef->e_shdr = shdr;
210*22028508SToomas Soome
211*22028508SToomas Soome /*
212*22028508SToomas Soome * Decide where to load everything, but don't read it yet.
213*22028508SToomas Soome * We store the load address as a non-zero sh_addr value.
214*22028508SToomas Soome * Start with the code/data and bss.
215*22028508SToomas Soome */
216*22028508SToomas Soome for (i = 0; i < hdr->e_shnum; i++)
217*22028508SToomas Soome shdr[i].sh_addr = 0;
218*22028508SToomas Soome for (i = 0; i < hdr->e_shnum; i++) {
219*22028508SToomas Soome if (shdr[i].sh_size == 0)
220*22028508SToomas Soome continue;
221*22028508SToomas Soome switch (shdr[i].sh_type) {
222*22028508SToomas Soome case SHT_PROGBITS:
223*22028508SToomas Soome case SHT_NOBITS:
224*22028508SToomas Soome lastaddr = roundup(lastaddr, shdr[i].sh_addralign);
225*22028508SToomas Soome shdr[i].sh_addr = (Elf_Addr)lastaddr;
226*22028508SToomas Soome lastaddr += shdr[i].sh_size;
227*22028508SToomas Soome break;
228*22028508SToomas Soome }
229*22028508SToomas Soome }
230*22028508SToomas Soome
231*22028508SToomas Soome /* Symbols. */
232*22028508SToomas Soome nsym = 0;
233*22028508SToomas Soome for (i = 0; i < hdr->e_shnum; i++) {
234*22028508SToomas Soome switch (shdr[i].sh_type) {
235*22028508SToomas Soome case SHT_SYMTAB:
236*22028508SToomas Soome nsym++;
237*22028508SToomas Soome ef->symtabindex = i;
238*22028508SToomas Soome shdr[i].sh_addr = (Elf_Addr)lastaddr;
239*22028508SToomas Soome lastaddr += shdr[i].sh_size;
240*22028508SToomas Soome break;
241*22028508SToomas Soome }
242*22028508SToomas Soome }
243*22028508SToomas Soome if (nsym != 1) {
244*22028508SToomas Soome printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
245*22028508SToomas Soome "_obj_loadimage: file has no valid symbol table\n");
246*22028508SToomas Soome goto out;
247*22028508SToomas Soome }
248*22028508SToomas Soome lastaddr = roundup(lastaddr, shdr[ef->symtabindex].sh_addralign);
249*22028508SToomas Soome shdr[ef->symtabindex].sh_addr = (Elf_Addr)lastaddr;
250*22028508SToomas Soome lastaddr += shdr[ef->symtabindex].sh_size;
251*22028508SToomas Soome
252*22028508SToomas Soome symstrindex = shdr[ef->symtabindex].sh_link;
253*22028508SToomas Soome if (symstrindex < 0 || symstrindex >= hdr->e_shnum ||
254*22028508SToomas Soome shdr[symstrindex].sh_type != SHT_STRTAB) {
255*22028508SToomas Soome printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
256*22028508SToomas Soome "_obj_loadimage: file has invalid symbol strings\n");
257*22028508SToomas Soome goto out;
258*22028508SToomas Soome }
259*22028508SToomas Soome lastaddr = roundup(lastaddr, shdr[symstrindex].sh_addralign);
260*22028508SToomas Soome shdr[symstrindex].sh_addr = (Elf_Addr)lastaddr;
261*22028508SToomas Soome lastaddr += shdr[symstrindex].sh_size;
262*22028508SToomas Soome
263*22028508SToomas Soome /* Section names. */
264*22028508SToomas Soome if (hdr->e_shstrndx == 0 || hdr->e_shstrndx >= hdr->e_shnum ||
265*22028508SToomas Soome shdr[hdr->e_shstrndx].sh_type != SHT_STRTAB) {
266*22028508SToomas Soome printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
267*22028508SToomas Soome "_obj_loadimage: file has no section names\n");
268*22028508SToomas Soome goto out;
269*22028508SToomas Soome }
270*22028508SToomas Soome ef->shstrindex = hdr->e_shstrndx;
271*22028508SToomas Soome lastaddr = roundup(lastaddr, shdr[ef->shstrindex].sh_addralign);
272*22028508SToomas Soome shdr[ef->shstrindex].sh_addr = (Elf_Addr)lastaddr;
273*22028508SToomas Soome lastaddr += shdr[ef->shstrindex].sh_size;
274*22028508SToomas Soome
275*22028508SToomas Soome /* Relocation tables. */
276*22028508SToomas Soome for (i = 0; i < hdr->e_shnum; i++) {
277*22028508SToomas Soome switch (shdr[i].sh_type) {
278*22028508SToomas Soome case SHT_REL:
279*22028508SToomas Soome case SHT_RELA:
280*22028508SToomas Soome lastaddr = roundup(lastaddr, shdr[i].sh_addralign);
281*22028508SToomas Soome shdr[i].sh_addr = (Elf_Addr)lastaddr;
282*22028508SToomas Soome lastaddr += shdr[i].sh_size;
283*22028508SToomas Soome break;
284*22028508SToomas Soome }
285*22028508SToomas Soome }
286*22028508SToomas Soome
287*22028508SToomas Soome /* Clear the whole area, including bss regions. */
288*22028508SToomas Soome kern_bzero(firstaddr, lastaddr - firstaddr);
289*22028508SToomas Soome
290*22028508SToomas Soome /* Figure section with the lowest file offset we haven't loaded yet. */
291*22028508SToomas Soome for (cshdr = NULL; /* none */; /* none */)
292*22028508SToomas Soome {
293*22028508SToomas Soome /*
294*22028508SToomas Soome * Find next section to load. The complexity of this loop is
295*22028508SToomas Soome * O(n^2), but with the number of sections being typically
296*22028508SToomas Soome * small, we do not care.
297*22028508SToomas Soome */
298*22028508SToomas Soome lshdr = cshdr;
299*22028508SToomas Soome
300*22028508SToomas Soome for (i = 0; i < hdr->e_shnum; i++) {
301*22028508SToomas Soome if (shdr[i].sh_addr == 0 ||
302*22028508SToomas Soome shdr[i].sh_type == SHT_NOBITS)
303*22028508SToomas Soome continue;
304*22028508SToomas Soome /* Skip sections that were loaded already. */
305*22028508SToomas Soome if (lshdr != NULL &&
306*22028508SToomas Soome lshdr->sh_offset >= shdr[i].sh_offset)
307*22028508SToomas Soome continue;
308*22028508SToomas Soome /* Find section with smallest offset. */
309*22028508SToomas Soome if (cshdr == lshdr ||
310*22028508SToomas Soome cshdr->sh_offset > shdr[i].sh_offset)
311*22028508SToomas Soome cshdr = &shdr[i];
312*22028508SToomas Soome }
313*22028508SToomas Soome
314*22028508SToomas Soome if (cshdr == lshdr)
315*22028508SToomas Soome break;
316*22028508SToomas Soome
317*22028508SToomas Soome if (kern_pread(ef->fd, (vm_offset_t)cshdr->sh_addr,
318*22028508SToomas Soome cshdr->sh_size, (off_t)cshdr->sh_offset) != 0) {
319*22028508SToomas Soome printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
320*22028508SToomas Soome "_obj_loadimage: read failed\n");
321*22028508SToomas Soome goto out;
322*22028508SToomas Soome }
323*22028508SToomas Soome }
324*22028508SToomas Soome
325*22028508SToomas Soome file_addmetadata(fp, MODINFOMD_SHDR, shdrbytes, shdr);
326*22028508SToomas Soome
327*22028508SToomas Soome res = __elfN(obj_parse_modmetadata)(fp, ef);
328*22028508SToomas Soome if (res != 0)
329*22028508SToomas Soome goto out;
330*22028508SToomas Soome
331*22028508SToomas Soome ret = lastaddr - firstaddr;
332*22028508SToomas Soome fp->f_addr = firstaddr;
333*22028508SToomas Soome
334*22028508SToomas Soome printf("size 0x%lx at 0x%lx", (u_long)ret, (u_long)firstaddr);
335*22028508SToomas Soome
336*22028508SToomas Soome out:
337*22028508SToomas Soome printf("\n");
338*22028508SToomas Soome return ret;
339*22028508SToomas Soome }
340*22028508SToomas Soome
341*22028508SToomas Soome #if defined(__i386__) && __ELF_WORD_SIZE == 64
342*22028508SToomas Soome struct mod_metadata64 {
343*22028508SToomas Soome int md_version; /* structure version MDTV_* */
344*22028508SToomas Soome int md_type; /* type of entry MDT_* */
345*22028508SToomas Soome u_int64_t md_data; /* specific data */
346*22028508SToomas Soome u_int64_t md_cval; /* common string label */
347*22028508SToomas Soome };
348*22028508SToomas Soome #endif
349*22028508SToomas Soome
350*22028508SToomas Soome int
__elfN(obj_parse_modmetadata)351*22028508SToomas Soome __elfN(obj_parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef)
352*22028508SToomas Soome {
353*22028508SToomas Soome struct mod_metadata md;
354*22028508SToomas Soome #if defined(__i386__) && __ELF_WORD_SIZE == 64
355*22028508SToomas Soome struct mod_metadata64 md64;
356*22028508SToomas Soome #endif
357*22028508SToomas Soome struct mod_depend *mdepend;
358*22028508SToomas Soome struct mod_version mver;
359*22028508SToomas Soome char *s;
360*22028508SToomas Soome int error, modcnt, minfolen;
361*22028508SToomas Soome Elf_Addr v, p, p_stop;
362*22028508SToomas Soome
363*22028508SToomas Soome if (__elfN(obj_lookup_set)(fp, ef, "modmetadata_set", &p, &p_stop,
364*22028508SToomas Soome &modcnt) != 0)
365*22028508SToomas Soome return 0;
366*22028508SToomas Soome
367*22028508SToomas Soome modcnt = 0;
368*22028508SToomas Soome while (p < p_stop) {
369*22028508SToomas Soome COPYOUT(p, &v, sizeof(v));
370*22028508SToomas Soome error = __elfN(obj_reloc_ptr)(fp, ef, p, &v, sizeof(v));
371*22028508SToomas Soome if (error != 0)
372*22028508SToomas Soome return (error);
373*22028508SToomas Soome #if defined(__i386__) && __ELF_WORD_SIZE == 64
374*22028508SToomas Soome COPYOUT(v, &md64, sizeof(md64));
375*22028508SToomas Soome error = __elfN(obj_reloc_ptr)(fp, ef, v, &md64, sizeof(md64));
376*22028508SToomas Soome if (error != 0)
377*22028508SToomas Soome return (error);
378*22028508SToomas Soome md.md_version = md64.md_version;
379*22028508SToomas Soome md.md_type = md64.md_type;
380*22028508SToomas Soome md.md_cval = (const char *)(uintptr_t)md64.md_cval;
381*22028508SToomas Soome md.md_data = (void *)(uintptr_t)md64.md_data;
382*22028508SToomas Soome #else
383*22028508SToomas Soome COPYOUT(v, &md, sizeof(md));
384*22028508SToomas Soome error = __elfN(obj_reloc_ptr)(fp, ef, v, &md, sizeof(md));
385*22028508SToomas Soome if (error != 0)
386*22028508SToomas Soome return (error);
387*22028508SToomas Soome #endif
388*22028508SToomas Soome p += sizeof(Elf_Addr);
389*22028508SToomas Soome switch(md.md_type) {
390*22028508SToomas Soome case MDT_DEPEND:
391*22028508SToomas Soome s = strdupout((vm_offset_t)md.md_cval);
392*22028508SToomas Soome minfolen = sizeof(*mdepend) + strlen(s) + 1;
393*22028508SToomas Soome mdepend = malloc(minfolen);
394*22028508SToomas Soome if (mdepend == NULL)
395*22028508SToomas Soome return ENOMEM;
396*22028508SToomas Soome COPYOUT((vm_offset_t)md.md_data, mdepend,
397*22028508SToomas Soome sizeof(*mdepend));
398*22028508SToomas Soome strcpy((char*)(mdepend + 1), s);
399*22028508SToomas Soome free(s);
400*22028508SToomas Soome file_addmetadata(fp, MODINFOMD_DEPLIST, minfolen,
401*22028508SToomas Soome mdepend);
402*22028508SToomas Soome free(mdepend);
403*22028508SToomas Soome break;
404*22028508SToomas Soome case MDT_VERSION:
405*22028508SToomas Soome s = strdupout((vm_offset_t)md.md_cval);
406*22028508SToomas Soome COPYOUT((vm_offset_t)md.md_data, &mver, sizeof(mver));
407*22028508SToomas Soome file_addmodule(fp, s, mver.mv_version, NULL);
408*22028508SToomas Soome free(s);
409*22028508SToomas Soome modcnt++;
410*22028508SToomas Soome break;
411*22028508SToomas Soome case MDT_MODULE:
412*22028508SToomas Soome case MDT_PNP_INFO:
413*22028508SToomas Soome break;
414*22028508SToomas Soome default:
415*22028508SToomas Soome printf("unknown type %d\n", md.md_type);
416*22028508SToomas Soome break;
417*22028508SToomas Soome }
418*22028508SToomas Soome }
419*22028508SToomas Soome return 0;
420*22028508SToomas Soome }
421*22028508SToomas Soome
422*22028508SToomas Soome static int
__elfN(obj_lookup_set)423*22028508SToomas Soome __elfN(obj_lookup_set)(struct preloaded_file *fp __unused, elf_file_t ef,
424*22028508SToomas Soome const char* name, Elf_Addr *startp, Elf_Addr *stopp, int *countp)
425*22028508SToomas Soome {
426*22028508SToomas Soome Elf_Ehdr *hdr;
427*22028508SToomas Soome Elf_Shdr *shdr;
428*22028508SToomas Soome char *p;
429*22028508SToomas Soome vm_offset_t shstrtab;
430*22028508SToomas Soome int i;
431*22028508SToomas Soome
432*22028508SToomas Soome hdr = &ef->hdr;
433*22028508SToomas Soome shdr = ef->e_shdr;
434*22028508SToomas Soome shstrtab = shdr[ef->shstrindex].sh_addr;
435*22028508SToomas Soome
436*22028508SToomas Soome for (i = 0; i < hdr->e_shnum; i++) {
437*22028508SToomas Soome if (shdr[i].sh_type != SHT_PROGBITS)
438*22028508SToomas Soome continue;
439*22028508SToomas Soome if (shdr[i].sh_name == 0)
440*22028508SToomas Soome continue;
441*22028508SToomas Soome p = strdupout(shstrtab + shdr[i].sh_name);
442*22028508SToomas Soome if (strncmp(p, "set_", 4) == 0 && strcmp(p + 4, name) == 0) {
443*22028508SToomas Soome *startp = shdr[i].sh_addr;
444*22028508SToomas Soome *stopp = shdr[i].sh_addr + shdr[i].sh_size;
445*22028508SToomas Soome *countp = (*stopp - *startp) / sizeof(Elf_Addr);
446*22028508SToomas Soome free(p);
447*22028508SToomas Soome return (0);
448*22028508SToomas Soome }
449*22028508SToomas Soome free(p);
450*22028508SToomas Soome }
451*22028508SToomas Soome
452*22028508SToomas Soome return (ESRCH);
453*22028508SToomas Soome }
454*22028508SToomas Soome
455*22028508SToomas Soome /*
456*22028508SToomas Soome * Apply any intra-module relocations to the value. p is the load address
457*22028508SToomas Soome * of the value and val/len is the value to be modified. This does NOT modify
458*22028508SToomas Soome * the image in-place, because this is done by kern_linker later on.
459*22028508SToomas Soome */
460*22028508SToomas Soome static int
__elfN(obj_reloc_ptr)461*22028508SToomas Soome __elfN(obj_reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, Elf_Addr p,
462*22028508SToomas Soome void *val, size_t len)
463*22028508SToomas Soome {
464*22028508SToomas Soome Elf_Ehdr *hdr;
465*22028508SToomas Soome Elf_Shdr *shdr;
466*22028508SToomas Soome Elf_Addr off = p;
467*22028508SToomas Soome Elf_Addr base;
468*22028508SToomas Soome Elf_Rela a, *abase;
469*22028508SToomas Soome Elf_Rel r, *rbase;
470*22028508SToomas Soome int error, i, j, nrel, nrela;
471*22028508SToomas Soome
472*22028508SToomas Soome (void)mp;
473*22028508SToomas Soome hdr = &ef->hdr;
474*22028508SToomas Soome shdr = ef->e_shdr;
475*22028508SToomas Soome
476*22028508SToomas Soome for (i = 0; i < hdr->e_shnum; i++) {
477*22028508SToomas Soome if (shdr[i].sh_type != SHT_RELA && shdr[i].sh_type != SHT_REL)
478*22028508SToomas Soome continue;
479*22028508SToomas Soome base = shdr[shdr[i].sh_info].sh_addr;
480*22028508SToomas Soome if (base == 0 || shdr[i].sh_addr == 0)
481*22028508SToomas Soome continue;
482*22028508SToomas Soome if (off < base || off + len > base +
483*22028508SToomas Soome shdr[shdr[i].sh_info].sh_size)
484*22028508SToomas Soome continue;
485*22028508SToomas Soome
486*22028508SToomas Soome switch (shdr[i].sh_type) {
487*22028508SToomas Soome case SHT_RELA:
488*22028508SToomas Soome abase = (Elf_Rela *)(intptr_t)shdr[i].sh_addr;
489*22028508SToomas Soome
490*22028508SToomas Soome nrela = shdr[i].sh_size / sizeof(Elf_Rela);
491*22028508SToomas Soome for (j = 0; j < nrela; j++) {
492*22028508SToomas Soome COPYOUT(abase + j, &a, sizeof(a));
493*22028508SToomas Soome
494*22028508SToomas Soome error = __elfN(reloc)(ef, __elfN(obj_symaddr),
495*22028508SToomas Soome &a, ELF_RELOC_RELA, base, off, val, len);
496*22028508SToomas Soome if (error != 0)
497*22028508SToomas Soome return (error);
498*22028508SToomas Soome }
499*22028508SToomas Soome break;
500*22028508SToomas Soome case SHT_REL:
501*22028508SToomas Soome rbase = (Elf_Rel *)(intptr_t)shdr[i].sh_addr;
502*22028508SToomas Soome
503*22028508SToomas Soome nrel = shdr[i].sh_size / sizeof(Elf_Rel);
504*22028508SToomas Soome for (j = 0; j < nrel; j++) {
505*22028508SToomas Soome COPYOUT(rbase + j, &r, sizeof(r));
506*22028508SToomas Soome
507*22028508SToomas Soome error = __elfN(reloc)(ef, __elfN(obj_symaddr),
508*22028508SToomas Soome &r, ELF_RELOC_REL, base, off, val, len);
509*22028508SToomas Soome if (error != 0)
510*22028508SToomas Soome return (error);
511*22028508SToomas Soome }
512*22028508SToomas Soome break;
513*22028508SToomas Soome }
514*22028508SToomas Soome }
515*22028508SToomas Soome return (0);
516*22028508SToomas Soome }
517*22028508SToomas Soome
518*22028508SToomas Soome /* Look up the address of a specified symbol. */
519*22028508SToomas Soome static Elf_Addr
__elfN(obj_symaddr)520*22028508SToomas Soome __elfN(obj_symaddr)(struct elf_file *ef, Elf_Size symidx)
521*22028508SToomas Soome {
522*22028508SToomas Soome Elf_Sym sym;
523*22028508SToomas Soome Elf_Addr base;
524*22028508SToomas Soome
525*22028508SToomas Soome if (symidx >= ef->e_shdr[ef->symtabindex].sh_size / sizeof(Elf_Sym))
526*22028508SToomas Soome return (0);
527*22028508SToomas Soome COPYOUT(ef->e_shdr[ef->symtabindex].sh_addr + symidx * sizeof(Elf_Sym),
528*22028508SToomas Soome &sym, sizeof(sym));
529*22028508SToomas Soome if (sym.st_shndx == SHN_UNDEF || sym.st_shndx >= ef->hdr.e_shnum)
530*22028508SToomas Soome return (0);
531*22028508SToomas Soome base = ef->e_shdr[sym.st_shndx].sh_addr;
532*22028508SToomas Soome if (base == 0)
533*22028508SToomas Soome return (0);
534*22028508SToomas Soome return (base + sym.st_value);
535*22028508SToomas Soome }
536