xref: /illumos-gate/usr/src/boot/common/load_elf.c (revision de11c9b692361446554965e726e5a8084864f764)
1*de11c9b6SToomas Soome /*
222028508SToomas Soome  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
322028508SToomas Soome  * Copyright (c) 1998 Peter Wemm <peter@freebsd.org>
422028508SToomas Soome  * All rights reserved.
522028508SToomas Soome  *
622028508SToomas Soome  * Redistribution and use in source and binary forms, with or without
722028508SToomas Soome  * modification, are permitted provided that the following conditions
822028508SToomas Soome  * are met:
922028508SToomas Soome  * 1. Redistributions of source code must retain the above copyright
1022028508SToomas Soome  *    notice, this list of conditions and the following disclaimer.
1122028508SToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
1222028508SToomas Soome  *    notice, this list of conditions and the following disclaimer in the
1322028508SToomas Soome  *    documentation and/or other materials provided with the distribution.
1422028508SToomas Soome  *
1522028508SToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1622028508SToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1722028508SToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1822028508SToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1922028508SToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2022028508SToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2122028508SToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2222028508SToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2322028508SToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2422028508SToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2522028508SToomas Soome  * SUCH DAMAGE.
2622028508SToomas Soome  */
2722028508SToomas Soome 
2822028508SToomas Soome #include <sys/cdefs.h>
2922028508SToomas Soome 
3022028508SToomas Soome #include <sys/param.h>
3122028508SToomas Soome #include <sys/exec.h>
3222028508SToomas Soome #include <sys/linker.h>
3322028508SToomas Soome #include <sys/module.h>
3422028508SToomas Soome #include <sys/stdint.h>
3522028508SToomas Soome #include <string.h>
3622028508SToomas Soome #include <machine/elf.h>
3722028508SToomas Soome #include <stand.h>
3822028508SToomas Soome #define	FREEBSD_ELF
3922028508SToomas Soome #include <link.h>
4022028508SToomas Soome 
4122028508SToomas Soome #include "bootstrap.h"
4222028508SToomas Soome 
4322028508SToomas Soome #define	COPYOUT(s, d, l)	archsw.arch_copyout((vm_offset_t)(s), d, l)
4422028508SToomas Soome 
4522028508SToomas Soome #if defined(__i386__) && __ELF_WORD_SIZE == 64
4622028508SToomas Soome #undef ELF_TARG_CLASS
4722028508SToomas Soome #undef ELF_TARG_MACH
4822028508SToomas Soome #define	ELF_TARG_CLASS  ELFCLASS64
4922028508SToomas Soome #define	ELF_TARG_MACH   EM_X86_64
5022028508SToomas Soome #endif
5122028508SToomas Soome 
5222028508SToomas Soome typedef struct elf_file {
5322028508SToomas Soome 	Elf_Phdr	*ph;
5422028508SToomas Soome 	Elf_Ehdr	*ehdr;
5522028508SToomas Soome 	Elf_Sym		*symtab;
5622028508SToomas Soome 	Elf_Hashelt	*hashtab;
5722028508SToomas Soome 	Elf_Hashelt	nbuckets;
5822028508SToomas Soome 	Elf_Hashelt	nchains;
5922028508SToomas Soome 	Elf_Hashelt	*buckets;
6022028508SToomas Soome 	Elf_Hashelt	*chains;
6122028508SToomas Soome 	Elf_Rel		*rel;
6222028508SToomas Soome 	size_t		relsz;
6322028508SToomas Soome 	Elf_Rela	*rela;
6422028508SToomas Soome 	size_t		relasz;
6522028508SToomas Soome 	char		*strtab;
6622028508SToomas Soome 	size_t		strsz;
6722028508SToomas Soome 	int		fd;
6822028508SToomas Soome 	caddr_t		firstpage;
6922028508SToomas Soome 	size_t		firstlen;
7022028508SToomas Soome 	int		kernel;
71*de11c9b6SToomas Soome 	uint64_t	off;
7222028508SToomas Soome } *elf_file_t;
7322028508SToomas Soome 
74*de11c9b6SToomas Soome static int __elfN(loadimage)(struct preloaded_file *, elf_file_t, uint64_t);
75*de11c9b6SToomas Soome static int __elfN(lookup_symbol)(struct preloaded_file *, elf_file_t,
76*de11c9b6SToomas Soome     const char *, Elf_Sym *);
77*de11c9b6SToomas Soome static int __elfN(reloc_ptr)(struct preloaded_file *, elf_file_t,
78*de11c9b6SToomas Soome     Elf_Addr, void *, size_t);
79*de11c9b6SToomas Soome static int __elfN(parse_modmetadata)(struct preloaded_file *, elf_file_t,
80*de11c9b6SToomas Soome     Elf_Addr, Elf_Addr);
8122028508SToomas Soome static symaddr_fn __elfN(symaddr);
82*de11c9b6SToomas Soome static char *fake_modname(const char *);
8322028508SToomas Soome 
8422028508SToomas Soome const char	*__elfN(kerneltype) = "elf kernel";
8522028508SToomas Soome const char	*__elfN(moduletype) = "elf module";
8622028508SToomas Soome 
87*de11c9b6SToomas Soome uint64_t	__elfN(relocation_offset) = 0;
8822028508SToomas Soome 
8922028508SToomas Soome static int
__elfN(load_elf_header)9022028508SToomas Soome __elfN(load_elf_header)(char *filename, elf_file_t ef)
9122028508SToomas Soome {
9222028508SToomas Soome 	ssize_t		bytes_read;
9322028508SToomas Soome 	Elf_Ehdr	*ehdr;
9422028508SToomas Soome 	int		err;
9522028508SToomas Soome 
9622028508SToomas Soome 	/*
9722028508SToomas Soome 	 * Open the image, read and validate the ELF header
9822028508SToomas Soome 	 */
9922028508SToomas Soome 	if (filename == NULL)	/* can't handle nameless */
10022028508SToomas Soome 		return (EFTYPE);
10122028508SToomas Soome 	if ((ef->fd = open(filename, O_RDONLY)) == -1)
10222028508SToomas Soome 		return (errno);
10322028508SToomas Soome 	ef->firstpage = malloc(PAGE_SIZE);
10422028508SToomas Soome 	if (ef->firstpage == NULL) {
10522028508SToomas Soome 		close(ef->fd);
10622028508SToomas Soome 		return (ENOMEM);
10722028508SToomas Soome 	}
10822028508SToomas Soome 	bytes_read = read(ef->fd, ef->firstpage, PAGE_SIZE);
10922028508SToomas Soome 	ef->firstlen = (size_t)bytes_read;
11022028508SToomas Soome 	if (bytes_read < 0 || ef->firstlen <= sizeof (Elf_Ehdr)) {
11122028508SToomas Soome 		err = EFTYPE; /* could be EIO, but may be small file */
11222028508SToomas Soome 		goto error;
11322028508SToomas Soome 	}
11422028508SToomas Soome 	ehdr = ef->ehdr = (Elf_Ehdr *)ef->firstpage;
11522028508SToomas Soome 
11622028508SToomas Soome 	/* Is it ELF? */
11722028508SToomas Soome 	if (!IS_ELF(*ehdr)) {
11822028508SToomas Soome 		err = EFTYPE;
11922028508SToomas Soome 		goto error;
12022028508SToomas Soome 	}
12122028508SToomas Soome 	if (ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */
12222028508SToomas Soome 	    ehdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
12322028508SToomas Soome 	    ehdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */
12422028508SToomas Soome 	    ehdr->e_version != EV_CURRENT ||
12522028508SToomas Soome 	    ehdr->e_machine != ELF_TARG_MACH) { /* Machine ? */
12622028508SToomas Soome 		err = EFTYPE;
12722028508SToomas Soome 		goto error;
12822028508SToomas Soome 	}
12922028508SToomas Soome 
13022028508SToomas Soome 	return (0);
13122028508SToomas Soome 
13222028508SToomas Soome error:
13322028508SToomas Soome 	if (ef->firstpage != NULL) {
13422028508SToomas Soome 		free(ef->firstpage);
13522028508SToomas Soome 		ef->firstpage = NULL;
13622028508SToomas Soome 	}
13722028508SToomas Soome 	if (ef->fd != -1) {
13822028508SToomas Soome 		close(ef->fd);
13922028508SToomas Soome 		ef->fd = -1;
14022028508SToomas Soome 	}
14122028508SToomas Soome 	return (err);
14222028508SToomas Soome }
14322028508SToomas Soome 
14422028508SToomas Soome /*
14522028508SToomas Soome  * Attempt to load the file (file) as an ELF module.  It will be stored at
14622028508SToomas Soome  * (dest), and a pointer to a module structure describing the loaded object
14722028508SToomas Soome  * will be saved in (result).
14822028508SToomas Soome  */
14922028508SToomas Soome int
__elfN(loadfile)150*de11c9b6SToomas Soome __elfN(loadfile)(char *filename, uint64_t dest, struct preloaded_file **result)
15122028508SToomas Soome {
15222028508SToomas Soome 	return (__elfN(loadfile_raw)(filename, dest, result, 0));
15322028508SToomas Soome }
15422028508SToomas Soome 
15522028508SToomas Soome int
__elfN(loadfile_raw)156*de11c9b6SToomas Soome __elfN(loadfile_raw)(char *filename, uint64_t dest,
15722028508SToomas Soome     struct preloaded_file **result, int multiboot)
15822028508SToomas Soome {
15922028508SToomas Soome 	struct preloaded_file	*fp, *kfp;
16022028508SToomas Soome 	struct elf_file		ef;
16122028508SToomas Soome 	Elf_Ehdr		*ehdr;
16222028508SToomas Soome 	int			err;
16322028508SToomas Soome 
16422028508SToomas Soome 	fp = NULL;
16522028508SToomas Soome 	bzero(&ef, sizeof (struct elf_file));
16622028508SToomas Soome 	ef.fd = -1;
16722028508SToomas Soome 
16822028508SToomas Soome 	err = __elfN(load_elf_header)(filename, &ef);
16922028508SToomas Soome 	if (err != 0)
17022028508SToomas Soome 		return (err);
17122028508SToomas Soome 
17222028508SToomas Soome 	ehdr = ef.ehdr;
17322028508SToomas Soome 
17422028508SToomas Soome 	/*
17522028508SToomas Soome 	 * Check to see what sort of module we are.
17622028508SToomas Soome 	 */
17722028508SToomas Soome 	kfp = file_findfile(NULL, __elfN(kerneltype));
17822028508SToomas Soome #ifdef __powerpc__
17922028508SToomas Soome 	/*
18022028508SToomas Soome 	 * Kernels can be ET_DYN, so just assume the first loaded object is the
18122028508SToomas Soome 	 * kernel. This assumption will be checked later.
18222028508SToomas Soome 	 */
18322028508SToomas Soome 	if (kfp == NULL)
18422028508SToomas Soome 		ef.kernel = 1;
18522028508SToomas Soome #endif
18622028508SToomas Soome 	if (ef.kernel || ehdr->e_type == ET_EXEC) {
18722028508SToomas Soome 		/* Looks like a kernel */
18822028508SToomas Soome 		if (kfp != NULL) {
189*de11c9b6SToomas Soome 			printf("elf" __XSTRING(__ELF_WORD_SIZE)
190*de11c9b6SToomas Soome 			    "_loadfile: kernel already loaded\n");
19122028508SToomas Soome 			err = EPERM;
19222028508SToomas Soome 			goto oerr;
19322028508SToomas Soome 		}
19422028508SToomas Soome 		/*
19522028508SToomas Soome 		 * Calculate destination address based on kernel entrypoint.
19622028508SToomas Soome 		 *
197*de11c9b6SToomas Soome 		 * For ARM, the destination address is independent of any
198*de11c9b6SToomas Soome 		 * values in the elf header (an ARM kernel can be loaded at
199*de11c9b6SToomas Soome 		 * any 2MB boundary), so we leave dest set to the value
200*de11c9b6SToomas Soome 		 * calculated by archsw.arch_loadaddr() and passed in to
201*de11c9b6SToomas Soome 		 * this function.
20222028508SToomas Soome 		 */
20322028508SToomas Soome #ifndef __arm__
20422028508SToomas Soome 		if (ehdr->e_type == ET_EXEC)
20522028508SToomas Soome 			dest = (ehdr->e_entry & ~PAGE_MASK);
20622028508SToomas Soome #endif
20722028508SToomas Soome 		if ((ehdr->e_entry & ~PAGE_MASK) == 0) {
208*de11c9b6SToomas Soome 			printf("elf" __XSTRING(__ELF_WORD_SIZE)
209*de11c9b6SToomas Soome 			    "_loadfile: not a kernel (maybe static binary?)\n");
21022028508SToomas Soome 			err = EPERM;
21122028508SToomas Soome 			goto oerr;
21222028508SToomas Soome 		}
21322028508SToomas Soome 		ef.kernel = 1;
21422028508SToomas Soome 
21522028508SToomas Soome 	} else if (ehdr->e_type == ET_DYN) {
21622028508SToomas Soome 		/* Looks like a kld module */
21722028508SToomas Soome 		if (multiboot != 0) {
218*de11c9b6SToomas Soome 			printf("elf" __XSTRING(__ELF_WORD_SIZE)
219*de11c9b6SToomas Soome 			    "_loadfile: can't load module as multiboot\n");
22022028508SToomas Soome 			err = EPERM;
22122028508SToomas Soome 			goto oerr;
22222028508SToomas Soome 		}
22322028508SToomas Soome 		if (kfp == NULL) {
224*de11c9b6SToomas Soome 			printf("elf" __XSTRING(__ELF_WORD_SIZE)
225*de11c9b6SToomas Soome 			    "_loadfile: can't load module before kernel\n");
22622028508SToomas Soome 			err = EPERM;
22722028508SToomas Soome 			goto oerr;
22822028508SToomas Soome 		}
22922028508SToomas Soome 		if (strcmp(__elfN(kerneltype), kfp->f_type)) {
230*de11c9b6SToomas Soome 			printf("elf" __XSTRING(__ELF_WORD_SIZE)
231*de11c9b6SToomas Soome 			    "_loadfile: can't load module with "
232*de11c9b6SToomas Soome 			    "kernel type '%s'\n", kfp->f_type);
23322028508SToomas Soome 			err = EPERM;
23422028508SToomas Soome 			goto oerr;
23522028508SToomas Soome 		}
23622028508SToomas Soome 		/* Looks OK, got ahead */
23722028508SToomas Soome 		ef.kernel = 0;
23822028508SToomas Soome 	} else {
23922028508SToomas Soome 		err = EFTYPE;
24022028508SToomas Soome 		goto oerr;
24122028508SToomas Soome 	}
24222028508SToomas Soome 
24322028508SToomas Soome 	if (archsw.arch_loadaddr != NULL)
24422028508SToomas Soome 		dest = archsw.arch_loadaddr(LOAD_ELF, ehdr, dest);
24522028508SToomas Soome 	else
24622028508SToomas Soome 		dest = roundup(dest, PAGE_SIZE);
24722028508SToomas Soome 
24822028508SToomas Soome 	/*
24922028508SToomas Soome 	 * Ok, we think we should handle this.
25022028508SToomas Soome 	 */
25122028508SToomas Soome 	fp = file_alloc();
25222028508SToomas Soome 	if (fp == NULL) {
253*de11c9b6SToomas Soome 		printf("elf" __XSTRING(__ELF_WORD_SIZE)
254*de11c9b6SToomas Soome 		    "_loadfile: cannot allocate module info\n");
25522028508SToomas Soome 		err = EPERM;
25622028508SToomas Soome 		goto out;
25722028508SToomas Soome 	}
25822028508SToomas Soome 	if (ef.kernel == 1 && multiboot == 0)
25922028508SToomas Soome 		setenv("kernelname", filename, 1);
26022028508SToomas Soome 	fp->f_name = strdup(filename);
26122028508SToomas Soome 	if (multiboot == 0) {
26222028508SToomas Soome 		fp->f_type = strdup(ef.kernel ?
26322028508SToomas Soome 		    __elfN(kerneltype) : __elfN(moduletype));
26422028508SToomas Soome 	} else {
26522028508SToomas Soome 		if (multiboot == 1)
26622028508SToomas Soome 			fp->f_type = strdup("elf multiboot kernel");
26722028508SToomas Soome 		else
26822028508SToomas Soome 			fp->f_type = strdup("elf multiboot2 kernel");
26922028508SToomas Soome 	}
27022028508SToomas Soome 
27122028508SToomas Soome #ifdef ELF_VERBOSE
27222028508SToomas Soome 	if (ef.kernel)
273*de11c9b6SToomas Soome 		printf("%s entry at 0x%jx\n", filename,
274*de11c9b6SToomas Soome 		    (uintmax_t)ehdr->e_entry);
27522028508SToomas Soome #else
27622028508SToomas Soome 	printf("%s ", filename);
27722028508SToomas Soome #endif
27822028508SToomas Soome 
27922028508SToomas Soome 	fp->f_size = __elfN(loadimage)(fp, &ef, dest);
28022028508SToomas Soome 	if (fp->f_size == 0 || fp->f_addr == 0)
28122028508SToomas Soome 		goto ioerr;
28222028508SToomas Soome 
28322028508SToomas Soome 	/* save exec header as metadata */
28422028508SToomas Soome 	file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof (*ehdr), ehdr);
28522028508SToomas Soome 
28622028508SToomas Soome 	/* Load OK, return module pointer */
28722028508SToomas Soome 	*result = (struct preloaded_file *)fp;
28822028508SToomas Soome 	err = 0;
28922028508SToomas Soome 	goto out;
29022028508SToomas Soome 
29122028508SToomas Soome ioerr:
29222028508SToomas Soome 	err = EIO;
29322028508SToomas Soome oerr:
29422028508SToomas Soome 	file_discard(fp);
29522028508SToomas Soome out:
29622028508SToomas Soome 	if (ef.firstpage)
29722028508SToomas Soome 		free(ef.firstpage);
29822028508SToomas Soome 	if (ef.fd != -1)
29922028508SToomas Soome 		close(ef.fd);
30022028508SToomas Soome 	return (err);
30122028508SToomas Soome }
30222028508SToomas Soome 
30322028508SToomas Soome /*
30422028508SToomas Soome  * With the file (fd) open on the image, and (ehdr) containing
30522028508SToomas Soome  * the Elf header, load the image at (off)
30622028508SToomas Soome  */
30722028508SToomas Soome static int
__elfN(loadimage)308*de11c9b6SToomas Soome __elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, uint64_t off)
30922028508SToomas Soome {
31022028508SToomas Soome 	int		i;
311*de11c9b6SToomas Soome 	uint_t		j;
31222028508SToomas Soome 	Elf_Ehdr	*ehdr;
31322028508SToomas Soome 	Elf_Phdr	*phdr, *php;
31422028508SToomas Soome 	Elf_Shdr	*shdr;
31522028508SToomas Soome 	char		*shstr;
31622028508SToomas Soome 	int		ret;
31722028508SToomas Soome 	vm_offset_t	 firstaddr;
31822028508SToomas Soome 	vm_offset_t	 lastaddr;
31922028508SToomas Soome 	size_t		chunk;
32022028508SToomas Soome 	ssize_t		result;
32122028508SToomas Soome 	Elf_Addr	ssym, esym;
32222028508SToomas Soome 	Elf_Dyn		*dp;
32322028508SToomas Soome 	Elf_Addr	adp;
32422028508SToomas Soome 	Elf_Addr	ctors;
32522028508SToomas Soome 	int		ndp;
32622028508SToomas Soome 	int		symstrindex;
32722028508SToomas Soome 	int		symtabindex;
32822028508SToomas Soome 	Elf_Size	size;
329*de11c9b6SToomas Soome 	uint_t		fpcopy;
33022028508SToomas Soome 	Elf_Sym		sym;
33122028508SToomas Soome 	Elf_Addr	p_start, p_end;
33222028508SToomas Soome 
33322028508SToomas Soome 	dp = NULL;
33422028508SToomas Soome 	shdr = NULL;
33522028508SToomas Soome 	ret = 0;
33622028508SToomas Soome 	firstaddr = lastaddr = 0;
33722028508SToomas Soome 	ehdr = ef->ehdr;
33822028508SToomas Soome 	if (ehdr->e_type == ET_EXEC) {
33922028508SToomas Soome #if defined(__i386__) || defined(__amd64__)
34022028508SToomas Soome #if __ELF_WORD_SIZE == 64
341*de11c9b6SToomas Soome 		/* x86_64 relocates after locore */
342*de11c9b6SToomas Soome 		off = - (off & 0xffffffffff000000ull);
34322028508SToomas Soome #else
344*de11c9b6SToomas Soome 		/* i386 relocates after locore */
345*de11c9b6SToomas Soome 		off = - (off & 0xff000000u);
34622028508SToomas Soome #endif
34722028508SToomas Soome #elif defined(__powerpc__)
34822028508SToomas Soome 		/*
349*de11c9b6SToomas Soome 		 * On the purely virtual memory machines like e500, the kernel
350*de11c9b6SToomas Soome 		 * is linked against its final VA range, which is most often
351*de11c9b6SToomas Soome 		 * not available at the loader stage, but only after kernel
352*de11c9b6SToomas Soome 		 * initializes and completes its VM settings. In such cases
353*de11c9b6SToomas Soome 		 * we cannot use p_vaddr field directly to load ELF segments,
354*de11c9b6SToomas Soome 		 * but put them at some 'load-time' locations.
35522028508SToomas Soome 		 */
35622028508SToomas Soome 		if (off & 0xf0000000u) {
35722028508SToomas Soome 			off = -(off & 0xf0000000u);
35822028508SToomas Soome 			/*
359*de11c9b6SToomas Soome 			 * XXX the physical load address should not be
360*de11c9b6SToomas Soome 			 * hardcoded. Note that the Book-E kernel assumes
361*de11c9b6SToomas Soome 			 * that it's loaded at a 16MB boundary for now...
36222028508SToomas Soome 			 */
36322028508SToomas Soome 			off += 0x01000000;
36422028508SToomas Soome 			ehdr->e_entry += off;
36522028508SToomas Soome #ifdef ELF_VERBOSE
36622028508SToomas Soome 			printf("Converted entry 0x%08x\n", ehdr->e_entry);
36722028508SToomas Soome #endif
368*de11c9b6SToomas Soome 		} else {
36922028508SToomas Soome 			off = 0;
370*de11c9b6SToomas Soome 		}
37122028508SToomas Soome #elif defined(__arm__) && !defined(EFI)
37222028508SToomas Soome 		/*
373*de11c9b6SToomas Soome 		 * The elf headers in arm kernels specify virtual addresses
374*de11c9b6SToomas Soome 		 * in all header fields, even the ones that should be physical
375*de11c9b6SToomas Soome 		 * addresses.
376*de11c9b6SToomas Soome 		 * We assume the entry point is in the first page, and masking
377*de11c9b6SToomas Soome 		 * the page offset will leave us with the virtual address the
378*de11c9b6SToomas Soome 		 * kernel was linked at. We subtract that from the load offset,
379*de11c9b6SToomas Soome 		 * making 'off' into the value which, when added to a virtual
380*de11c9b6SToomas Soome 		 * address in an elf header, translates it to a physical
381*de11c9b6SToomas Soome 		 * address. We do the va->pa conversion on the entry point
382*de11c9b6SToomas Soome 		 * address in the header now, so that later we can
38322028508SToomas Soome 		 * launch the kernel by just jumping to that address.
38422028508SToomas Soome 		 *
385*de11c9b6SToomas Soome 		 * When booting from UEFI the copyin and copyout functions
386*de11c9b6SToomas Soome 		 * handle adjusting the location relative to the first virtual
387*de11c9b6SToomas Soome 		 * address. Because of this there is no need to adjust the
388*de11c9b6SToomas Soome 		 * offset or entry point address as these will both be handled
389*de11c9b6SToomas Soome 		 * by the efi code.
39022028508SToomas Soome 		 */
39122028508SToomas Soome 		off -= ehdr->e_entry & ~PAGE_MASK;
39222028508SToomas Soome 		ehdr->e_entry += off;
39322028508SToomas Soome #ifdef ELF_VERBOSE
394*de11c9b6SToomas Soome 		printf("ehdr->e_entry 0x%08x, va<->pa off %llx\n",
395*de11c9b6SToomas Soome 		    ehdr->e_entry, off);
39622028508SToomas Soome #endif
39722028508SToomas Soome #else
39822028508SToomas Soome 		off = 0;	/* other archs use direct mapped kernels */
39922028508SToomas Soome #endif
40022028508SToomas Soome 	}
40122028508SToomas Soome 	ef->off = off;
40222028508SToomas Soome 
40322028508SToomas Soome 	if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) {
40422028508SToomas Soome 		/* use entry address from header */
40522028508SToomas Soome 		fp->f_addr = ehdr->e_entry;
40622028508SToomas Soome 	}
40722028508SToomas Soome 
40822028508SToomas Soome 	if (ef->kernel)
40922028508SToomas Soome 		__elfN(relocation_offset) = off;
41022028508SToomas Soome 
41122028508SToomas Soome 	if ((ehdr->e_phoff + ehdr->e_phnum * sizeof (*phdr)) > ef->firstlen) {
412*de11c9b6SToomas Soome 		printf("elf" __XSTRING(__ELF_WORD_SIZE)
413*de11c9b6SToomas Soome 		    "_loadimage: program header not within first page\n");
41422028508SToomas Soome 		goto out;
41522028508SToomas Soome 	}
41622028508SToomas Soome 	phdr = (Elf_Phdr *)(ef->firstpage + ehdr->e_phoff);
41722028508SToomas Soome 
41822028508SToomas Soome 	for (i = 0; i < ehdr->e_phnum; i++) {
41922028508SToomas Soome 		/* We want to load PT_LOAD segments only.. */
42022028508SToomas Soome 		if (phdr[i].p_type != PT_LOAD)
42122028508SToomas Soome 			continue;
42222028508SToomas Soome 
42322028508SToomas Soome #ifdef ELF_VERBOSE
42422028508SToomas Soome 		if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) {
42522028508SToomas Soome 			printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx",
42622028508SToomas Soome 			    (long)phdr[i].p_filesz, (long)phdr[i].p_offset,
42722028508SToomas Soome 			    (long)(phdr[i].p_paddr + off),
428*de11c9b6SToomas Soome 			    (long)(phdr[i].p_paddr + off +
429*de11c9b6SToomas Soome 			    phdr[i].p_memsz - 1));
43022028508SToomas Soome 		} else {
43122028508SToomas Soome 			printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx",
43222028508SToomas Soome 			    (long)phdr[i].p_filesz, (long)phdr[i].p_offset,
43322028508SToomas Soome 			    (long)(phdr[i].p_vaddr + off),
434*de11c9b6SToomas Soome 			    (long)(phdr[i].p_vaddr + off +
435*de11c9b6SToomas Soome 			    phdr[i].p_memsz - 1));
43622028508SToomas Soome 		}
43722028508SToomas Soome #else
43822028508SToomas Soome 		if ((phdr[i].p_flags & PF_W) == 0) {
43922028508SToomas Soome 			printf("text=0x%lx ", (long)phdr[i].p_filesz);
44022028508SToomas Soome 		} else {
44122028508SToomas Soome 			printf("data=0x%lx", (long)phdr[i].p_filesz);
44222028508SToomas Soome 			if (phdr[i].p_filesz < phdr[i].p_memsz)
443*de11c9b6SToomas Soome 				printf("+0x%lx",
444*de11c9b6SToomas Soome 				    (long)(phdr[i].p_memsz -phdr[i].p_filesz));
44522028508SToomas Soome 			printf(" ");
44622028508SToomas Soome 		}
44722028508SToomas Soome #endif
44822028508SToomas Soome 		fpcopy = 0;
44922028508SToomas Soome 		if (ef->firstlen > phdr[i].p_offset) {
45022028508SToomas Soome 			fpcopy = ef->firstlen - phdr[i].p_offset;
45122028508SToomas Soome 			if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) {
452*de11c9b6SToomas Soome 				archsw.arch_copyin(ef->firstpage +
453*de11c9b6SToomas Soome 				    phdr[i].p_offset,
45422028508SToomas Soome 				    phdr[i].p_paddr + off, fpcopy);
45522028508SToomas Soome 			} else {
456*de11c9b6SToomas Soome 				archsw.arch_copyin(ef->firstpage +
457*de11c9b6SToomas Soome 				    phdr[i].p_offset,
45822028508SToomas Soome 				    phdr[i].p_vaddr + off, fpcopy);
45922028508SToomas Soome 			}
46022028508SToomas Soome 		}
46122028508SToomas Soome 		if (phdr[i].p_filesz > fpcopy) {
46222028508SToomas Soome 			if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) {
463*de11c9b6SToomas Soome 				if (kern_pread(ef->fd,
464*de11c9b6SToomas Soome 				    phdr[i].p_paddr + off + fpcopy,
46522028508SToomas Soome 				    phdr[i].p_filesz - fpcopy,
46622028508SToomas Soome 				    phdr[i].p_offset + fpcopy) != 0) {
467*de11c9b6SToomas Soome 					printf("\nelf"
468*de11c9b6SToomas Soome 					    __XSTRING(__ELF_WORD_SIZE)
46922028508SToomas Soome 					    "_loadimage: read failed\n");
47022028508SToomas Soome 					goto out;
47122028508SToomas Soome 				}
47222028508SToomas Soome 			} else {
473*de11c9b6SToomas Soome 				if (kern_pread(ef->fd,
474*de11c9b6SToomas Soome 				    phdr[i].p_vaddr + off + fpcopy,
47522028508SToomas Soome 				    phdr[i].p_filesz - fpcopy,
47622028508SToomas Soome 				    phdr[i].p_offset + fpcopy) != 0) {
477*de11c9b6SToomas Soome 					printf("\nelf"
478*de11c9b6SToomas Soome 					    __XSTRING(__ELF_WORD_SIZE)
47922028508SToomas Soome 					    "_loadimage: read failed\n");
48022028508SToomas Soome 					goto out;
48122028508SToomas Soome 				}
48222028508SToomas Soome 			}
48322028508SToomas Soome 		}
48422028508SToomas Soome 		/* clear space from oversized segments; eg: bss */
48522028508SToomas Soome 		if (phdr[i].p_filesz < phdr[i].p_memsz) {
48622028508SToomas Soome #ifdef ELF_VERBOSE
48722028508SToomas Soome 			if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) {
48822028508SToomas Soome 				printf(" (bss: 0x%lx-0x%lx)",
489*de11c9b6SToomas Soome 				    (long)(phdr[i].p_paddr + off +
490*de11c9b6SToomas Soome 				    phdr[i].p_filesz),
491*de11c9b6SToomas Soome 				    (long)(phdr[i].p_paddr + off +
492*de11c9b6SToomas Soome 				    phdr[i].p_memsz - 1));
49322028508SToomas Soome 			} else {
49422028508SToomas Soome 				printf(" (bss: 0x%lx-0x%lx)",
495*de11c9b6SToomas Soome 				    (long)(phdr[i].p_vaddr + off +
496*de11c9b6SToomas Soome 				    phdr[i].p_filesz),
497*de11c9b6SToomas Soome 				    (long)(phdr[i].p_vaddr + off +
498*de11c9b6SToomas Soome 				    phdr[i].p_memsz - 1));
49922028508SToomas Soome 			}
50022028508SToomas Soome #endif
50122028508SToomas Soome 
50222028508SToomas Soome 			if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) {
503*de11c9b6SToomas Soome 				kern_bzero(phdr[i].p_paddr + off +
504*de11c9b6SToomas Soome 				    phdr[i].p_filesz,
50522028508SToomas Soome 				    phdr[i].p_memsz - phdr[i].p_filesz);
50622028508SToomas Soome 			} else {
507*de11c9b6SToomas Soome 				kern_bzero(phdr[i].p_vaddr + off +
508*de11c9b6SToomas Soome 				    phdr[i].p_filesz,
50922028508SToomas Soome 				    phdr[i].p_memsz - phdr[i].p_filesz);
51022028508SToomas Soome 			}
51122028508SToomas Soome 		}
51222028508SToomas Soome #ifdef ELF_VERBOSE
51322028508SToomas Soome 		printf("\n");
51422028508SToomas Soome #endif
51522028508SToomas Soome 
51622028508SToomas Soome 		if (archsw.arch_loadseg != NULL)
51722028508SToomas Soome 			archsw.arch_loadseg(ehdr, phdr + i, off);
51822028508SToomas Soome 
51922028508SToomas Soome 		if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) {
520*de11c9b6SToomas Soome 			if (firstaddr == 0 ||
521*de11c9b6SToomas Soome 			    firstaddr > (phdr[i].p_paddr + off))
52222028508SToomas Soome 				firstaddr = phdr[i].p_paddr + off;
523*de11c9b6SToomas Soome 			if (lastaddr == 0 || lastaddr <
524*de11c9b6SToomas Soome 			    (phdr[i].p_paddr + off + phdr[i].p_memsz))
525*de11c9b6SToomas Soome 				lastaddr = phdr[i].p_paddr + off +
526*de11c9b6SToomas Soome 				    phdr[i].p_memsz;
52722028508SToomas Soome 		} else {
528*de11c9b6SToomas Soome 			if (firstaddr == 0 ||
529*de11c9b6SToomas Soome 			    firstaddr > (phdr[i].p_vaddr + off))
53022028508SToomas Soome 				firstaddr = phdr[i].p_vaddr + off;
531*de11c9b6SToomas Soome 			if (lastaddr == 0 || lastaddr <
532*de11c9b6SToomas Soome 			    (phdr[i].p_vaddr + off + phdr[i].p_memsz))
533*de11c9b6SToomas Soome 				lastaddr = phdr[i].p_vaddr + off +
534*de11c9b6SToomas Soome 				    phdr[i].p_memsz;
53522028508SToomas Soome 		}
53622028508SToomas Soome 	}
53722028508SToomas Soome 	lastaddr = roundup(lastaddr, sizeof (long));
53822028508SToomas Soome 
53922028508SToomas Soome 	/*
54022028508SToomas Soome 	 * Get the section headers.  We need this for finding the .ctors
54122028508SToomas Soome 	 * section as well as for loading any symbols.  Both may be hard
54222028508SToomas Soome 	 * to do if reading from a .gz file as it involves seeking.  I
54322028508SToomas Soome 	 * think the rule is going to have to be that you must strip a
54422028508SToomas Soome 	 * file to remove symbols before gzipping it.
54522028508SToomas Soome 	 */
54622028508SToomas Soome 	chunk = ehdr->e_shnum * ehdr->e_shentsize;
54722028508SToomas Soome 	if (chunk == 0 || ehdr->e_shoff == 0)
54822028508SToomas Soome 		goto nosyms;
54922028508SToomas Soome 	shdr = alloc_pread(ef->fd, ehdr->e_shoff, chunk);
55022028508SToomas Soome 	if (shdr == NULL) {
55122028508SToomas Soome 		printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
55222028508SToomas Soome 		    "_loadimage: failed to read section headers");
55322028508SToomas Soome 		goto nosyms;
55422028508SToomas Soome 	}
55522028508SToomas Soome 	file_addmetadata(fp, MODINFOMD_SHDR, chunk, shdr);
55622028508SToomas Soome 
55722028508SToomas Soome 	/*
55822028508SToomas Soome 	 * Read the section string table and look for the .ctors section.
55922028508SToomas Soome 	 * We need to tell the kernel where it is so that it can call the
56022028508SToomas Soome 	 * ctors.
56122028508SToomas Soome 	 */
56222028508SToomas Soome 	chunk = shdr[ehdr->e_shstrndx].sh_size;
56322028508SToomas Soome 	if (chunk) {
564*de11c9b6SToomas Soome 		shstr = alloc_pread(ef->fd, shdr[ehdr->e_shstrndx].sh_offset,
565*de11c9b6SToomas Soome 		    chunk);
56622028508SToomas Soome 		if (shstr) {
56722028508SToomas Soome 			for (i = 0; i < ehdr->e_shnum; i++) {
568*de11c9b6SToomas Soome 				if (strcmp(shstr + shdr[i].sh_name,
569*de11c9b6SToomas Soome 				    ".ctors") != 0)
57022028508SToomas Soome 					continue;
57122028508SToomas Soome 				ctors = shdr[i].sh_addr;
572*de11c9b6SToomas Soome 				file_addmetadata(fp, MODINFOMD_CTORS_ADDR,
573*de11c9b6SToomas Soome 				    sizeof (ctors), &ctors);
57422028508SToomas Soome 				size = shdr[i].sh_size;
575*de11c9b6SToomas Soome 				file_addmetadata(fp, MODINFOMD_CTORS_SIZE,
576*de11c9b6SToomas Soome 				    sizeof (size), &size);
57722028508SToomas Soome 				break;
57822028508SToomas Soome 			}
57922028508SToomas Soome 			free(shstr);
58022028508SToomas Soome 		}
58122028508SToomas Soome 	}
58222028508SToomas Soome 
58322028508SToomas Soome 	/*
58422028508SToomas Soome 	 * Now load any symbols.
58522028508SToomas Soome 	 */
58622028508SToomas Soome 	symtabindex = -1;
58722028508SToomas Soome 	symstrindex = -1;
58822028508SToomas Soome 	for (i = 0; i < ehdr->e_shnum; i++) {
58922028508SToomas Soome 		if (shdr[i].sh_type != SHT_SYMTAB)
59022028508SToomas Soome 			continue;
59122028508SToomas Soome 		for (j = 0; j < ehdr->e_phnum; j++) {
59222028508SToomas Soome 			if (phdr[j].p_type != PT_LOAD)
59322028508SToomas Soome 				continue;
59422028508SToomas Soome 			if (shdr[i].sh_offset >= phdr[j].p_offset &&
59522028508SToomas Soome 			    (shdr[i].sh_offset + shdr[i].sh_size <=
59622028508SToomas Soome 			    phdr[j].p_offset + phdr[j].p_filesz)) {
59722028508SToomas Soome 				shdr[i].sh_offset = 0;
59822028508SToomas Soome 				shdr[i].sh_size = 0;
59922028508SToomas Soome 				break;
60022028508SToomas Soome 			}
60122028508SToomas Soome 		}
60222028508SToomas Soome 		if (shdr[i].sh_offset == 0 || shdr[i].sh_size == 0)
60322028508SToomas Soome 			continue;	/* alread loaded in a PT_LOAD above */
60422028508SToomas Soome 		/* Save it for loading below */
60522028508SToomas Soome 		symtabindex = i;
60622028508SToomas Soome 		symstrindex = shdr[i].sh_link;
60722028508SToomas Soome 	}
60822028508SToomas Soome 	if (symtabindex < 0 || symstrindex < 0)
60922028508SToomas Soome 		goto nosyms;
61022028508SToomas Soome 
61122028508SToomas Soome 	/* Ok, committed to a load. */
61222028508SToomas Soome #ifndef ELF_VERBOSE
61322028508SToomas Soome 	printf("syms=[");
61422028508SToomas Soome #endif
61522028508SToomas Soome 	ssym = lastaddr;
61622028508SToomas Soome 	for (i = symtabindex; i >= 0; i = symstrindex) {
61722028508SToomas Soome #ifdef ELF_VERBOSE
61822028508SToomas Soome 		char	*secname;
61922028508SToomas Soome 
62022028508SToomas Soome 		switch (shdr[i].sh_type) {
62122028508SToomas Soome 		case SHT_SYMTAB:		/* Symbol table */
62222028508SToomas Soome 			secname = "symtab";
62322028508SToomas Soome 			break;
62422028508SToomas Soome 		case SHT_STRTAB:		/* String table */
62522028508SToomas Soome 			secname = "strtab";
62622028508SToomas Soome 			break;
62722028508SToomas Soome 		default:
62822028508SToomas Soome 			secname = "WHOA!!";
62922028508SToomas Soome 			break;
63022028508SToomas Soome 		}
63122028508SToomas Soome #endif
63222028508SToomas Soome 
63322028508SToomas Soome 		size = shdr[i].sh_size;
63422028508SToomas Soome 		archsw.arch_copyin(&size, lastaddr, sizeof (size));
63522028508SToomas Soome 		lastaddr += sizeof (size);
63622028508SToomas Soome 
63722028508SToomas Soome #ifdef ELF_VERBOSE
63822028508SToomas Soome 		printf("\n%s: 0x%jx@0x%jx -> 0x%jx-0x%jx", secname,
63922028508SToomas Soome 		    (uintmax_t)shdr[i].sh_size, (uintmax_t)shdr[i].sh_offset,
640*de11c9b6SToomas Soome 		    (uintmax_t)lastaddr,
641*de11c9b6SToomas Soome 		    (uintmax_t)(lastaddr + shdr[i].sh_size));
64222028508SToomas Soome #else
64322028508SToomas Soome 		if (i == symstrindex)
64422028508SToomas Soome 			printf("+");
64522028508SToomas Soome 		printf("0x%lx+0x%lx", (long)sizeof (size), (long)size);
64622028508SToomas Soome #endif
64722028508SToomas Soome 
64822028508SToomas Soome 		if (lseek(ef->fd, (off_t)shdr[i].sh_offset, SEEK_SET) == -1) {
649*de11c9b6SToomas Soome 			printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage:"
650*de11c9b6SToomas Soome 			    " could not seek for symbols - skipped!");
65122028508SToomas Soome 			lastaddr = ssym;
65222028508SToomas Soome 			ssym = 0;
65322028508SToomas Soome 			goto nosyms;
65422028508SToomas Soome 		}
65522028508SToomas Soome 		result = archsw.arch_readin(ef->fd, lastaddr, shdr[i].sh_size);
65622028508SToomas Soome 		if (result < 0 || (size_t)result != shdr[i].sh_size) {
657*de11c9b6SToomas Soome 			printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: "
658*de11c9b6SToomas Soome 			    "could not read symbols - skipped! (%ju != %ju)",
659*de11c9b6SToomas Soome 			    (uintmax_t)result, (uintmax_t)shdr[i].sh_size);
66022028508SToomas Soome 			lastaddr = ssym;
66122028508SToomas Soome 			ssym = 0;
66222028508SToomas Soome 			goto nosyms;
66322028508SToomas Soome 		}
66422028508SToomas Soome 		/* Reset offsets relative to ssym */
66522028508SToomas Soome 		lastaddr += shdr[i].sh_size;
66622028508SToomas Soome 		lastaddr = roundup(lastaddr, sizeof (size));
66722028508SToomas Soome 		if (i == symtabindex)
66822028508SToomas Soome 			symtabindex = -1;
66922028508SToomas Soome 		else if (i == symstrindex)
67022028508SToomas Soome 			symstrindex = -1;
67122028508SToomas Soome 	}
67222028508SToomas Soome 	esym = lastaddr;
67322028508SToomas Soome #ifndef ELF_VERBOSE
67422028508SToomas Soome 	printf("]");
67522028508SToomas Soome #endif
67622028508SToomas Soome 
67722028508SToomas Soome 	file_addmetadata(fp, MODINFOMD_SSYM, sizeof (ssym), &ssym);
67822028508SToomas Soome 	file_addmetadata(fp, MODINFOMD_ESYM, sizeof (esym), &esym);
67922028508SToomas Soome 
68022028508SToomas Soome nosyms:
68122028508SToomas Soome 	printf("\n");
68222028508SToomas Soome 
68322028508SToomas Soome 	ret = lastaddr - firstaddr;
68422028508SToomas Soome 	if (ehdr->e_ident[EI_OSABI] != ELFOSABI_SOLARIS)
68522028508SToomas Soome 		fp->f_addr = firstaddr;
68622028508SToomas Soome 
68722028508SToomas Soome 	php = NULL;
68822028508SToomas Soome 	for (i = 0; i < ehdr->e_phnum; i++) {
68922028508SToomas Soome 		if (phdr[i].p_type == PT_DYNAMIC) {
69022028508SToomas Soome 			php = phdr + i;
69122028508SToomas Soome 			adp = php->p_vaddr;
692*de11c9b6SToomas Soome 			file_addmetadata(fp, MODINFOMD_DYNAMIC,
693*de11c9b6SToomas Soome 			    sizeof (adp), &adp);
69422028508SToomas Soome 			break;
69522028508SToomas Soome 		}
69622028508SToomas Soome 	}
69722028508SToomas Soome 
69822028508SToomas Soome 	if (php == NULL) /* this is bad, we cannot get to symbols or _DYNAMIC */
69922028508SToomas Soome 		goto out;
70022028508SToomas Soome 
70122028508SToomas Soome 	ndp = php->p_filesz / sizeof (Elf_Dyn);
70222028508SToomas Soome 	if (ndp == 0)
70322028508SToomas Soome 		goto out;
70422028508SToomas Soome 	dp = malloc(php->p_filesz);
70522028508SToomas Soome 	if (dp == NULL)
70622028508SToomas Soome 		goto out;
70722028508SToomas Soome 	if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS)
70822028508SToomas Soome 		archsw.arch_copyout(php->p_paddr + off, dp, php->p_filesz);
70922028508SToomas Soome 	else
71022028508SToomas Soome 		archsw.arch_copyout(php->p_vaddr + off, dp, php->p_filesz);
71122028508SToomas Soome 
71222028508SToomas Soome 	ef->strsz = 0;
71322028508SToomas Soome 	for (i = 0; i < ndp; i++) {
71422028508SToomas Soome 		if (dp[i].d_tag == 0)
71522028508SToomas Soome 			break;
71622028508SToomas Soome 		switch (dp[i].d_tag) {
71722028508SToomas Soome 		case DT_HASH:
718*de11c9b6SToomas Soome 			ef->hashtab = (Elf_Hashelt*)(uintptr_t)
719*de11c9b6SToomas Soome 			    (dp[i].d_un.d_ptr + off);
72022028508SToomas Soome 		break;
72122028508SToomas Soome 		case DT_STRTAB:
722*de11c9b6SToomas Soome 			ef->strtab = (char *)(uintptr_t)
723*de11c9b6SToomas Soome 			    (dp[i].d_un.d_ptr + off);
72422028508SToomas Soome 			break;
72522028508SToomas Soome 		case DT_STRSZ:
72622028508SToomas Soome 			ef->strsz = dp[i].d_un.d_val;
72722028508SToomas Soome 			break;
72822028508SToomas Soome 		case DT_SYMTAB:
729*de11c9b6SToomas Soome 			ef->symtab = (Elf_Sym*)(uintptr_t)
730*de11c9b6SToomas Soome 			    (dp[i].d_un.d_ptr + off);
73122028508SToomas Soome 			break;
73222028508SToomas Soome 		case DT_REL:
733*de11c9b6SToomas Soome 			ef->rel = (Elf_Rel *)(uintptr_t)
734*de11c9b6SToomas Soome 			    (dp[i].d_un.d_ptr + off);
73522028508SToomas Soome 			break;
73622028508SToomas Soome 		case DT_RELSZ:
73722028508SToomas Soome 			ef->relsz = dp[i].d_un.d_val;
73822028508SToomas Soome 			break;
73922028508SToomas Soome 		case DT_RELA:
740*de11c9b6SToomas Soome 			ef->rela = (Elf_Rela *)(uintptr_t)
741*de11c9b6SToomas Soome 			    (dp[i].d_un.d_ptr + off);
74222028508SToomas Soome 			break;
74322028508SToomas Soome 		case DT_RELASZ:
74422028508SToomas Soome 			ef->relasz = dp[i].d_un.d_val;
74522028508SToomas Soome 			break;
74622028508SToomas Soome 		default:
74722028508SToomas Soome 			break;
74822028508SToomas Soome 		}
74922028508SToomas Soome 	}
75022028508SToomas Soome 	if (ef->hashtab == NULL || ef->symtab == NULL ||
75122028508SToomas Soome 	    ef->strtab == NULL || ef->strsz == 0)
75222028508SToomas Soome 		goto out;
75322028508SToomas Soome 	COPYOUT(ef->hashtab, &ef->nbuckets, sizeof (ef->nbuckets));
75422028508SToomas Soome 	COPYOUT(ef->hashtab + 1, &ef->nchains, sizeof (ef->nchains));
75522028508SToomas Soome 	ef->buckets = ef->hashtab + 2;
75622028508SToomas Soome 	ef->chains = ef->buckets + ef->nbuckets;
75722028508SToomas Soome 
758*de11c9b6SToomas Soome 	if (__elfN(lookup_symbol)(fp, ef, "__start_set_modmetadata_set",
759*de11c9b6SToomas Soome 	    &sym) != 0)
760*de11c9b6SToomas Soome 		return (0);
76122028508SToomas Soome 	p_start = sym.st_value + ef->off;
762*de11c9b6SToomas Soome 	if (__elfN(lookup_symbol)(fp, ef, "__stop_set_modmetadata_set",
763*de11c9b6SToomas Soome 	    &sym) != 0)
764*de11c9b6SToomas Soome 		return (ENOENT);
76522028508SToomas Soome 	p_end = sym.st_value + ef->off;
76622028508SToomas Soome 
76722028508SToomas Soome 	if (__elfN(parse_modmetadata)(fp, ef, p_start, p_end) == 0)
76822028508SToomas Soome 		goto out;
76922028508SToomas Soome 
77022028508SToomas Soome 	if (ef->kernel)			/* kernel must not depend on anything */
77122028508SToomas Soome 		goto out;
77222028508SToomas Soome 
77322028508SToomas Soome out:
77422028508SToomas Soome 	free(dp);
77522028508SToomas Soome 	free(shdr);
776*de11c9b6SToomas Soome 	return (ret);
77722028508SToomas Soome }
77822028508SToomas Soome 
77922028508SToomas Soome static char invalid_name[] = "bad";
78022028508SToomas Soome 
78122028508SToomas Soome char *
fake_modname(const char * name)78222028508SToomas Soome fake_modname(const char *name)
78322028508SToomas Soome {
78422028508SToomas Soome 	const char *sp, *ep;
78522028508SToomas Soome 	char *fp;
78622028508SToomas Soome 	size_t len;
78722028508SToomas Soome 
78822028508SToomas Soome 	sp = strrchr(name, '/');
78922028508SToomas Soome 	if (sp)
79022028508SToomas Soome 		sp++;
79122028508SToomas Soome 	else
79222028508SToomas Soome 		sp = name;
79322028508SToomas Soome 	ep = strrchr(name, '.');
79422028508SToomas Soome 	if (ep) {
79522028508SToomas Soome 		if (ep == name) {
79622028508SToomas Soome 			sp = invalid_name;
79722028508SToomas Soome 			ep = invalid_name + sizeof (invalid_name) - 1;
79822028508SToomas Soome 		}
799*de11c9b6SToomas Soome 	} else {
80022028508SToomas Soome 		ep = name + strlen(name);
801*de11c9b6SToomas Soome 	}
80222028508SToomas Soome 	len = ep - sp;
80322028508SToomas Soome 	fp = malloc(len + 1);
80422028508SToomas Soome 	if (fp == NULL)
805*de11c9b6SToomas Soome 		return (NULL);
80622028508SToomas Soome 	memcpy(fp, sp, len);
80722028508SToomas Soome 	fp[len] = '\0';
808*de11c9b6SToomas Soome 	return (fp);
80922028508SToomas Soome }
81022028508SToomas Soome 
81122028508SToomas Soome #if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64
81222028508SToomas Soome struct mod_metadata64 {
81322028508SToomas Soome 	int		md_version;	/* structure version MDTV_* */
81422028508SToomas Soome 	int		md_type;	/* type of entry MDT_* */
815*de11c9b6SToomas Soome 	uint64_t	md_data;	/* specific data */
816*de11c9b6SToomas Soome 	uint64_t	md_cval;	/* common string label */
81722028508SToomas Soome };
81822028508SToomas Soome #endif
81922028508SToomas Soome #if defined(__amd64__) && __ELF_WORD_SIZE == 32
82022028508SToomas Soome struct mod_metadata32 {
82122028508SToomas Soome 	int		md_version;	/* structure version MDTV_* */
82222028508SToomas Soome 	int		md_type;	/* type of entry MDT_* */
823*de11c9b6SToomas Soome 	uint32_t	md_data;	/* specific data */
824*de11c9b6SToomas Soome 	uint32_t	md_cval;	/* common string label */
82522028508SToomas Soome };
82622028508SToomas Soome #endif
82722028508SToomas Soome 
82822028508SToomas Soome int
__elfN(load_modmetadata)829*de11c9b6SToomas Soome __elfN(load_modmetadata)(struct preloaded_file *fp, uint64_t dest)
83022028508SToomas Soome {
83122028508SToomas Soome 	struct elf_file		 ef;
83222028508SToomas Soome 	int			 err, i, j;
83322028508SToomas Soome 	Elf_Shdr		*sh_meta, *shdr = NULL;
83422028508SToomas Soome 	Elf_Shdr		*sh_data[2];
83522028508SToomas Soome 	char			*shstrtab = NULL;
83622028508SToomas Soome 	size_t			 size;
83722028508SToomas Soome 	Elf_Addr		 p_start, p_end;
83822028508SToomas Soome 
83922028508SToomas Soome 	bzero(&ef, sizeof (struct elf_file));
84022028508SToomas Soome 	ef.fd = -1;
84122028508SToomas Soome 
84222028508SToomas Soome 	err = __elfN(load_elf_header)(fp->f_name, &ef);
84322028508SToomas Soome 	if (err != 0)
84422028508SToomas Soome 		goto out;
84522028508SToomas Soome 
84622028508SToomas Soome 	if (ef.kernel == 1 || ef.ehdr->e_type == ET_EXEC) {
84722028508SToomas Soome 		ef.kernel = 1;
84822028508SToomas Soome 	} else if (ef.ehdr->e_type != ET_DYN) {
84922028508SToomas Soome 		err = EFTYPE;
85022028508SToomas Soome 		goto out;
85122028508SToomas Soome 	}
85222028508SToomas Soome 
85322028508SToomas Soome 	size = ef.ehdr->e_shnum * ef.ehdr->e_shentsize;
85422028508SToomas Soome 	shdr = alloc_pread(ef.fd, ef.ehdr->e_shoff, size);
85522028508SToomas Soome 	if (shdr == NULL) {
85622028508SToomas Soome 		err = ENOMEM;
85722028508SToomas Soome 		goto out;
85822028508SToomas Soome 	}
85922028508SToomas Soome 
86022028508SToomas Soome 	/* Load shstrtab. */
86122028508SToomas Soome 	shstrtab = alloc_pread(ef.fd, shdr[ef.ehdr->e_shstrndx].sh_offset,
86222028508SToomas Soome 	    shdr[ef.ehdr->e_shstrndx].sh_size);
86322028508SToomas Soome 	if (shstrtab == NULL) {
86422028508SToomas Soome 		printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
86522028508SToomas Soome 		    "load_modmetadata: unable to load shstrtab\n");
86622028508SToomas Soome 		err = EFTYPE;
86722028508SToomas Soome 		goto out;
86822028508SToomas Soome 	}
86922028508SToomas Soome 
87022028508SToomas Soome 	/* Find set_modmetadata_set and data sections. */
87122028508SToomas Soome 	sh_data[0] = sh_data[1] = sh_meta = NULL;
87222028508SToomas Soome 	for (i = 0, j = 0; i < ef.ehdr->e_shnum; i++) {
87322028508SToomas Soome 		if (strcmp(&shstrtab[shdr[i].sh_name],
87422028508SToomas Soome 		    "set_modmetadata_set") == 0) {
87522028508SToomas Soome 			sh_meta = &shdr[i];
87622028508SToomas Soome 		}
87722028508SToomas Soome 		if ((strcmp(&shstrtab[shdr[i].sh_name], ".data") == 0) ||
87822028508SToomas Soome 		    (strcmp(&shstrtab[shdr[i].sh_name], ".rodata") == 0)) {
87922028508SToomas Soome 			sh_data[j++] = &shdr[i];
88022028508SToomas Soome 		}
88122028508SToomas Soome 	}
88222028508SToomas Soome 	if (sh_meta == NULL || sh_data[0] == NULL || sh_data[1] == NULL) {
883*de11c9b6SToomas Soome 		printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "load_modmetadata: "
884*de11c9b6SToomas Soome 		    "unable to find set_modmetadata_set or data sections\n");
88522028508SToomas Soome 		err = EFTYPE;
88622028508SToomas Soome 		goto out;
88722028508SToomas Soome 	}
88822028508SToomas Soome 
88922028508SToomas Soome 	/* Load set_modmetadata_set into memory */
89022028508SToomas Soome 	err = kern_pread(ef.fd, dest, sh_meta->sh_size, sh_meta->sh_offset);
89122028508SToomas Soome 	if (err != 0) {
892*de11c9b6SToomas Soome 		printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "load_modmetadata: "
893*de11c9b6SToomas Soome 		    "unable to load set_modmetadata_set: %d\n", err);
89422028508SToomas Soome 		goto out;
89522028508SToomas Soome 	}
89622028508SToomas Soome 	p_start = dest;
89722028508SToomas Soome 	p_end = dest + sh_meta->sh_size;
89822028508SToomas Soome 	dest += sh_meta->sh_size;
89922028508SToomas Soome 
90022028508SToomas Soome 	/* Load data sections into memory. */
90122028508SToomas Soome 	err = kern_pread(ef.fd, dest, sh_data[0]->sh_size,
90222028508SToomas Soome 	    sh_data[0]->sh_offset);
90322028508SToomas Soome 	if (err != 0) {
90422028508SToomas Soome 		printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
90522028508SToomas Soome 		    "load_modmetadata: unable to load data: %d\n", err);
90622028508SToomas Soome 		goto out;
90722028508SToomas Soome 	}
90822028508SToomas Soome 
90922028508SToomas Soome 	/*
91022028508SToomas Soome 	 * We have to increment the dest, so that the offset is the same into
91122028508SToomas Soome 	 * both the .rodata and .data sections.
91222028508SToomas Soome 	 */
91322028508SToomas Soome 	ef.off = -(sh_data[0]->sh_addr - dest);
91422028508SToomas Soome 	dest +=	(sh_data[1]->sh_addr - sh_data[0]->sh_addr);
91522028508SToomas Soome 
91622028508SToomas Soome 	err = kern_pread(ef.fd, dest, sh_data[1]->sh_size,
91722028508SToomas Soome 	    sh_data[1]->sh_offset);
91822028508SToomas Soome 	if (err != 0) {
91922028508SToomas Soome 		printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
92022028508SToomas Soome 		    "load_modmetadata: unable to load data: %d\n", err);
92122028508SToomas Soome 		goto out;
92222028508SToomas Soome 	}
92322028508SToomas Soome 
92422028508SToomas Soome 	err = __elfN(parse_modmetadata)(fp, &ef, p_start, p_end);
92522028508SToomas Soome 	if (err != 0) {
92622028508SToomas Soome 		printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
92722028508SToomas Soome 		    "load_modmetadata: unable to parse metadata: %d\n", err);
92822028508SToomas Soome 		goto out;
92922028508SToomas Soome 	}
93022028508SToomas Soome 
93122028508SToomas Soome out:
93222028508SToomas Soome 	if (shstrtab != NULL)
93322028508SToomas Soome 		free(shstrtab);
93422028508SToomas Soome 	if (shdr != NULL)
93522028508SToomas Soome 		free(shdr);
93622028508SToomas Soome 	if (ef.firstpage != NULL)
93722028508SToomas Soome 		free(ef.firstpage);
93822028508SToomas Soome 	if (ef.fd != -1)
93922028508SToomas Soome 		close(ef.fd);
94022028508SToomas Soome 	return (err);
94122028508SToomas Soome }
94222028508SToomas Soome 
94322028508SToomas Soome int
__elfN(parse_modmetadata)94422028508SToomas Soome __elfN(parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef,
94522028508SToomas Soome     Elf_Addr p_start, Elf_Addr p_end)
94622028508SToomas Soome {
94722028508SToomas Soome 	struct mod_metadata md;
94822028508SToomas Soome #if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64
94922028508SToomas Soome 	struct mod_metadata64 md64;
95022028508SToomas Soome #elif defined(__amd64__) && __ELF_WORD_SIZE == 32
95122028508SToomas Soome 	struct mod_metadata32 md32;
95222028508SToomas Soome #endif
95322028508SToomas Soome 	struct mod_depend *mdepend;
95422028508SToomas Soome 	struct mod_version mver;
95522028508SToomas Soome 	char *s;
95622028508SToomas Soome 	int error, modcnt, minfolen;
95722028508SToomas Soome 	Elf_Addr v, p;
95822028508SToomas Soome 
95922028508SToomas Soome 	modcnt = 0;
96022028508SToomas Soome 	p = p_start;
96122028508SToomas Soome 	while (p < p_end) {
96222028508SToomas Soome 		COPYOUT(p, &v, sizeof (v));
96322028508SToomas Soome 		error = __elfN(reloc_ptr)(fp, ef, p, &v, sizeof (v));
96422028508SToomas Soome 		if (error == EOPNOTSUPP)
96522028508SToomas Soome 			v += ef->off;
96622028508SToomas Soome 		else if (error != 0)
96722028508SToomas Soome 			return (error);
96822028508SToomas Soome #if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64
96922028508SToomas Soome 		COPYOUT(v, &md64, sizeof (md64));
97022028508SToomas Soome 		error = __elfN(reloc_ptr)(fp, ef, v, &md64, sizeof (md64));
97122028508SToomas Soome 		if (error == EOPNOTSUPP) {
97222028508SToomas Soome 			md64.md_cval += ef->off;
97322028508SToomas Soome 			md64.md_data += ef->off;
97422028508SToomas Soome 		} else if (error != 0)
97522028508SToomas Soome 			return (error);
97622028508SToomas Soome 		md.md_version = md64.md_version;
97722028508SToomas Soome 		md.md_type = md64.md_type;
97822028508SToomas Soome 		md.md_cval = (const char *)(uintptr_t)md64.md_cval;
97922028508SToomas Soome 		md.md_data = (void *)(uintptr_t)md64.md_data;
98022028508SToomas Soome #elif defined(__amd64__) && __ELF_WORD_SIZE == 32
98122028508SToomas Soome 		COPYOUT(v, &md32, sizeof (md32));
98222028508SToomas Soome 		error = __elfN(reloc_ptr)(fp, ef, v, &md32, sizeof (md32));
98322028508SToomas Soome 		if (error == EOPNOTSUPP) {
98422028508SToomas Soome 			md32.md_cval += ef->off;
98522028508SToomas Soome 			md32.md_data += ef->off;
98622028508SToomas Soome 		} else if (error != 0)
98722028508SToomas Soome 			return (error);
98822028508SToomas Soome 		md.md_version = md32.md_version;
98922028508SToomas Soome 		md.md_type = md32.md_type;
99022028508SToomas Soome 		md.md_cval = (const char *)(uintptr_t)md32.md_cval;
99122028508SToomas Soome 		md.md_data = (void *)(uintptr_t)md32.md_data;
99222028508SToomas Soome #else
99322028508SToomas Soome 		COPYOUT(v, &md, sizeof (md));
99422028508SToomas Soome 		error = __elfN(reloc_ptr)(fp, ef, v, &md, sizeof (md));
99522028508SToomas Soome 		if (error == EOPNOTSUPP) {
99622028508SToomas Soome 			md.md_cval += ef->off;
997*de11c9b6SToomas Soome 			md.md_data = (void *)((uintptr_t)md.md_data +
998*de11c9b6SToomas Soome 			    (uintptr_t)ef->off);
99922028508SToomas Soome 		} else if (error != 0)
100022028508SToomas Soome 			return (error);
100122028508SToomas Soome #endif
100222028508SToomas Soome 		p += sizeof (Elf_Addr);
100322028508SToomas Soome 		switch (md.md_type) {
100422028508SToomas Soome 		case MDT_DEPEND:
100522028508SToomas Soome 			if (ef->kernel)	/* kernel must not depend on anything */
100622028508SToomas Soome 				break;
100722028508SToomas Soome 			s = strdupout((vm_offset_t)md.md_cval);
100822028508SToomas Soome 			minfolen = sizeof (*mdepend) + strlen(s) + 1;
100922028508SToomas Soome 			mdepend = malloc(minfolen);
101022028508SToomas Soome 			if (mdepend == NULL)
1011*de11c9b6SToomas Soome 				return (ENOMEM);
1012*de11c9b6SToomas Soome 			COPYOUT((vm_offset_t)md.md_data, mdepend,
1013*de11c9b6SToomas Soome 			    sizeof (*mdepend));
101422028508SToomas Soome 			strcpy((char *)(mdepend + 1), s);
101522028508SToomas Soome 			free(s);
1016*de11c9b6SToomas Soome 			file_addmetadata(fp, MODINFOMD_DEPLIST, minfolen,
1017*de11c9b6SToomas Soome 			    mdepend);
101822028508SToomas Soome 			free(mdepend);
101922028508SToomas Soome 			break;
102022028508SToomas Soome 		case MDT_VERSION:
102122028508SToomas Soome 			s = strdupout((vm_offset_t)md.md_cval);
102222028508SToomas Soome 			COPYOUT((vm_offset_t)md.md_data, &mver, sizeof (mver));
102322028508SToomas Soome 			file_addmodule(fp, s, mver.mv_version, NULL);
102422028508SToomas Soome 			free(s);
102522028508SToomas Soome 			modcnt++;
102622028508SToomas Soome 			break;
102722028508SToomas Soome 		}
102822028508SToomas Soome 	}
102922028508SToomas Soome 	if (modcnt == 0) {
103022028508SToomas Soome 		s = fake_modname(fp->f_name);
103122028508SToomas Soome 		file_addmodule(fp, s, 1, NULL);
103222028508SToomas Soome 		free(s);
103322028508SToomas Soome 	}
1034*de11c9b6SToomas Soome 	return (0);
103522028508SToomas Soome }
103622028508SToomas Soome 
103722028508SToomas Soome static unsigned long
elf_hash(const char * name)103822028508SToomas Soome elf_hash(const char *name)
103922028508SToomas Soome {
104022028508SToomas Soome 	const unsigned char *p = (const unsigned char *) name;
104122028508SToomas Soome 	unsigned long h = 0;
104222028508SToomas Soome 	unsigned long g;
104322028508SToomas Soome 
104422028508SToomas Soome 	while (*p != '\0') {
104522028508SToomas Soome 		h = (h << 4) + *p++;
104622028508SToomas Soome 		if ((g = h & 0xf0000000) != 0)
104722028508SToomas Soome 			h ^= g >> 24;
104822028508SToomas Soome 		h &= ~g;
104922028508SToomas Soome 	}
1050*de11c9b6SToomas Soome 	return (h);
105122028508SToomas Soome }
105222028508SToomas Soome 
1053*de11c9b6SToomas Soome static const char __elfN(bad_symtable)[] = "elf" __XSTRING(__ELF_WORD_SIZE)
1054*de11c9b6SToomas Soome 	"_lookup_symbol: corrupt symbol table\n";
1055*de11c9b6SToomas Soome 
105622028508SToomas Soome int
__elfN(lookup_symbol)105722028508SToomas Soome __elfN(lookup_symbol)(struct preloaded_file *fp __unused, elf_file_t ef,
105822028508SToomas Soome     const char *name, Elf_Sym *symp)
105922028508SToomas Soome {
106022028508SToomas Soome 	Elf_Hashelt symnum;
106122028508SToomas Soome 	Elf_Sym sym;
106222028508SToomas Soome 	char *strp;
106322028508SToomas Soome 	unsigned long hash;
106422028508SToomas Soome 
106522028508SToomas Soome 	hash = elf_hash(name);
106622028508SToomas Soome 	COPYOUT(&ef->buckets[hash % ef->nbuckets], &symnum, sizeof (symnum));
106722028508SToomas Soome 
106822028508SToomas Soome 	while (symnum != STN_UNDEF) {
106922028508SToomas Soome 		if (symnum >= ef->nchains) {
107022028508SToomas Soome 			printf(__elfN(bad_symtable));
1071*de11c9b6SToomas Soome 			return (ENOENT);
107222028508SToomas Soome 		}
107322028508SToomas Soome 
107422028508SToomas Soome 		COPYOUT(ef->symtab + symnum, &sym, sizeof (sym));
107522028508SToomas Soome 		if (sym.st_name == 0) {
107622028508SToomas Soome 			printf(__elfN(bad_symtable));
1077*de11c9b6SToomas Soome 			return (ENOENT);
107822028508SToomas Soome 		}
107922028508SToomas Soome 
108022028508SToomas Soome 		strp = strdupout((vm_offset_t)(ef->strtab + sym.st_name));
108122028508SToomas Soome 		if (strcmp(name, strp) == 0) {
108222028508SToomas Soome 			free(strp);
108322028508SToomas Soome 			if (sym.st_shndx != SHN_UNDEF ||
108422028508SToomas Soome 			    (sym.st_value != 0 &&
108522028508SToomas Soome 			    ELF_ST_TYPE(sym.st_info) == STT_FUNC)) {
108622028508SToomas Soome 				*symp = sym;
1087*de11c9b6SToomas Soome 				return (0);
108822028508SToomas Soome 			}
1089*de11c9b6SToomas Soome 			return (ENOENT);
109022028508SToomas Soome 		}
109122028508SToomas Soome 		free(strp);
109222028508SToomas Soome 		COPYOUT(&ef->chains[symnum], &symnum, sizeof (symnum));
109322028508SToomas Soome 	}
1094*de11c9b6SToomas Soome 	return (ENOENT);
109522028508SToomas Soome }
109622028508SToomas Soome 
109722028508SToomas Soome /*
109822028508SToomas Soome  * Apply any intra-module relocations to the value. p is the load address
109922028508SToomas Soome  * of the value and val/len is the value to be modified. This does NOT modify
110022028508SToomas Soome  * the image in-place, because this is done by kern_linker later on.
110122028508SToomas Soome  *
110222028508SToomas Soome  * Returns EOPNOTSUPP if no relocation method is supplied.
110322028508SToomas Soome  */
110422028508SToomas Soome static int
__elfN(reloc_ptr)1105*de11c9b6SToomas Soome __elfN(reloc_ptr)(struct preloaded_file *mp __unused, elf_file_t ef,
110622028508SToomas Soome     Elf_Addr p, void *val, size_t len)
110722028508SToomas Soome {
110822028508SToomas Soome 	size_t n;
110922028508SToomas Soome 	Elf_Rela a;
111022028508SToomas Soome 	Elf_Rel r;
111122028508SToomas Soome 	int error;
111222028508SToomas Soome 
111322028508SToomas Soome 	/*
111422028508SToomas Soome 	 * The kernel is already relocated, but we still want to apply
111522028508SToomas Soome 	 * offset adjustments.
111622028508SToomas Soome 	 */
111722028508SToomas Soome 	if (ef->kernel)
111822028508SToomas Soome 		return (EOPNOTSUPP);
111922028508SToomas Soome 
112022028508SToomas Soome 	for (n = 0; n < ef->relsz / sizeof (r); n++) {
112122028508SToomas Soome 		COPYOUT(ef->rel + n, &r, sizeof (r));
112222028508SToomas Soome 
112322028508SToomas Soome 		error = __elfN(reloc)(ef, __elfN(symaddr), &r, ELF_RELOC_REL,
112422028508SToomas Soome 		    ef->off, p, val, len);
112522028508SToomas Soome 		if (error != 0)
112622028508SToomas Soome 			return (error);
112722028508SToomas Soome 	}
112822028508SToomas Soome 	for (n = 0; n < ef->relasz / sizeof (a); n++) {
112922028508SToomas Soome 		COPYOUT(ef->rela + n, &a, sizeof (a));
113022028508SToomas Soome 
113122028508SToomas Soome 		error = __elfN(reloc)(ef, __elfN(symaddr), &a, ELF_RELOC_RELA,
113222028508SToomas Soome 		    ef->off, p, val, len);
113322028508SToomas Soome 		if (error != 0)
113422028508SToomas Soome 			return (error);
113522028508SToomas Soome 	}
113622028508SToomas Soome 
113722028508SToomas Soome 	return (0);
113822028508SToomas Soome }
113922028508SToomas Soome 
114022028508SToomas Soome static Elf_Addr
__elfN(symaddr)114122028508SToomas Soome __elfN(symaddr)(struct elf_file *ef __unused, Elf_Size symidx __unused)
114222028508SToomas Soome {
114322028508SToomas Soome 	/* Symbol lookup by index not required here. */
114422028508SToomas Soome 	return (0);
114522028508SToomas Soome }
1146