xref: /openbsd-src/sys/lib/libsa/loadfile_elf.c (revision d64c9d9411a5ef9b1569b40e1bf69200456df05c)
1*d64c9d94Stom /* $NetBSD: loadfile.c,v 1.10 2000/12/03 02:53:04 tsutsui Exp $ */
2*d64c9d94Stom /* $OpenBSD: loadfile_elf.c,v 1.1 2007/05/30 01:25:43 tom Exp $ */
3*d64c9d94Stom 
4*d64c9d94Stom /*-
5*d64c9d94Stom  * Copyright (c) 1997 The NetBSD Foundation, Inc.
6*d64c9d94Stom  * All rights reserved.
7*d64c9d94Stom  *
8*d64c9d94Stom  * This code is derived from software contributed to The NetBSD Foundation
9*d64c9d94Stom  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10*d64c9d94Stom  * NASA Ames Research Center and by Christos Zoulas.
11*d64c9d94Stom  *
12*d64c9d94Stom  * Redistribution and use in source and binary forms, with or without
13*d64c9d94Stom  * modification, are permitted provided that the following conditions
14*d64c9d94Stom  * are met:
15*d64c9d94Stom  * 1. Redistributions of source code must retain the above copyright
16*d64c9d94Stom  *    notice, this list of conditions and the following disclaimer.
17*d64c9d94Stom  * 2. Redistributions in binary form must reproduce the above copyright
18*d64c9d94Stom  *    notice, this list of conditions and the following disclaimer in the
19*d64c9d94Stom  *    documentation and/or other materials provided with the distribution.
20*d64c9d94Stom  * 3. All advertising materials mentioning features or use of this software
21*d64c9d94Stom  *    must display the following acknowledgement:
22*d64c9d94Stom  *	This product includes software developed by the NetBSD
23*d64c9d94Stom  *	Foundation, Inc. and its contributors.
24*d64c9d94Stom  * 4. Neither the name of The NetBSD Foundation nor the names of its
25*d64c9d94Stom  *    contributors may be used to endorse or promote products derived
26*d64c9d94Stom  *    from this software without specific prior written permission.
27*d64c9d94Stom  *
28*d64c9d94Stom  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29*d64c9d94Stom  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30*d64c9d94Stom  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31*d64c9d94Stom  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32*d64c9d94Stom  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33*d64c9d94Stom  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34*d64c9d94Stom  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35*d64c9d94Stom  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36*d64c9d94Stom  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37*d64c9d94Stom  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38*d64c9d94Stom  * POSSIBILITY OF SUCH DAMAGE.
39*d64c9d94Stom  */
40*d64c9d94Stom 
41*d64c9d94Stom /*
42*d64c9d94Stom  * Copyright (c) 1992, 1993
43*d64c9d94Stom  *	The Regents of the University of California.  All rights reserved.
44*d64c9d94Stom  *
45*d64c9d94Stom  * This code is derived from software contributed to Berkeley by
46*d64c9d94Stom  * Ralph Campbell.
47*d64c9d94Stom  *
48*d64c9d94Stom  * Redistribution and use in source and binary forms, with or without
49*d64c9d94Stom  * modification, are permitted provided that the following conditions
50*d64c9d94Stom  * are met:
51*d64c9d94Stom  * 1. Redistributions of source code must retain the above copyright
52*d64c9d94Stom  *    notice, this list of conditions and the following disclaimer.
53*d64c9d94Stom  * 2. Redistributions in binary form must reproduce the above copyright
54*d64c9d94Stom  *    notice, this list of conditions and the following disclaimer in the
55*d64c9d94Stom  *    documentation and/or other materials provided with the distribution.
56*d64c9d94Stom  * 3. Neither the name of the University nor the names of its contributors
57*d64c9d94Stom  *    may be used to endorse or promote products derived from this software
58*d64c9d94Stom  *    without specific prior written permission.
59*d64c9d94Stom  *
60*d64c9d94Stom  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
61*d64c9d94Stom  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62*d64c9d94Stom  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63*d64c9d94Stom  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
64*d64c9d94Stom  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
65*d64c9d94Stom  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
66*d64c9d94Stom  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67*d64c9d94Stom  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68*d64c9d94Stom  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69*d64c9d94Stom  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70*d64c9d94Stom  * SUCH DAMAGE.
71*d64c9d94Stom  *
72*d64c9d94Stom  *	@(#)boot.c	8.1 (Berkeley) 6/10/93
73*d64c9d94Stom  */
74*d64c9d94Stom 
75*d64c9d94Stom int ELFNAME(exec)(int, Elf_Ehdr *, u_long *, int);
76*d64c9d94Stom 
77*d64c9d94Stom int
78*d64c9d94Stom ELFNAME(exec)(int fd, Elf_Ehdr *elf, u_long *marks, int flags)
79*d64c9d94Stom {
80*d64c9d94Stom 	Elf_Shdr *shp;
81*d64c9d94Stom 	Elf_Phdr *phdr;
82*d64c9d94Stom 	Elf_Off off;
83*d64c9d94Stom 	int i;
84*d64c9d94Stom 	size_t sz;
85*d64c9d94Stom 	int first;
86*d64c9d94Stom 	int havesyms;
87*d64c9d94Stom 	paddr_t minp = ~0, maxp = 0, pos = 0;
88*d64c9d94Stom 	paddr_t offset = marks[MARK_START], shpp, elfp;
89*d64c9d94Stom 
90*d64c9d94Stom 	sz = elf->e_phnum * sizeof(Elf_Phdr);
91*d64c9d94Stom 	phdr = ALLOC(sz);
92*d64c9d94Stom 
93*d64c9d94Stom 	if (lseek(fd, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
94*d64c9d94Stom 		WARN(("lseek phdr"));
95*d64c9d94Stom 		FREE(phdr, sz);
96*d64c9d94Stom 		return 1;
97*d64c9d94Stom 	}
98*d64c9d94Stom 	if (read(fd, phdr, sz) != sz) {
99*d64c9d94Stom 		WARN(("read program headers"));
100*d64c9d94Stom 		FREE(phdr, sz);
101*d64c9d94Stom 		return 1;
102*d64c9d94Stom 	}
103*d64c9d94Stom 
104*d64c9d94Stom 	for (first = 1, i = 0; i < elf->e_phnum; i++) {
105*d64c9d94Stom 
106*d64c9d94Stom 		if (phdr[i].p_type != PT_LOAD ||
107*d64c9d94Stom 		    (phdr[i].p_flags & (PF_W|PF_R|PF_X)) == 0)
108*d64c9d94Stom 			continue;
109*d64c9d94Stom 
110*d64c9d94Stom #define IS_TEXT(p)	(p.p_flags & PF_X)
111*d64c9d94Stom #define IS_DATA(p)	((p.p_flags & PF_X) == 0)
112*d64c9d94Stom #define IS_BSS(p)	(p.p_filesz < p.p_memsz)
113*d64c9d94Stom 		/*
114*d64c9d94Stom 		 * XXX: Assume first address is lowest
115*d64c9d94Stom 		 */
116*d64c9d94Stom 		if ((IS_TEXT(phdr[i]) && (flags & LOAD_TEXT)) ||
117*d64c9d94Stom 		    (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
118*d64c9d94Stom 
119*d64c9d94Stom 			/* Read in segment. */
120*d64c9d94Stom 			PROGRESS(("%s%lu", first ? "" : "+",
121*d64c9d94Stom 			    (u_long)phdr[i].p_filesz));
122*d64c9d94Stom 
123*d64c9d94Stom 			if (lseek(fd, (off_t)phdr[i].p_offset, SEEK_SET) == -1)  {
124*d64c9d94Stom 				WARN(("lseek text"));
125*d64c9d94Stom 				FREE(phdr, sz);
126*d64c9d94Stom 				return 1;
127*d64c9d94Stom 			}
128*d64c9d94Stom 			if (READ(fd, phdr[i].p_vaddr, phdr[i].p_filesz) !=
129*d64c9d94Stom 			    phdr[i].p_filesz) {
130*d64c9d94Stom 				WARN(("read text"));
131*d64c9d94Stom 				FREE(phdr, sz);
132*d64c9d94Stom 				return 1;
133*d64c9d94Stom 			}
134*d64c9d94Stom 			first = 0;
135*d64c9d94Stom 
136*d64c9d94Stom 		}
137*d64c9d94Stom 		if ((IS_TEXT(phdr[i]) && (flags & (LOAD_TEXT|COUNT_TEXT))) ||
138*d64c9d94Stom 		    (IS_DATA(phdr[i]) && (flags & (LOAD_DATA|COUNT_TEXT)))) {
139*d64c9d94Stom 			pos = phdr[i].p_vaddr;
140*d64c9d94Stom 			if (minp > pos)
141*d64c9d94Stom 				minp = pos;
142*d64c9d94Stom 			pos += phdr[i].p_filesz;
143*d64c9d94Stom 			if (maxp < pos)
144*d64c9d94Stom 				maxp = pos;
145*d64c9d94Stom 		}
146*d64c9d94Stom 
147*d64c9d94Stom 		/* Zero out bss. */
148*d64c9d94Stom 		if (IS_BSS(phdr[i]) && (flags & LOAD_BSS)) {
149*d64c9d94Stom 			PROGRESS(("+%lu",
150*d64c9d94Stom 			    (u_long)(phdr[i].p_memsz - phdr[i].p_filesz)));
151*d64c9d94Stom 			BZERO((phdr[i].p_vaddr + phdr[i].p_filesz),
152*d64c9d94Stom 			    phdr[i].p_memsz - phdr[i].p_filesz);
153*d64c9d94Stom 		}
154*d64c9d94Stom 		if (IS_BSS(phdr[i]) && (flags & (LOAD_BSS|COUNT_BSS))) {
155*d64c9d94Stom 			pos += phdr[i].p_memsz - phdr[i].p_filesz;
156*d64c9d94Stom 			if (maxp < pos)
157*d64c9d94Stom 				maxp = pos;
158*d64c9d94Stom 		}
159*d64c9d94Stom 	}
160*d64c9d94Stom 	FREE(phdr, sz);
161*d64c9d94Stom 
162*d64c9d94Stom 	/*
163*d64c9d94Stom 	 * Copy the ELF and section headers.
164*d64c9d94Stom 	 */
165*d64c9d94Stom 	elfp = maxp = roundup(maxp, sizeof(long));
166*d64c9d94Stom 	if (flags & (LOAD_HDR|COUNT_HDR))
167*d64c9d94Stom 		maxp += sizeof(Elf_Ehdr);
168*d64c9d94Stom 
169*d64c9d94Stom 	if (flags & (LOAD_SYM|COUNT_SYM)) {
170*d64c9d94Stom 		if (lseek(fd, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
171*d64c9d94Stom 			WARN(("lseek section headers"));
172*d64c9d94Stom 			return 1;
173*d64c9d94Stom 		}
174*d64c9d94Stom 		sz = elf->e_shnum * sizeof(Elf_Shdr);
175*d64c9d94Stom 		shp = ALLOC(sz);
176*d64c9d94Stom 
177*d64c9d94Stom 		if (read(fd, shp, sz) != sz) {
178*d64c9d94Stom 			WARN(("read section headers"));
179*d64c9d94Stom 			FREE(shp, sz);
180*d64c9d94Stom 			return 1;
181*d64c9d94Stom 		}
182*d64c9d94Stom 
183*d64c9d94Stom 		shpp = maxp;
184*d64c9d94Stom 		maxp += roundup(sz, sizeof(long));
185*d64c9d94Stom 
186*d64c9d94Stom 		/*
187*d64c9d94Stom 		 * Now load the symbol sections themselves.  Make sure the
188*d64c9d94Stom 		 * sections are aligned. Don't bother with string tables if
189*d64c9d94Stom 		 * there are no symbol sections.
190*d64c9d94Stom 		 */
191*d64c9d94Stom 		off = roundup((sizeof(Elf_Ehdr) + sz), sizeof(long));
192*d64c9d94Stom 
193*d64c9d94Stom 		for (havesyms = i = 0; i < elf->e_shnum; i++)
194*d64c9d94Stom 			if (shp[i].sh_type == SHT_SYMTAB)
195*d64c9d94Stom 				havesyms = 1;
196*d64c9d94Stom 
197*d64c9d94Stom 		for (first = 1, i = 0; i < elf->e_shnum; i++) {
198*d64c9d94Stom 			if (shp[i].sh_type == SHT_SYMTAB ||
199*d64c9d94Stom 			    shp[i].sh_type == SHT_STRTAB) {
200*d64c9d94Stom 				if (havesyms && (flags & LOAD_SYM)) {
201*d64c9d94Stom 					PROGRESS(("%s%ld", first ? " [" : "+",
202*d64c9d94Stom 					    (u_long)shp[i].sh_size));
203*d64c9d94Stom 					if (lseek(fd, (off_t)shp[i].sh_offset,
204*d64c9d94Stom 					    SEEK_SET) == -1) {
205*d64c9d94Stom 						WARN(("lseek symbols"));
206*d64c9d94Stom 						FREE(shp, sz);
207*d64c9d94Stom 						return 1;
208*d64c9d94Stom 					}
209*d64c9d94Stom 					if (READ(fd, maxp, shp[i].sh_size) !=
210*d64c9d94Stom 					    shp[i].sh_size) {
211*d64c9d94Stom 						WARN(("read symbols"));
212*d64c9d94Stom 						FREE(shp, sz);
213*d64c9d94Stom 						return 1;
214*d64c9d94Stom 					}
215*d64c9d94Stom 				}
216*d64c9d94Stom 				maxp += roundup(shp[i].sh_size,
217*d64c9d94Stom 				    sizeof(long));
218*d64c9d94Stom 				shp[i].sh_offset = off;
219*d64c9d94Stom 				off += roundup(shp[i].sh_size, sizeof(long));
220*d64c9d94Stom 				first = 0;
221*d64c9d94Stom 			}
222*d64c9d94Stom 		}
223*d64c9d94Stom 		if (flags & LOAD_SYM) {
224*d64c9d94Stom 			BCOPY(shp, shpp, sz);
225*d64c9d94Stom 
226*d64c9d94Stom 			if (havesyms && first == 0)
227*d64c9d94Stom 				PROGRESS(("]"));
228*d64c9d94Stom 		}
229*d64c9d94Stom 		FREE(shp, sz);
230*d64c9d94Stom 	}
231*d64c9d94Stom 
232*d64c9d94Stom 	/*
233*d64c9d94Stom 	 * Frob the copied ELF header to give information relative
234*d64c9d94Stom 	 * to elfp.
235*d64c9d94Stom 	 */
236*d64c9d94Stom 	if (flags & LOAD_HDR) {
237*d64c9d94Stom 		elf->e_phoff = 0;
238*d64c9d94Stom 		elf->e_shoff = sizeof(Elf_Ehdr);
239*d64c9d94Stom 		elf->e_phentsize = 0;
240*d64c9d94Stom 		elf->e_phnum = 0;
241*d64c9d94Stom 		BCOPY(elf, elfp, sizeof(*elf));
242*d64c9d94Stom 	}
243*d64c9d94Stom 
244*d64c9d94Stom 	marks[MARK_START] = LOADADDR(minp);
245*d64c9d94Stom 	marks[MARK_ENTRY] = LOADADDR(elf->e_entry);
246*d64c9d94Stom 	marks[MARK_NSYM] = 1;	/* XXX: Kernel needs >= 0 */
247*d64c9d94Stom 	marks[MARK_SYM] = LOADADDR(elfp);
248*d64c9d94Stom 	marks[MARK_END] = LOADADDR(maxp);
249*d64c9d94Stom 	return 0;
250*d64c9d94Stom }
251