1227569Sphilip/*
2301388Sarybchik * Copyright (c) 2000, Boris Popov
3284555Sarybchik * Copyright (c) 1998-2000 Doug Rabson
4227569Sphilip * Copyright (c) 2004 Peter Wemm
5227569Sphilip * All rights reserved.
6284555Sarybchik *
7227569Sphilip * Redistribution and use in source and binary forms, with or without
8284555Sarybchik * modification, are permitted provided that the following conditions
9284555Sarybchik * are met:
10284555Sarybchik * 1. Redistributions of source code must retain the above copyright
11284555Sarybchik *    notice, this list of conditions and the following disclaimer.
12284555Sarybchik * 2. Redistributions in binary form must reproduce the above copyright
13228078Sphilip *    notice, this list of conditions and the following disclaimer in the
14284555Sarybchik *    documentation and/or other materials provided with the distribution.
15284555Sarybchik * 3. All advertising materials mentioning features or use of this software
16284555Sarybchik *    must display the following acknowledgement:
17284555Sarybchik *    This product includes software developed by Boris Popov.
18284555Sarybchik * 4. Neither the name of the author nor the names of any co-contributors
19284555Sarybchik *    may be used to endorse or promote products derived from this software
20284555Sarybchik *    without specific prior written permission.
21284555Sarybchik *
22284555Sarybchik * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23284555Sarybchik * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24284555Sarybchik * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25284555Sarybchik * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26284555Sarybchik * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27284555Sarybchik * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28284555Sarybchik * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29284555Sarybchik * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30228078Sphilip * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31227569Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32227569Sphilip * SUCH DAMAGE.
33227569Sphilip *
34227569Sphilip * $FreeBSD$
35227569Sphilip */
36227569Sphilip
37227569Sphilip#include <sys/param.h>
38284555Sarybchik#include <sys/linker.h>
39227569Sphilip#include <string.h>
40284555Sarybchik#include <stdio.h>
41284555Sarybchik#include <stdlib.h>
42284555Sarybchik#include <unistd.h>
43284555Sarybchik#include <errno.h>
44284555Sarybchik#include <fcntl.h>
45284555Sarybchik#include <machine/elf.h>
46227569Sphilip#define FREEBSD_ELF
47227569Sphilip
48227569Sphilip#include <err.h>
49227569Sphilip
50284555Sarybchik#include "ef.h"
51284555Sarybchik
52284555Sarybchiktypedef struct {
53284555Sarybchik	void		*addr;
54293980Sarybchik	Elf_Off		size;
55293980Sarybchik	int		flags;
56293980Sarybchik	int		sec;	/* Original section */
57293980Sarybchik	char		*name;
58293980Sarybchik} Elf_progent;
59293980Sarybchik
60293980Sarybchiktypedef struct {
61293980Sarybchik	Elf_Rel		*rel;
62227569Sphilip	int		nrel;
63227569Sphilip	int		sec;
64227569Sphilip} Elf_relent;
65227569Sphilip
66284555Sarybchiktypedef struct {
67284555Sarybchik	Elf_Rela	*rela;
68284555Sarybchik	int		nrela;
69284555Sarybchik	int		sec;
70284555Sarybchik} Elf_relaent;
71284555Sarybchik
72284555Sarybchikstruct ef_file {
73284555Sarybchik	char		*ef_name;
74284555Sarybchik	int		ef_fd;
75284555Sarybchik	Elf_Ehdr	ef_hdr;
76284555Sarybchik	struct elf_file *ef_efile;
77284555Sarybchik
78301327Sarybchik	caddr_t		address;
79227569Sphilip	Elf_Off		size;
80301355Sarybchik	Elf_Shdr	*e_shdr;
81301355Sarybchik
82301355Sarybchik	Elf_progent	*progtab;
83227569Sphilip	int		nprogtab;
84227569Sphilip
85227569Sphilip	Elf_relaent	*relatab;
86227569Sphilip	int		nrela;
87284555Sarybchik
88294395Sarybchik	Elf_relent	*reltab;
89227569Sphilip	int		nrel;
90227569Sphilip
91227569Sphilip	Elf_Sym		*ddbsymtab;	/* The symbol table we are using */
92284555Sarybchik	long		ddbsymcnt;	/* Number of symbols */
93293927Sarybchik	caddr_t		ddbstrtab;	/* String table */
94284555Sarybchik	long		ddbstrcnt;	/* number of bytes in string table */
95293927Sarybchik
96284555Sarybchik	caddr_t		shstrtab;	/* Section name string table */
97311070Sarybchik	long		shstrcnt;	/* number of bytes in string table */
98284555Sarybchik
99293927Sarybchik	int		ef_verbose;
100284555Sarybchik};
101293927Sarybchik
102284555Sarybchikstatic int ef_obj_get_type(elf_file_t ef);
103284555Sarybchikstatic int ef_obj_close(elf_file_t ef);
104284555Sarybchikstatic int ef_obj_read(elf_file_t ef, Elf_Off offset, size_t len, void* dest);
105284555Sarybchikstatic int ef_obj_read_entry(elf_file_t ef, Elf_Off offset, size_t len,
106284555Sarybchik    void **ptr);
107284555Sarybchikstatic int ef_obj_seg_read(elf_file_t ef, Elf_Off offset, size_t len,
108293927Sarybchik    void *dest);
109284555Sarybchikstatic int ef_obj_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len,
110293927Sarybchik    void *dest);
111284555Sarybchikstatic int ef_obj_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len,
112284555Sarybchik    void **ptr);
113284555Sarybchikstatic int ef_obj_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len,
114284555Sarybchik    void **ptr);
115284555Sarybchikstatic Elf_Addr ef_obj_symaddr(elf_file_t ef, Elf_Size symidx);
116284555Sarybchikstatic int ef_obj_lookup_set(elf_file_t ef, const char *name, long *startp,
117293927Sarybchik    long *stopp, long *countp);
118284555Sarybchikstatic int ef_obj_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym);
119284555Sarybchik
120284555Sarybchikstatic struct elf_file_ops ef_obj_file_ops = {
121293927Sarybchik	ef_obj_get_type,
122293927Sarybchik	ef_obj_close,
123284555Sarybchik	ef_obj_read,
124293927Sarybchik	ef_obj_read_entry,
125284555Sarybchik	ef_obj_seg_read,
126311063Sarybchik	ef_obj_seg_read_rel,
127284555Sarybchik	ef_obj_seg_read_entry,
128293927Sarybchik	ef_obj_seg_read_entry_rel,
129284555Sarybchik	ef_obj_symaddr,
130293927Sarybchik	ef_obj_lookup_set,
131284555Sarybchik	ef_obj_lookup_symbol
132284555Sarybchik};
133284555Sarybchik
134284555Sarybchikstatic int
135284555Sarybchikef_obj_get_type(elf_file_t __unused ef)
136284555Sarybchik{
137284555Sarybchik
138284555Sarybchik	return (EFT_KLD);
139294381Sarybchik}
140294381Sarybchik
141294381Sarybchikstatic int
142284555Sarybchikef_obj_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym)
143284555Sarybchik{
144342509Sarybchik	Elf_Sym *symp;
145342509Sarybchik	const char *strp;
146284555Sarybchik	int i;
147284555Sarybchik
148284555Sarybchik	for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
149284555Sarybchik		strp = ef->ddbstrtab + symp->st_name;
150284555Sarybchik		if (symp->st_shndx != SHN_UNDEF && strcmp(name, strp) == 0) {
151284555Sarybchik			*sym = symp;
152284555Sarybchik			return 0;
153293927Sarybchik		}
154284555Sarybchik	}
155284555Sarybchik	return ENOENT;
156293927Sarybchik}
157284555Sarybchik
158284555Sarybchikstatic int
159293927Sarybchikef_obj_lookup_set(elf_file_t ef, const char *name, long *startp, long *stopp,
160284555Sarybchik    long *countp)
161293927Sarybchik{
162293927Sarybchik	int i;
163284555Sarybchik
164294008Sarybchik	for (i = 0; i < ef->nprogtab; i++) {
165294008Sarybchik		if ((strncmp(ef->progtab[i].name, "set_", 4) == 0) &&
166294008Sarybchik		    strcmp(ef->progtab[i].name + 4, name) == 0) {
167294008Sarybchik			*startp = (char *)ef->progtab[i].addr - ef->address;
168294008Sarybchik			*stopp = (char *)ef->progtab[i].addr +
169284555Sarybchik			    ef->progtab[i].size - ef->address;
170284555Sarybchik			*countp = (*stopp - *startp) / sizeof(void *);
171284555Sarybchik			return (0);
172284555Sarybchik		}
173293927Sarybchik	}
174284555Sarybchik	return (ESRCH);
175293927Sarybchik}
176284555Sarybchik
177284555Sarybchikstatic Elf_Addr
178284555Sarybchikef_obj_symaddr(elf_file_t ef, Elf_Size symidx)
179284555Sarybchik{
180284555Sarybchik	const Elf_Sym *sym;
181284555Sarybchik
182227569Sphilip	if (symidx >= (size_t) ef->ddbsymcnt)
183293927Sarybchik		return (0);
184293927Sarybchik	sym = ef->ddbsymtab + symidx;
185293927Sarybchik
186294397Sarybchik	if (sym->st_shndx != SHN_UNDEF)
187301380Sarybchik		return (sym->st_value - (Elf_Addr)ef->address);
188293927Sarybchik	return (0);
189293927Sarybchik}
190293927Sarybchik
191284555Sarybchikstatic int
192284555Sarybchikef_obj_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
193227569Sphilip{
194293927Sarybchik	ssize_t r;
195227569Sphilip
196227569Sphilip	if (offset != (Elf_Off)-1) {
197227569Sphilip		if (lseek(ef->ef_fd, offset, SEEK_SET) == -1)
198311080Sarybchik			return EIO;
199293927Sarybchik	}
200293927Sarybchik
201227569Sphilip	r = read(ef->ef_fd, dest, len);
202293927Sarybchik	if (r != -1 && (size_t)r == len)
203227569Sphilip		return 0;
204227569Sphilip	else
205227569Sphilip		return EIO;
206227569Sphilip}
207227569Sphilip
208293927Sarybchikstatic int
209293927Sarybchikef_obj_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr)
210293927Sarybchik{
211293927Sarybchik	int error;
212293927Sarybchik
213227569Sphilip	*ptr = malloc(len);
214293927Sarybchik	if (*ptr == NULL)
215227569Sphilip		return ENOMEM;
216227569Sphilip	error = ef_obj_read(ef, offset, len, *ptr);
217284555Sarybchik	if (error)
218293927Sarybchik		free(*ptr);
219293927Sarybchik	return error;
220293927Sarybchik}
221284555Sarybchik
222227569Sphilipstatic int
223284555Sarybchikef_obj_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
224284555Sarybchik{
225227569Sphilip
226227569Sphilip	if (offset + len > ef->size) {
227284555Sarybchik		if (ef->ef_verbose)
228284555Sarybchik			warnx("ef_seg_read_rel(%s): bad offset/len (%lx:%ld)",
229293927Sarybchik			    ef->ef_name, (long)offset, (long)len);
230293927Sarybchik		return (EFAULT);
231293927Sarybchik	}
232293927Sarybchik	bcopy(ef->address + offset, dest, len);
233293927Sarybchik	return (0);
234293927Sarybchik}
235311494Sarybchik
236311494Sarybchikstatic int
237293927Sarybchikef_obj_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
238284555Sarybchik{
239301337Sarybchik	char *memaddr;
240284555Sarybchik	Elf_Rel *r;
241284555Sarybchik	Elf_Rela *a;
242293927Sarybchik	Elf_Off secbase, dataoff;
243284555Sarybchik	int error, i, sec;
244284555Sarybchik
245284555Sarybchik	if (offset + len > ef->size) {
246284555Sarybchik		if (ef->ef_verbose)
247284555Sarybchik			warnx("ef_seg_read_rel(%s): bad offset/len (%lx:%ld)",
248284555Sarybchik			    ef->ef_name, (long)offset, (long)len);
249284555Sarybchik		return (EFAULT);
250284555Sarybchik	}
251301337Sarybchik	bcopy(ef->address + offset, dest, len);
252284555Sarybchik
253284555Sarybchik	/* Find out which section contains the data. */
254284555Sarybchik	memaddr = ef->address + offset;
255284555Sarybchik	sec = -1;
256227569Sphilip	secbase = dataoff = 0;
257227569Sphilip	for (i = 0; i < ef->nprogtab; i++) {
258311056Sarybchik		if (ef->progtab[i].addr == NULL)
259227569Sphilip			continue;
260227569Sphilip		if (memaddr < (char *)ef->progtab[i].addr || memaddr + len >
261227569Sphilip		     (char *)ef->progtab[i].addr + ef->progtab[i].size)
262227569Sphilip			continue;
263284555Sarybchik		sec = ef->progtab[i].sec;
264284555Sarybchik		/* We relocate to address 0. */
265284555Sarybchik		secbase = (char *)ef->progtab[i].addr - ef->address;
266227569Sphilip		dataoff = memaddr - ef->address;
267227569Sphilip		break;
268227569Sphilip	}
269227569Sphilip
270284555Sarybchik	if (sec == -1)
271284555Sarybchik		return (EFAULT);
272284555Sarybchik
273227569Sphilip	/* Now do the relocations. */
274227569Sphilip	for (i = 0; i < ef->nrel; i++) {
275227569Sphilip		if (ef->reltab[i].sec != sec)
276227569Sphilip			continue;
277227569Sphilip		for (r = ef->reltab[i].rel;
278227569Sphilip		     r < &ef->reltab[i].rel[ef->reltab[i].nrel]; r++) {
279227569Sphilip			error = ef_reloc(ef->ef_efile, r, EF_RELOC_REL, secbase,
280227569Sphilip			    dataoff, len, dest);
281227569Sphilip			if (error != 0)
282227569Sphilip				return (error);
283227569Sphilip		}
284227569Sphilip	}
285227569Sphilip	for (i = 0; i < ef->nrela; i++) {
286227569Sphilip		if (ef->relatab[i].sec != sec)
287227569Sphilip			continue;
288227569Sphilip		for (a = ef->relatab[i].rela;
289227569Sphilip		     a < &ef->relatab[i].rela[ef->relatab[i].nrela]; a++) {
290284555Sarybchik			error = ef_reloc(ef->ef_efile, a, EF_RELOC_RELA,
291284555Sarybchik			    secbase, dataoff, len, dest);
292227569Sphilip			if (error != 0)
293301340Sarybchik				return (error);
294301340Sarybchik		}
295227569Sphilip	}
296227569Sphilip	return (0);
297227569Sphilip}
298227569Sphilip
299293927Sarybchikstatic int
300293927Sarybchikef_obj_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr)
301227569Sphilip{
302227569Sphilip	int error;
303227569Sphilip
304227569Sphilip	*ptr = malloc(len);
305301340Sarybchik	if (*ptr == NULL)
306301340Sarybchik		return ENOMEM;
307227569Sphilip	error = ef_obj_seg_read(ef, offset, len, *ptr);
308227569Sphilip	if (error)
309284555Sarybchik		free(*ptr);
310293927Sarybchik	return error;
311284555Sarybchik}
312284555Sarybchik
313284555Sarybchikstatic int
314293927Sarybchikef_obj_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len,
315294001Sarybchik    void **ptr)
316294001Sarybchik{
317294001Sarybchik	int error;
318294001Sarybchik
319284555Sarybchik	*ptr = malloc(len);
320284555Sarybchik	if (*ptr == NULL)
321284555Sarybchik		return ENOMEM;
322227569Sphilip	error = ef_obj_seg_read_rel(ef, offset, len, *ptr);
323301340Sarybchik	if (error)
324301340Sarybchik		free(*ptr);
325301340Sarybchik	return error;
326301340Sarybchik}
327227569Sphilip
328227569Sphilipint
329227569Sphilipef_obj_open(const char *filename, struct elf_file *efile, int verbose)
330293927Sarybchik{
331294377Sarybchik	elf_file_t ef;
332293927Sarybchik	Elf_Ehdr *hdr;
333293927Sarybchik	Elf_Shdr *shdr;
334293927Sarybchik	Elf_Sym *es;
335293927Sarybchik	char *mapbase;
336293927Sarybchik	void *vtmp;
337284555Sarybchik	size_t mapsize, alignmask, max_addralign;
338227569Sphilip	int error, fd, pb, ra, res, rl;
339293927Sarybchik	int i, j, nbytes, nsym, shstrindex, symstrindex, symtabindex;
340227569Sphilip
341293927Sarybchik	if (filename == NULL)
342293927Sarybchik		return EFTYPE;
343227569Sphilip	if ((fd = open(filename, O_RDONLY)) == -1)
344227569Sphilip		return errno;
345280562Sarybchik
346284555Sarybchik	ef = calloc(1, sizeof(*ef));
347280562Sarybchik	if (ef == NULL) {
348280562Sarybchik		close(fd);
349284555Sarybchik		return (ENOMEM);
350280562Sarybchik	}
351280562Sarybchik
352284555Sarybchik	efile->ef_ef = ef;
353280562Sarybchik	efile->ef_ops = &ef_obj_file_ops;
354280562Sarybchik
355284555Sarybchik	ef->ef_verbose = verbose;
356280562Sarybchik	ef->ef_fd = fd;
357227569Sphilip	ef->ef_name = strdup(filename);
358227569Sphilip	ef->ef_efile = efile;
359227569Sphilip	hdr = (Elf_Ehdr *)&ef->ef_hdr;
360301346Sarybchik
361301346Sarybchik	res = read(fd, hdr, sizeof(*hdr));
362301346Sarybchik	error = EFTYPE;
363301346Sarybchik	if (res != sizeof(*hdr))
364301346Sarybchik		goto out;
365301346Sarybchik	if (!IS_ELF(*hdr))
366227569Sphilip		goto out;
367301346Sarybchik	if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
368301346Sarybchik	    hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
369301346Sarybchik	    hdr->e_ident[EI_VERSION] != EV_CURRENT ||
370301346Sarybchik	    hdr->e_version != EV_CURRENT || hdr->e_machine != ELF_TARG_MACH ||
371301346Sarybchik	    hdr->e_type != ET_REL)
372301346Sarybchik		goto out;
373301346Sarybchik
374284555Sarybchik	nbytes = hdr->e_shnum * hdr->e_shentsize;
375301346Sarybchik	if (nbytes == 0 || hdr->e_shoff == 0 ||
376301346Sarybchik	    hdr->e_shentsize != sizeof(Elf_Shdr))
377301346Sarybchik		goto out;
378301346Sarybchik
379301346Sarybchik	if (ef_obj_read_entry(ef, hdr->e_shoff, nbytes, &vtmp) != 0) {
380301346Sarybchik		printf("ef_read_entry failed\n");
381227569Sphilip		goto out;
382301346Sarybchik	}
383301346Sarybchik	ef->e_shdr = shdr = vtmp;
384227569Sphilip
385301346Sarybchik	/* Scan the section header for information and table sizing. */
386301346Sarybchik	nsym = 0;
387301346Sarybchik	symtabindex = -1;
388301346Sarybchik	symstrindex = -1;
389301346Sarybchik	for (i = 0; i < hdr->e_shnum; i++) {
390301346Sarybchik		switch (shdr[i].sh_type) {
391301346Sarybchik		case SHT_PROGBITS:
392227569Sphilip		case SHT_NOBITS:
393301346Sarybchik			ef->nprogtab++;
394301346Sarybchik			break;
395301346Sarybchik		case SHT_SYMTAB:
396301346Sarybchik			nsym++;
397301346Sarybchik			symtabindex = i;
398301346Sarybchik			symstrindex = shdr[i].sh_link;
399227569Sphilip			break;
400301346Sarybchik		case SHT_REL:
401301346Sarybchik			ef->nrel++;
402301346Sarybchik			break;
403301346Sarybchik		case SHT_RELA:
404227569Sphilip			ef->nrela++;
405227569Sphilip			break;
406301324Sarybchik		case SHT_STRTAB:
407301346Sarybchik			break;
408301324Sarybchik		}
409293996Sarybchik	}
410293996Sarybchik
411293996Sarybchik	if (ef->nprogtab == 0) {
412227569Sphilip		warnx("%s: file has no contents", filename);
413227569Sphilip		goto out;
414284555Sarybchik	}
415301345Sarybchik	if (nsym != 1) {
416227569Sphilip		warnx("%s: file has no valid symbol table", filename);
417301346Sarybchik		goto out;
418227569Sphilip	}
419284555Sarybchik	if (symstrindex < 0 || symstrindex > hdr->e_shnum ||
420227569Sphilip	    shdr[symstrindex].sh_type != SHT_STRTAB) {
421284555Sarybchik		warnx("%s: file has invalid symbol strings", filename);
422227569Sphilip		goto out;
423284555Sarybchik	}
424293927Sarybchik
425294378Sarybchik	/* Allocate space for tracking the load chunks */
426294378Sarybchik	if (ef->nprogtab != 0)
427293927Sarybchik		ef->progtab = calloc(ef->nprogtab, sizeof(*ef->progtab));
428293972Sarybchik	if (ef->nrel != 0)
429293972Sarybchik		ef->reltab = calloc(ef->nrel, sizeof(*ef->reltab));
430284555Sarybchik	if (ef->nrela != 0)
431311496Sarybchik		ef->relatab = calloc(ef->nrela, sizeof(*ef->relatab));
432311496Sarybchik	if ((ef->nprogtab != 0 && ef->progtab == NULL) ||
433311496Sarybchik	    (ef->nrel != 0 && ef->reltab == NULL) ||
434311496Sarybchik	    (ef->nrela != 0 && ef->relatab == NULL)) {
435284555Sarybchik		printf("malloc failed\n");
436227569Sphilip		error = ENOMEM;
437284555Sarybchik		goto out;
438301340Sarybchik	}
439284555Sarybchik
440284555Sarybchik	ef->ddbsymcnt = shdr[symtabindex].sh_size / sizeof(Elf_Sym);
441284555Sarybchik	if (ef_obj_read_entry(ef, shdr[symtabindex].sh_offset,
442227569Sphilip	    shdr[symtabindex].sh_size, (void**)&ef->ddbsymtab) != 0) {
443284555Sarybchik		printf("ef_read_entry failed\n");
444227569Sphilip		goto out;
445227569Sphilip	}
446227569Sphilip
447227569Sphilip	ef->ddbstrcnt = shdr[symstrindex].sh_size;
448293927Sarybchik	if (ef_obj_read_entry(ef, shdr[symstrindex].sh_offset,
449227569Sphilip	    shdr[symstrindex].sh_size, (void**)&ef->ddbstrtab) != 0) {
450294379Sarybchik		printf("ef_read_entry failed\n");
451294379Sarybchik		goto out;
452294379Sarybchik	}
453294379Sarybchik
454294379Sarybchik	/* Do we have a string table for the section names?  */
455293927Sarybchik	shstrindex = -1;
456294379Sarybchik	if (hdr->e_shstrndx != 0 &&
457294379Sarybchik	    shdr[hdr->e_shstrndx].sh_type == SHT_STRTAB) {
458294379Sarybchik		shstrindex = hdr->e_shstrndx;
459293927Sarybchik		ef->shstrcnt = shdr[shstrindex].sh_size;
460311495Sarybchik		if (ef_obj_read_entry(ef, shdr[shstrindex].sh_offset,
461294379Sarybchik		    shdr[shstrindex].sh_size, (void**)&ef->shstrtab) != 0) {
462294379Sarybchik			printf("ef_read_entry failed\n");
463294379Sarybchik			goto out;
464293927Sarybchik		}
465301321Sarybchik	}
466301321Sarybchik
467227569Sphilip	/* Size up code/data(progbits) and bss(nobits). */
468227569Sphilip	alignmask = 0;
469227569Sphilip	max_addralign = 0;
470227569Sphilip	mapsize = 0;
471227569Sphilip	for (i = 0; i < hdr->e_shnum; i++) {
472293927Sarybchik		switch (shdr[i].sh_type) {
473293927Sarybchik		case SHT_PROGBITS:
474293927Sarybchik		case SHT_NOBITS:
475293927Sarybchik			alignmask = shdr[i].sh_addralign - 1;
476293927Sarybchik			if (shdr[i].sh_addralign > max_addralign)
477293927Sarybchik				max_addralign = shdr[i].sh_addralign;
478293927Sarybchik			mapsize += alignmask;
479293927Sarybchik			mapsize &= ~alignmask;
480293927Sarybchik			mapsize += shdr[i].sh_size;
481293927Sarybchik			break;
482293927Sarybchik		}
483293927Sarybchik	}
484293927Sarybchik
485227569Sphilip	/* We know how much space we need for the text/data/bss/etc. */
486227569Sphilip	ef->size = mapsize;
487227569Sphilip	if (posix_memalign((void **)&ef->address, max_addralign, mapsize)) {
488284555Sarybchik		printf("posix_memalign failed\n");
489284555Sarybchik		goto out;
490293927Sarybchik	}
491284555Sarybchik	mapbase = ef->address;
492284555Sarybchik
493284555Sarybchik	/*
494284555Sarybchik	 * Now load code/data(progbits), zero bss(nobits), allocate
495284555Sarybchik	 * space for and load relocs
496284555Sarybchik	 */
497293927Sarybchik	pb = 0;
498284555Sarybchik	rl = 0;
499284555Sarybchik	ra = 0;
500284555Sarybchik	alignmask = 0;
501284555Sarybchik	for (i = 0; i < hdr->e_shnum; i++) {
502284555Sarybchik		switch (shdr[i].sh_type) {
503284555Sarybchik		case SHT_PROGBITS:
504284555Sarybchik		case SHT_NOBITS:
505284555Sarybchik			alignmask = shdr[i].sh_addralign - 1;
506293927Sarybchik			mapbase += alignmask;
507284555Sarybchik			mapbase  = (char *)((uintptr_t)mapbase & ~alignmask);
508284555Sarybchik			ef->progtab[pb].addr = (void *)(uintptr_t)mapbase;
509284555Sarybchik			if (shdr[i].sh_type == SHT_PROGBITS) {
510284555Sarybchik				ef->progtab[pb].name = "<<PROGBITS>>";
511284555Sarybchik				if (ef_obj_read(ef, shdr[i].sh_offset,
512293944Sarybchik				    shdr[i].sh_size,
513293944Sarybchik				    ef->progtab[pb].addr) != 0) {
514284555Sarybchik					printf("failed to read progbits\n");
515293927Sarybchik					goto out;
516284555Sarybchik				}
517284555Sarybchik			} else {
518284555Sarybchik				ef->progtab[pb].name = "<<NOBITS>>";
519284555Sarybchik				bzero(ef->progtab[pb].addr, shdr[i].sh_size);
520293927Sarybchik			}
521284555Sarybchik			ef->progtab[pb].size = shdr[i].sh_size;
522284555Sarybchik			ef->progtab[pb].sec = i;
523284555Sarybchik			if (ef->shstrtab && shdr[i].sh_name != 0)
524284555Sarybchik				ef->progtab[pb].name =
525284555Sarybchik				    ef->shstrtab + shdr[i].sh_name;
526294403Sarybchik
527294403Sarybchik			/* Update all symbol values with the offset. */
528284555Sarybchik			for (j = 0; j < ef->ddbsymcnt; j++) {
529293927Sarybchik				es = &ef->ddbsymtab[j];
530284555Sarybchik				if (es->st_shndx != i)
531284555Sarybchik					continue;
532284555Sarybchik				es->st_value += (Elf_Addr)ef->progtab[pb].addr;
533284555Sarybchik			}
534284555Sarybchik			mapbase += shdr[i].sh_size;
535284555Sarybchik			pb++;
536293927Sarybchik			break;
537284555Sarybchik		case SHT_REL:
538284555Sarybchik			ef->reltab[rl].nrel = shdr[i].sh_size / sizeof(Elf_Rel);
539284555Sarybchik			ef->reltab[rl].sec = shdr[i].sh_info;
540284555Sarybchik			if (ef_obj_read_entry(ef, shdr[i].sh_offset,
541342512Sarybchik			    shdr[i].sh_size, (void**)&ef->reltab[rl].rel) !=
542284555Sarybchik			    0) {
543284555Sarybchik				printf("ef_read_entry failed\n");
544293927Sarybchik				goto out;
545284555Sarybchik			}
546284555Sarybchik			rl++;
547284555Sarybchik			break;
548311495Sarybchik		case SHT_RELA:
549311495Sarybchik			ef->relatab[ra].nrela =
550284555Sarybchik			    shdr[i].sh_size / sizeof(Elf_Rela);
551284555Sarybchik			ef->relatab[ra].sec = shdr[i].sh_info;
552284555Sarybchik			if (ef_obj_read_entry(ef, shdr[i].sh_offset,
553293927Sarybchik			    shdr[i].sh_size, (void**)&ef->relatab[ra].rela) !=
554284555Sarybchik			    0) {
555284555Sarybchik				printf("ef_read_entry failed\n");
556284555Sarybchik				goto out;
557284555Sarybchik			}
558284555Sarybchik			ra++;
559284555Sarybchik			break;
560284555Sarybchik		}
561284555Sarybchik	}
562294386Sarybchik	error = 0;
563294386Sarybchikout:
564294386Sarybchik	if (error)
565294386Sarybchik		ef_obj_close(ef);
566294386Sarybchik	return error;
567294386Sarybchik}
568294386Sarybchik
569294386Sarybchikstatic int
570301361Sarybchikef_obj_close(elf_file_t ef)
571301361Sarybchik{
572301361Sarybchik	int i;
573310842Sarybchik
574301361Sarybchik	close(ef->ef_fd);
575301361Sarybchik	if (ef->ef_name)
576301361Sarybchik		free(ef->ef_name);
577301361Sarybchik	if (ef->e_shdr != NULL)
578301361Sarybchik		free(ef->e_shdr);
579301361Sarybchik	if (ef->size != 0)
580301361Sarybchik		free(ef->address);
581301361Sarybchik	if (ef->nprogtab != 0)
582301361Sarybchik		free(ef->progtab);
583301361Sarybchik	if (ef->nrel != 0) {
584301361Sarybchik		for (i = 0; i < ef->nrel; i++)
585301361Sarybchik			if (ef->reltab[i].rel != NULL)
586301361Sarybchik				free(ef->reltab[i].rel);
587301361Sarybchik		free(ef->reltab);
588301361Sarybchik	}
589301361Sarybchik	if (ef->nrela != 0) {
590301361Sarybchik		for (i = 0; i < ef->nrela; i++)
591294386Sarybchik			if (ef->relatab[i].rela != NULL)
592294386Sarybchik				free(ef->relatab[i].rela);
593294386Sarybchik		free(ef->relatab);
594294386Sarybchik	}
595284555Sarybchik	if (ef->ddbsymtab != NULL)
596284555Sarybchik		free(ef->ddbsymtab);
597284555Sarybchik	if (ef->ddbstrtab != NULL)
598284555Sarybchik		free(ef->ddbstrtab);
599284555Sarybchik	if (ef->shstrtab != NULL)
600284555Sarybchik		free(ef->shstrtab);
601284555Sarybchik	ef->ef_efile->ef_ops = NULL;
602284555Sarybchik	ef->ef_efile->ef_ef = NULL;
603227569Sphilip	free(ef);
604227569Sphilip
605227569Sphilip	return 0;
606227569Sphilip}
607227569Sphilip