xref: /freebsd/sys/i386/i386/elf_machdep.c (revision 53b70c86)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright 1996-1998 John D. Polstra.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include "opt_cpu.h"
32 
33 #include <sys/param.h>
34 #include <sys/kernel.h>
35 #include <sys/systm.h>
36 #include <sys/exec.h>
37 #include <sys/imgact.h>
38 #include <sys/linker.h>
39 #include <sys/proc.h>
40 #include <sys/sysent.h>
41 #include <sys/imgact_elf.h>
42 #include <sys/syscall.h>
43 #include <sys/signalvar.h>
44 #include <sys/vnode.h>
45 
46 #include <vm/vm.h>
47 #include <vm/pmap.h>
48 #include <vm/vm_param.h>
49 
50 #include <machine/elf.h>
51 #include <machine/md_var.h>
52 #include <machine/npx.h>
53 
54 struct sysentvec elf32_freebsd_sysvec = {
55 	.sv_size	= SYS_MAXSYSCALL,
56 	.sv_table	= sysent,
57 	.sv_transtrap	= NULL,
58 	.sv_fixup	= __elfN(freebsd_fixup),
59 	.sv_sendsig	= sendsig,
60 	.sv_sigcode	= sigcode,
61 	.sv_szsigcode	= &szsigcode,
62 	.sv_name	= "FreeBSD ELF32",
63 	.sv_coredump	= __elfN(coredump),
64 	.sv_elf_core_osabi = ELFOSABI_FREEBSD,
65 	.sv_elf_core_abi_vendor = FREEBSD_ABI_VENDOR,
66 	.sv_elf_core_prepare_notes = __elfN(prepare_notes),
67 	.sv_imgact_try	= NULL,
68 	.sv_minsigstksz	= MINSIGSTKSZ,
69 	.sv_minuser	= VM_MIN_ADDRESS,
70 	.sv_maxuser	= VM_MAXUSER_ADDRESS,
71 	.sv_usrstack	= USRSTACK,
72 	.sv_psstrings	= PS_STRINGS,
73 	.sv_stackprot	= VM_PROT_ALL,
74 	.sv_copyout_auxargs = __elfN(freebsd_copyout_auxargs),
75 	.sv_copyout_strings	= exec_copyout_strings,
76 	.sv_setregs	= exec_setregs,
77 	.sv_fixlimit	= NULL,
78 	.sv_maxssiz	= NULL,
79 	.sv_flags	= SV_ABI_FREEBSD | SV_ASLR | SV_IA32 | SV_ILP32 |
80 			    SV_SHP | SV_TIMEKEEP | SV_RNG_SEED_VER,
81 	.sv_set_syscall_retval = cpu_set_syscall_retval,
82 	.sv_fetch_syscall_args = cpu_fetch_syscall_args,
83 	.sv_syscallnames = syscallnames,
84 	.sv_shared_page_base = SHAREDPAGE,
85 	.sv_shared_page_len = PAGE_SIZE,
86 	.sv_schedtail	= NULL,
87 	.sv_thread_detach = NULL,
88 	.sv_trap	= NULL,
89 	.sv_onexec_old	= exec_onexec_old,
90 	.sv_onexit	= exit_onexit,
91 	.sv_set_fork_retval = x86_set_fork_retval,
92 };
93 INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec);
94 
95 static Elf32_Brandinfo freebsd_brand_info = {
96 	.brand		= ELFOSABI_FREEBSD,
97 	.machine	= EM_386,
98 	.compat_3_brand	= "FreeBSD",
99 	.emul_path	= NULL,
100 	.interp_path	= "/libexec/ld-elf.so.1",
101 	.sysvec		= &elf32_freebsd_sysvec,
102 	.interp_newpath	= NULL,
103 	.brand_note	= &elf32_freebsd_brandnote,
104 	.flags		= BI_CAN_EXEC_DYN | BI_BRAND_NOTE
105 };
106 
107 SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_FIRST,
108 	(sysinit_cfunc_t) elf32_insert_brand_entry,
109 	&freebsd_brand_info);
110 
111 static Elf32_Brandinfo freebsd_brand_oinfo = {
112 	.brand		= ELFOSABI_FREEBSD,
113 	.machine	= EM_386,
114 	.compat_3_brand	= "FreeBSD",
115 	.emul_path	= NULL,
116 	.interp_path	= "/usr/libexec/ld-elf.so.1",
117 	.sysvec		= &elf32_freebsd_sysvec,
118 	.interp_newpath	= NULL,
119 	.brand_note	= &elf32_freebsd_brandnote,
120 	.flags		= BI_CAN_EXEC_DYN | BI_BRAND_NOTE
121 };
122 
123 SYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_ANY,
124 	(sysinit_cfunc_t) elf32_insert_brand_entry,
125 	&freebsd_brand_oinfo);
126 
127 static Elf32_Brandinfo kfreebsd_brand_info = {
128 	.brand		= ELFOSABI_FREEBSD,
129 	.machine	= EM_386,
130 	.compat_3_brand	= "FreeBSD",
131 	.emul_path	= NULL,
132 	.interp_path	= "/lib/ld.so.1",
133 	.sysvec		= &elf32_freebsd_sysvec,
134 	.interp_newpath	= NULL,
135 	.brand_note	= &elf32_kfreebsd_brandnote,
136 	.flags		= BI_CAN_EXEC_DYN | BI_BRAND_NOTE_MANDATORY
137 };
138 
139 SYSINIT(kelf32, SI_SUB_EXEC, SI_ORDER_ANY,
140 	(sysinit_cfunc_t) elf32_insert_brand_entry,
141 	&kfreebsd_brand_info);
142 
143 void
144 elf32_dump_thread(struct thread *td, void *dst, size_t *off)
145 {
146 	void *buf;
147 	size_t len;
148 
149 	len = 0;
150 	if (use_xsave) {
151 		if (dst != NULL) {
152 			npxgetregs(td);
153 			len += elf32_populate_note(NT_X86_XSTATE,
154 			    get_pcb_user_save_td(td), dst,
155 			    cpu_max_ext_state_size, &buf);
156 			*(uint64_t *)((char *)buf + X86_XSTATE_XCR0_OFFSET) =
157 			    xsave_mask;
158 		} else
159 			len += elf32_populate_note(NT_X86_XSTATE, NULL, NULL,
160 			    cpu_max_ext_state_size, NULL);
161 	}
162 	*off = len;
163 }
164 
165 bool
166 elf_is_ifunc_reloc(Elf_Size r_info)
167 {
168 
169 	return (ELF_R_TYPE(r_info) == R_386_IRELATIVE);
170 }
171 
172 #define	ERI_LOCAL	0x0001
173 
174 /* Process one elf relocation with addend. */
175 static int
176 elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
177     int type, elf_lookup_fn lookup, int flags)
178 {
179 	Elf_Addr *where;
180 	Elf_Addr addr;
181 	Elf_Addr addend;
182 	Elf_Word rtype, symidx;
183 	const Elf_Rel *rel;
184 	const Elf_Rela *rela;
185 	int error;
186 
187 	switch (type) {
188 	case ELF_RELOC_REL:
189 		rel = (const Elf_Rel *)data;
190 		where = (Elf_Addr *) (relocbase + rel->r_offset);
191 		addend = *where;
192 		rtype = ELF_R_TYPE(rel->r_info);
193 		symidx = ELF_R_SYM(rel->r_info);
194 		break;
195 	case ELF_RELOC_RELA:
196 		rela = (const Elf_Rela *)data;
197 		where = (Elf_Addr *) (relocbase + rela->r_offset);
198 		addend = rela->r_addend;
199 		rtype = ELF_R_TYPE(rela->r_info);
200 		symidx = ELF_R_SYM(rela->r_info);
201 		break;
202 	default:
203 		panic("unknown reloc type %d\n", type);
204 	}
205 
206 	if ((flags & ERI_LOCAL) != 0) {
207 		if (rtype == R_386_RELATIVE) {	/* A + B */
208 			addr = elf_relocaddr(lf, relocbase + addend);
209 			if (*where != addr)
210 				*where = addr;
211 		}
212 		return (0);
213 	}
214 
215 	switch (rtype) {
216 		case R_386_NONE:	/* none */
217 			break;
218 
219 		case R_386_32:		/* S + A */
220 			error = lookup(lf, symidx, 1, &addr);
221 			if (error != 0)
222 				return (-1);
223 			addr += addend;
224 			if (*where != addr)
225 				*where = addr;
226 			break;
227 
228 		case R_386_PC32:	/* S + A - P */
229 			error = lookup(lf, symidx, 1, &addr);
230 			if (error != 0)
231 				return (-1);
232 			addr += addend - (Elf_Addr)where;
233 			if (*where != addr)
234 				*where = addr;
235 			break;
236 
237 		case R_386_COPY:	/* none */
238 			/*
239 			 * There shouldn't be copy relocations in kernel
240 			 * objects.
241 			 */
242 			printf("kldload: unexpected R_COPY relocation, "
243 			    "symbol index %d\n", symidx);
244 			return (-1);
245 			break;
246 
247 		case R_386_GLOB_DAT:	/* S */
248 			error = lookup(lf, symidx, 1, &addr);
249 			if (error != 0)
250 				return (-1);
251 			if (*where != addr)
252 				*where = addr;
253 			break;
254 
255 		case R_386_RELATIVE:
256 			break;
257 
258 		case R_386_IRELATIVE:
259 			addr = relocbase + addend;
260 			addr = ((Elf_Addr (*)(void))addr)();
261 			if (*where != addr)
262 				*where = addr;
263 			break;
264 
265 		default:
266 			printf("kldload: unexpected relocation type %d, "
267 			    "symbol index %d\n", rtype, symidx);
268 			return (-1);
269 	}
270 	return(0);
271 }
272 
273 int
274 elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
275     elf_lookup_fn lookup)
276 {
277 
278 	return (elf_reloc_internal(lf, relocbase, data, type, lookup, 0));
279 }
280 
281 int
282 elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data,
283     int type, elf_lookup_fn lookup)
284 {
285 
286 	return (elf_reloc_internal(lf, relocbase, data, type, lookup,
287 	    ERI_LOCAL));
288 }
289 
290 int
291 elf_cpu_load_file(linker_file_t lf __unused)
292 {
293 
294 	return (0);
295 }
296 
297 int
298 elf_cpu_unload_file(linker_file_t lf __unused)
299 {
300 
301 	return (0);
302 }
303 
304 int
305 elf_cpu_parse_dynamic(caddr_t loadbase __unused, Elf_Dyn *dynamic __unused)
306 {
307 
308 	return (0);
309 }
310