xref: /illumos-gate/usr/src/boot/common/load_elf_obj.c (revision 22028508fd28d36ff74dc02c5774a8ba1f0db045)
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