xref: /openbsd-src/sys/lib/libsa/loadfile_elf.c (revision 174697beef01c2f6add49ad98dbc1dc953740c31)
1d64c9d94Stom /* $NetBSD: loadfile.c,v 1.10 2000/12/03 02:53:04 tsutsui Exp $ */
2*174697beSvisa /* $OpenBSD: loadfile_elf.c,v 1.17 2020/10/26 04:04:31 visa Exp $ */
3d64c9d94Stom 
4d64c9d94Stom /*-
5d64c9d94Stom  * Copyright (c) 1997 The NetBSD Foundation, Inc.
6d64c9d94Stom  * All rights reserved.
7d64c9d94Stom  *
8d64c9d94Stom  * This code is derived from software contributed to The NetBSD Foundation
9d64c9d94Stom  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10d64c9d94Stom  * NASA Ames Research Center and by Christos Zoulas.
11d64c9d94Stom  *
12d64c9d94Stom  * Redistribution and use in source and binary forms, with or without
13d64c9d94Stom  * modification, are permitted provided that the following conditions
14d64c9d94Stom  * are met:
15d64c9d94Stom  * 1. Redistributions of source code must retain the above copyright
16d64c9d94Stom  *    notice, this list of conditions and the following disclaimer.
17d64c9d94Stom  * 2. Redistributions in binary form must reproduce the above copyright
18d64c9d94Stom  *    notice, this list of conditions and the following disclaimer in the
19d64c9d94Stom  *    documentation and/or other materials provided with the distribution.
20d64c9d94Stom  *
21d64c9d94Stom  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22d64c9d94Stom  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23d64c9d94Stom  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24d64c9d94Stom  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25d64c9d94Stom  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26d64c9d94Stom  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27d64c9d94Stom  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28d64c9d94Stom  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29d64c9d94Stom  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30d64c9d94Stom  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31d64c9d94Stom  * POSSIBILITY OF SUCH DAMAGE.
32d64c9d94Stom  */
33d64c9d94Stom 
34d64c9d94Stom /*
35d64c9d94Stom  * Copyright (c) 1992, 1993
36d64c9d94Stom  *	The Regents of the University of California.  All rights reserved.
37d64c9d94Stom  *
38d64c9d94Stom  * This code is derived from software contributed to Berkeley by
39d64c9d94Stom  * Ralph Campbell.
40d64c9d94Stom  *
41d64c9d94Stom  * Redistribution and use in source and binary forms, with or without
42d64c9d94Stom  * modification, are permitted provided that the following conditions
43d64c9d94Stom  * are met:
44d64c9d94Stom  * 1. Redistributions of source code must retain the above copyright
45d64c9d94Stom  *    notice, this list of conditions and the following disclaimer.
46d64c9d94Stom  * 2. Redistributions in binary form must reproduce the above copyright
47d64c9d94Stom  *    notice, this list of conditions and the following disclaimer in the
48d64c9d94Stom  *    documentation and/or other materials provided with the distribution.
49d64c9d94Stom  * 3. Neither the name of the University nor the names of its contributors
50d64c9d94Stom  *    may be used to endorse or promote products derived from this software
51d64c9d94Stom  *    without specific prior written permission.
52d64c9d94Stom  *
53d64c9d94Stom  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54d64c9d94Stom  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55d64c9d94Stom  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56d64c9d94Stom  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57d64c9d94Stom  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58d64c9d94Stom  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59d64c9d94Stom  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60d64c9d94Stom  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61d64c9d94Stom  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62d64c9d94Stom  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63d64c9d94Stom  * SUCH DAMAGE.
64d64c9d94Stom  *
65d64c9d94Stom  *	@(#)boot.c	8.1 (Berkeley) 6/10/93
66d64c9d94Stom  */
67d64c9d94Stom 
68f65494e6Sderaadt #include <lib/libsa/arc4.h>
69f65494e6Sderaadt 
702340cfa5Sderaadt int ELFNAME(exec)(int, Elf_Ehdr *, uint64_t *, int);
71d64c9d94Stom 
72d64c9d94Stom int
ELFNAME(exec)732340cfa5Sderaadt ELFNAME(exec)(int fd, Elf_Ehdr *elf, uint64_t *marks, int flags)
74d64c9d94Stom {
75d64c9d94Stom 	Elf_Shdr *shp;
76d64c9d94Stom 	Elf_Phdr *phdr;
77d64c9d94Stom 	Elf_Off off;
78d64c9d94Stom 	int i;
79d64c9d94Stom 	size_t sz;
80d64c9d94Stom 	int first;
81*174697beSvisa 	int havesyms;
82d64c9d94Stom 	paddr_t minp = ~0, maxp = 0, pos = 0;
83d64c9d94Stom 	paddr_t offset = marks[MARK_START], shpp, elfp;
84d64c9d94Stom 
85d64c9d94Stom 	sz = elf->e_phnum * sizeof(Elf_Phdr);
86d64c9d94Stom 	phdr = ALLOC(sz);
87d64c9d94Stom 
88d64c9d94Stom 	if (lseek(fd, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
89d64c9d94Stom 		WARN(("lseek phdr"));
90d64c9d94Stom 		FREE(phdr, sz);
91d64c9d94Stom 		return 1;
92d64c9d94Stom 	}
93d64c9d94Stom 	if (read(fd, phdr, sz) != sz) {
94d64c9d94Stom 		WARN(("read program headers"));
95d64c9d94Stom 		FREE(phdr, sz);
96d64c9d94Stom 		return 1;
97d64c9d94Stom 	}
98d64c9d94Stom 
99d64c9d94Stom 	for (first = 1, i = 0; i < elf->e_phnum; i++) {
1002afebeaeSderaadt 		if (phdr[i].p_type == PT_OPENBSD_RANDOMIZE) {
1012afebeaeSderaadt 
10232ab6324Smiod 			/* Fill segment if asked for. */
103cd230c96Smiod 			if (flags & LOAD_RANDOM) {
104f65494e6Sderaadt 				extern struct rc4_ctx randomctx;
105f65494e6Sderaadt 
106f65494e6Sderaadt 				rc4_getbytes(&randomctx,
107f65494e6Sderaadt 				    (void *)LOADADDR(phdr[i].p_paddr),
108f65494e6Sderaadt 				    phdr[i].p_filesz);
1092afebeaeSderaadt 			}
110cd230c96Smiod 			if (flags & (LOAD_RANDOM | COUNT_RANDOM)) {
111cd230c96Smiod 				marks[MARK_RANDOM] = LOADADDR(phdr[i].p_paddr);
112cd230c96Smiod 				marks[MARK_ERANDOM] =
113cd230c96Smiod 				    marks[MARK_RANDOM] + phdr[i].p_filesz;
114cd230c96Smiod 			}
1152afebeaeSderaadt 			continue;
1162afebeaeSderaadt 		}
1172afebeaeSderaadt 
118d64c9d94Stom 		if (phdr[i].p_type != PT_LOAD ||
119d64c9d94Stom 		    (phdr[i].p_flags & (PF_W|PF_R|PF_X)) == 0)
120d64c9d94Stom 			continue;
121d64c9d94Stom 
122a19592f3Smiod #ifdef CHECK_PHDR
123a19592f3Smiod 		if (CHECK_PHDR(ELFSIZE, &phdr[i])) {
124a19592f3Smiod 			FREE(phdr, sz);
125a19592f3Smiod 			return 1;
126a19592f3Smiod 		}
127a19592f3Smiod #endif
128a19592f3Smiod 
129d64c9d94Stom #define IS_TEXT(p)	(p.p_flags & PF_X)
130d64c9d94Stom #define IS_DATA(p)	((p.p_flags & PF_X) == 0)
131d64c9d94Stom #define IS_BSS(p)	(p.p_filesz < p.p_memsz)
132d64c9d94Stom 		/*
133d64c9d94Stom 		 * XXX: Assume first address is lowest
134d64c9d94Stom 		 */
135d64c9d94Stom 		if ((IS_TEXT(phdr[i]) && (flags & LOAD_TEXT)) ||
136d64c9d94Stom 		    (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
137d64c9d94Stom 
138d64c9d94Stom 			/* Read in segment. */
139d64c9d94Stom 			PROGRESS(("%s%lu", first ? "" : "+",
140d64c9d94Stom 			    (u_long)phdr[i].p_filesz));
141d64c9d94Stom 
142d64c9d94Stom 			if (lseek(fd, (off_t)phdr[i].p_offset, SEEK_SET) == -1) {
143d64c9d94Stom 				WARN(("lseek text"));
144d64c9d94Stom 				FREE(phdr, sz);
145d64c9d94Stom 				return 1;
146d64c9d94Stom 			}
147e6e7289dSweingart 			if (READ(fd, phdr[i].p_paddr, phdr[i].p_filesz) !=
148d64c9d94Stom 			    phdr[i].p_filesz) {
149d64c9d94Stom 				WARN(("read text"));
150d64c9d94Stom 				FREE(phdr, sz);
151d64c9d94Stom 				return 1;
152d64c9d94Stom 			}
153d64c9d94Stom 
154975d1d82Sjsing 			first = 0;
155d64c9d94Stom 		}
156975d1d82Sjsing 
157d64c9d94Stom 		if ((IS_TEXT(phdr[i]) && (flags & (LOAD_TEXT | COUNT_TEXT))) ||
158d64c9d94Stom 		    (IS_DATA(phdr[i]) && (flags & (LOAD_DATA | COUNT_TEXT)))) {
159e6e7289dSweingart 			pos = phdr[i].p_paddr;
160d64c9d94Stom 			if (minp > pos)
161d64c9d94Stom 				minp = pos;
162d64c9d94Stom 			pos += phdr[i].p_filesz;
163d64c9d94Stom 			if (maxp < pos)
164d64c9d94Stom 				maxp = pos;
165d64c9d94Stom 		}
166d64c9d94Stom 
167975d1d82Sjsing 		/* Zero out BSS. */
168d64c9d94Stom 		if (IS_BSS(phdr[i]) && (flags & LOAD_BSS)) {
169d64c9d94Stom 			PROGRESS(("+%lu",
170d64c9d94Stom 			    (u_long)(phdr[i].p_memsz - phdr[i].p_filesz)));
171e6e7289dSweingart 			BZERO((phdr[i].p_paddr + phdr[i].p_filesz),
172d64c9d94Stom 			    phdr[i].p_memsz - phdr[i].p_filesz);
173d64c9d94Stom 		}
174d64c9d94Stom 		if (IS_BSS(phdr[i]) && (flags & (LOAD_BSS|COUNT_BSS))) {
175d64c9d94Stom 			pos += phdr[i].p_memsz - phdr[i].p_filesz;
176d64c9d94Stom 			if (maxp < pos)
177d64c9d94Stom 				maxp = pos;
178d64c9d94Stom 		}
179d64c9d94Stom 	}
180d64c9d94Stom 	FREE(phdr, sz);
181d64c9d94Stom 
182d64c9d94Stom 	/*
183d64c9d94Stom 	 * Copy the ELF and section headers.
184d64c9d94Stom 	 */
1851db65b31Sjsing 	elfp = maxp = roundup(maxp, sizeof(Elf_Addr));
186d64c9d94Stom 	if (flags & (LOAD_HDR | COUNT_HDR))
187d64c9d94Stom 		maxp += sizeof(Elf_Ehdr);
188d64c9d94Stom 
189d64c9d94Stom 	if (flags & (LOAD_SYM | COUNT_SYM)) {
190d64c9d94Stom 		if (lseek(fd, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
191d64c9d94Stom 			WARN(("lseek section headers"));
192d64c9d94Stom 			return 1;
193d64c9d94Stom 		}
194d64c9d94Stom 		sz = elf->e_shnum * sizeof(Elf_Shdr);
195d64c9d94Stom 		shp = ALLOC(sz);
196d64c9d94Stom 
197d64c9d94Stom 		if (read(fd, shp, sz) != sz) {
198d64c9d94Stom 			WARN(("read section headers"));
199d64c9d94Stom 			FREE(shp, sz);
200d64c9d94Stom 			return 1;
201d64c9d94Stom 		}
202d64c9d94Stom 
203d64c9d94Stom 		shpp = maxp;
2041db65b31Sjsing 		maxp += roundup(sz, sizeof(Elf_Addr));
205d64c9d94Stom 
2064d814044Smatthew 		size_t shstrsz = shp[elf->e_shstrndx].sh_size;
2074d814044Smatthew 		char *shstr = ALLOC(shstrsz);
2084d814044Smatthew 		if (lseek(fd, (off_t)shp[elf->e_shstrndx].sh_offset, SEEK_SET) == -1) {
2094d814044Smatthew 			WARN(("lseek section header string table"));
2104d814044Smatthew 			FREE(shstr, shstrsz);
2114d814044Smatthew 			FREE(shp, sz);
2124d814044Smatthew 			return 1;
2134d814044Smatthew 		}
2144bae614aSmiod 		if (read(fd, shstr, shstrsz) != shstrsz) {
2154d814044Smatthew 			WARN(("read section header string table"));
2164d814044Smatthew 			FREE(shstr, shstrsz);
2174d814044Smatthew 			FREE(shp, sz);
2184d814044Smatthew 			return 1;
2194d814044Smatthew 		}
2204d814044Smatthew 
221d64c9d94Stom 		/*
222d64c9d94Stom 		 * Now load the symbol sections themselves. Make sure the
223d64c9d94Stom 		 * sections are aligned. Don't bother with string tables if
224d64c9d94Stom 		 * there are no symbol sections.
225d64c9d94Stom 		 */
2261db65b31Sjsing 		off = roundup((sizeof(Elf_Ehdr) + sz), sizeof(Elf_Addr));
227d64c9d94Stom 
228*174697beSvisa 		for (havesyms = i = 0; i < elf->e_shnum; i++)
229d64c9d94Stom 			if (shp[i].sh_type == SHT_SYMTAB)
230d64c9d94Stom 				havesyms = 1;
231d64c9d94Stom 
232d64c9d94Stom 		for (first = 1, i = 0; i < elf->e_shnum; i++) {
233d64c9d94Stom 			if (shp[i].sh_type == SHT_SYMTAB ||
2344d814044Smatthew 			    shp[i].sh_type == SHT_STRTAB ||
235330b5787Sjasper 			    !strcmp(shstr + shp[i].sh_name, ".debug_line") ||
23672123b7dSjasper 			    !strcmp(shstr + shp[i].sh_name, ELF_CTF)) {
237d64c9d94Stom 				if (havesyms && (flags & LOAD_SYM)) {
238d64c9d94Stom 					PROGRESS(("%s%ld", first ? " [" : "+",
239d64c9d94Stom 					    (u_long)shp[i].sh_size));
240d64c9d94Stom 					if (lseek(fd, (off_t)shp[i].sh_offset,
241d64c9d94Stom 					    SEEK_SET) == -1) {
242d64c9d94Stom 						WARN(("lseek symbols"));
2434d814044Smatthew 						FREE(shstr, shstrsz);
244d64c9d94Stom 						FREE(shp, sz);
245d64c9d94Stom 						return 1;
246d64c9d94Stom 					}
247d64c9d94Stom 					if (READ(fd, maxp, shp[i].sh_size) !=
248d64c9d94Stom 					    shp[i].sh_size) {
249d64c9d94Stom 						WARN(("read symbols"));
2504d814044Smatthew 						FREE(shstr, shstrsz);
251d64c9d94Stom 						FREE(shp, sz);
252d64c9d94Stom 						return 1;
253d64c9d94Stom 					}
254d64c9d94Stom 				}
255d64c9d94Stom 				maxp += roundup(shp[i].sh_size,
2561db65b31Sjsing 				    sizeof(Elf_Addr));
257d64c9d94Stom 				shp[i].sh_offset = off;
2584d814044Smatthew 				shp[i].sh_flags |= SHF_ALLOC;
2591db65b31Sjsing 				off += roundup(shp[i].sh_size, sizeof(Elf_Addr));
260d64c9d94Stom 				first = 0;
261d64c9d94Stom 			}
262d64c9d94Stom 		}
263d64c9d94Stom 		if (flags & LOAD_SYM) {
264d64c9d94Stom 			BCOPY(shp, shpp, sz);
265d64c9d94Stom 
266d64c9d94Stom 			if (havesyms && first == 0)
267d64c9d94Stom 				PROGRESS(("]"));
268d64c9d94Stom 		}
2694d814044Smatthew 		FREE(shstr, shstrsz);
270d64c9d94Stom 		FREE(shp, sz);
271d64c9d94Stom 	}
272d64c9d94Stom 
273d64c9d94Stom 	/*
274d64c9d94Stom 	 * Frob the copied ELF header to give information relative
275d64c9d94Stom 	 * to elfp.
276d64c9d94Stom 	 */
277d64c9d94Stom 	if (flags & LOAD_HDR) {
278d64c9d94Stom 		elf->e_phoff = 0;
279d64c9d94Stom 		elf->e_shoff = sizeof(Elf_Ehdr);
280d64c9d94Stom 		elf->e_phentsize = 0;
281d64c9d94Stom 		elf->e_phnum = 0;
282d64c9d94Stom 		BCOPY(elf, elfp, sizeof(*elf));
283d64c9d94Stom 	}
284d64c9d94Stom 
285d64c9d94Stom 	marks[MARK_START] = LOADADDR(minp);
286d64c9d94Stom 	marks[MARK_ENTRY] = LOADADDR(elf->e_entry);
28793448402Skettenis 	marks[MARK_VENTRY] = elf->e_entry;
288d64c9d94Stom 	marks[MARK_NSYM] = 1;	/* XXX: Kernel needs >= 0 */
289d64c9d94Stom 	marks[MARK_SYM] = LOADADDR(elfp);
290d64c9d94Stom 	marks[MARK_END] = LOADADDR(maxp);
291975d1d82Sjsing 
292d64c9d94Stom 	return 0;
293d64c9d94Stom }
294