xref: /freebsd/libexec/rtld-elf/i386/reloc.c (revision 78b5dadb58e201e51a3a2eda5cf8cab6d31e0b62)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright 1996, 1997, 1998, 1999 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 /*
29  * Dynamic linker for ELF.
30  *
31  * John Polstra <jdp@polstra.com>.
32  */
33 
34 #include <sys/param.h>
35 #include <sys/mman.h>
36 
37 #include <machine/segments.h>
38 #include <machine/sysarch.h>
39 
40 #include <dlfcn.h>
41 #include <err.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <stdarg.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
49 
50 #include "debug.h"
51 #include "rtld.h"
52 #include "rtld_tls.h"
53 
54 /*
55  * Process the special R_386_COPY relocations in the main program.  These
56  * copy data from a shared object into a region in the main program's BSS
57  * segment.
58  *
59  * Returns 0 on success, -1 on failure.
60  */
61 int
do_copy_relocations(Obj_Entry * dstobj)62 do_copy_relocations(Obj_Entry *dstobj)
63 {
64 	const Elf_Rel *rellim;
65 	const Elf_Rel *rel;
66 
67 	assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */
68 
69 	rellim = (const Elf_Rel *)((const char *)dstobj->rel + dstobj->relsize);
70 	for (rel = dstobj->rel; rel < rellim; rel++) {
71 		if (ELF_R_TYPE(rel->r_info) == R_386_COPY) {
72 			void *dstaddr;
73 			const Elf_Sym *dstsym;
74 			const char *name;
75 			size_t size;
76 			const void *srcaddr;
77 			const Elf_Sym *srcsym;
78 			const Obj_Entry *srcobj, *defobj;
79 			SymLook req;
80 			int res;
81 
82 			dstaddr = (void *)(dstobj->relocbase + rel->r_offset);
83 			dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
84 			name = dstobj->strtab + dstsym->st_name;
85 			size = dstsym->st_size;
86 			symlook_init(&req, name);
87 			req.ventry = fetch_ventry(dstobj,
88 			    ELF_R_SYM(rel->r_info));
89 			req.flags = SYMLOOK_EARLY;
90 
91 			for (srcobj = globallist_next(dstobj); srcobj != NULL;
92 			    srcobj = globallist_next(srcobj)) {
93 				res = symlook_obj(&req, srcobj);
94 				if (res == 0) {
95 					srcsym = req.sym_out;
96 					defobj = req.defobj_out;
97 					break;
98 				}
99 			}
100 
101 			if (srcobj == NULL) {
102 				_rtld_error(
103 			    "Undefined symbol \"%s\" referenced from COPY"
104 				    " relocation in %s",
105 				    name, dstobj->path);
106 				return (-1);
107 			}
108 
109 			srcaddr = (const void *)(defobj->relocbase +
110 			    srcsym->st_value);
111 			memcpy(dstaddr, srcaddr, size);
112 		}
113 	}
114 
115 	return (0);
116 }
117 
118 /* Initialize the special GOT entries. */
119 void
init_pltgot(Obj_Entry * obj)120 init_pltgot(Obj_Entry *obj)
121 {
122 	if (obj->pltgot != NULL) {
123 		obj->pltgot[1] = (Elf_Addr)obj;
124 		obj->pltgot[2] = (Elf_Addr)&_rtld_bind_start;
125 	}
126 }
127 
128 /* Process the non-PLT relocations. */
129 int
reloc_non_plt(Obj_Entry * obj,Obj_Entry * obj_rtld,int flags,RtldLockState * lockstate)130 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
131     RtldLockState *lockstate)
132 {
133 	const Elf_Rel *rellim;
134 	const Elf_Rel *rel;
135 	SymCache *cache;
136 	const Elf_Sym *def;
137 	const Obj_Entry *defobj;
138 	Elf_Addr *where, symval, add;
139 	int r;
140 
141 	r = -1;
142 	/*
143 	 * The dynamic loader may be called from a thread, we have
144 	 * limited amounts of stack available so we cannot use alloca().
145 	 */
146 	if (obj != obj_rtld) {
147 		cache = calloc(obj->dynsymcount, sizeof(SymCache));
148 		/* No need to check for NULL here */
149 	} else {
150 		cache = NULL;
151 	}
152 
153 	/* Appease some compilers. */
154 	symval = 0;
155 	def = NULL;
156 
157 	rellim = (const Elf_Rel *)((const char *)obj->rel + obj->relsize);
158 	for (rel = obj->rel; rel < rellim; rel++) {
159 		switch (ELF_R_TYPE(rel->r_info)) {
160 		case R_386_32:
161 		case R_386_PC32:
162 		case R_386_GLOB_DAT:
163 		case R_386_TLS_TPOFF:
164 		case R_386_TLS_TPOFF32:
165 		case R_386_TLS_DTPMOD32:
166 		case R_386_TLS_DTPOFF32:
167 			def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
168 			    flags, cache, lockstate);
169 			if (def == NULL)
170 				goto done;
171 			if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
172 				switch (ELF_R_TYPE(rel->r_info)) {
173 				case R_386_32:
174 				case R_386_PC32:
175 				case R_386_GLOB_DAT:
176 					if ((flags & SYMLOOK_IFUNC) == 0) {
177 						obj->non_plt_gnu_ifunc = true;
178 						continue;
179 					}
180 					symval = (Elf_Addr)
181 					    rtld_resolve_ifunc(defobj, def);
182 					break;
183 				case R_386_TLS_TPOFF:
184 				case R_386_TLS_TPOFF32:
185 				case R_386_TLS_DTPMOD32:
186 				case R_386_TLS_DTPOFF32:
187 					_rtld_error("%s: IFUNC for TLS reloc",
188 					    obj->path);
189 					goto done;
190 				}
191 			} else {
192 				if ((flags & SYMLOOK_IFUNC) != 0)
193 					continue;
194 				symval = (Elf_Addr)defobj->relocbase +
195 				    def->st_value;
196 			}
197 			break;
198 		default:
199 			if ((flags & SYMLOOK_IFUNC) != 0)
200 				continue;
201 			break;
202 		}
203 		where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
204 
205 		switch (ELF_R_TYPE(rel->r_info)) {
206 		case R_386_NONE:
207 			break;
208 		case R_386_32:
209 			*where += symval;
210 			break;
211 		case R_386_PC32:
212 			/*
213 			 * I don't think the dynamic linker should ever
214 			 * see this type of relocation.  But the
215 			 * binutils-2.6 tools sometimes generate it.
216 			 */
217 			*where += symval - (Elf_Addr)where;
218 			break;
219 		case R_386_COPY:
220 			/*
221 			 * These are deferred until all other
222 			 * relocations have been done.  All we do here
223 			 * is make sure that the COPY relocation is
224 			 * not in a shared library.  They are allowed
225 			 * only in executable files.
226 			 */
227 			if (!obj->mainprog) {
228 				_rtld_error(
229 		"%s: Unexpected R_386_COPY relocation in shared library",
230 				    obj->path);
231 				goto done;
232 			}
233 			break;
234 		case R_386_GLOB_DAT:
235 			*where = symval;
236 			break;
237 		case R_386_RELATIVE:
238 			*where += (Elf_Addr)obj->relocbase;
239 			break;
240 		case R_386_TLS_TPOFF:
241 		case R_386_TLS_TPOFF32:
242 			/*
243 			 * We lazily allocate offsets for static TLS
244 			 * as we see the first relocation that
245 			 * references the TLS block. This allows us to
246 			 * support (small amounts of) static TLS in
247 			 * dynamically loaded modules. If we run out
248 			 * of space, we generate an error.
249 			 */
250 			if (!defobj->tls_static) {
251 				if (!allocate_tls_offset(
252 				    __DECONST(Obj_Entry *, defobj))) {
253 					_rtld_error(
254 		"%s: No space available for static Thread Local Storage",
255 					    obj->path);
256 					goto done;
257 				}
258 			}
259 			add = (Elf_Addr)(def->st_value - defobj->tlsoffset);
260 			if (ELF_R_TYPE(rel->r_info) == R_386_TLS_TPOFF)
261 				*where += add;
262 			else
263 				*where -= add;
264 			break;
265 		case R_386_TLS_DTPMOD32:
266 			*where += (Elf_Addr)defobj->tlsindex;
267 			break;
268 		case R_386_TLS_DTPOFF32:
269 			*where += (Elf_Addr)def->st_value;
270 			break;
271 		case R_386_IRELATIVE:
272 			obj->irelative_nonplt = true;
273 			break;
274 		default:
275 			_rtld_error(
276 		"%s: Unsupported relocation type %d in non-PLT relocations",
277 			    obj->path, ELF_R_TYPE(rel->r_info));
278 			goto done;
279 		}
280 	}
281 	r = 0;
282 done:
283 	free(cache);
284 	return (r);
285 }
286 
287 /* Process the PLT relocations. */
288 int
reloc_plt(Obj_Entry * obj,int flags __unused,RtldLockState * lockstate __unused)289 reloc_plt(Obj_Entry *obj, int flags __unused, RtldLockState *lockstate __unused)
290 {
291 	const Elf_Rel *rellim;
292 	const Elf_Rel *rel;
293 
294 	rellim = (const Elf_Rel *)((const char *)obj->pltrel + obj->pltrelsize);
295 	for (rel = obj->pltrel; rel < rellim; rel++) {
296 		Elf_Addr *where;
297 
298 		switch (ELF_R_TYPE(rel->r_info)) {
299 		case R_386_JMP_SLOT:
300 			/* Relocate the GOT slot pointing into the PLT. */
301 			where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
302 			*where += (Elf_Addr)obj->relocbase;
303 			break;
304 
305 		case R_386_IRELATIVE:
306 			obj->irelative = true;
307 			break;
308 
309 		default:
310 			_rtld_error("Unknown relocation type %x in PLT",
311 			    ELF_R_TYPE(rel->r_info));
312 			return (-1);
313 		}
314 	}
315 	return (0);
316 }
317 
318 /* Relocate the jump slots in an object. */
319 int
reloc_jmpslots(Obj_Entry * obj,int flags,RtldLockState * lockstate)320 reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
321 {
322 	const Elf_Rel *rellim;
323 	const Elf_Rel *rel;
324 
325 	if (obj->jmpslots_done)
326 		return (0);
327 	rellim = (const Elf_Rel *)((const char *)obj->pltrel + obj->pltrelsize);
328 	for (rel = obj->pltrel; rel < rellim; rel++) {
329 		Elf_Addr *where, target;
330 		const Elf_Sym *def;
331 		const Obj_Entry *defobj;
332 
333 		switch (ELF_R_TYPE(rel->r_info)) {
334 		case R_386_JMP_SLOT:
335 			where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
336 			def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
337 			    SYMLOOK_IN_PLT | flags, NULL, lockstate);
338 			if (def == NULL)
339 				return (-1);
340 			if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
341 				obj->gnu_ifunc = true;
342 				continue;
343 			}
344 			target = (Elf_Addr)(defobj->relocbase + def->st_value);
345 			reloc_jmpslot(where, target, defobj, obj, rel);
346 			break;
347 
348 		case R_386_IRELATIVE:
349 			break;
350 
351 		default:
352 			_rtld_error("Unknown relocation type %x in PLT",
353 			    ELF_R_TYPE(rel->r_info));
354 			return (-1);
355 		}
356 	}
357 
358 	obj->jmpslots_done = true;
359 	return (0);
360 }
361 
362 /* Fixup the jump slot at "where" to transfer control to "target". */
363 Elf_Addr
reloc_jmpslot(Elf_Addr * where,Elf_Addr target,const Obj_Entry * obj __unused,const Obj_Entry * refobj __unused,const Elf_Rel * rel __unused)364 reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *obj __unused,
365     const Obj_Entry *refobj __unused, const Elf_Rel *rel __unused)
366 {
367 	dbg("reloc_jmpslot: *%p = %p", where, (void *)target);
368 	if (!ld_bind_not)
369 		*where = target;
370 	return (target);
371 }
372 
373 static void
reloc_iresolve_one(Obj_Entry * obj,const Elf_Rel * rel,RtldLockState * lockstate)374 reloc_iresolve_one(Obj_Entry *obj, const Elf_Rel *rel, RtldLockState *lockstate)
375 {
376 	Elf_Addr *where, target;
377 
378 	where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
379 	lock_release(rtld_bind_lock, lockstate);
380 	target = call_ifunc_resolver(obj->relocbase + *where);
381 	wlock_acquire(rtld_bind_lock, lockstate);
382 	*where = target;
383 }
384 
385 int
reloc_iresolve(Obj_Entry * obj,RtldLockState * lockstate)386 reloc_iresolve(Obj_Entry *obj, RtldLockState *lockstate)
387 {
388 	const Elf_Rel *rellim;
389 	const Elf_Rel *rel;
390 
391 	if (!obj->irelative)
392 		return (0);
393 	obj->irelative = false;
394 	rellim = (const Elf_Rel *)((const char *)obj->pltrel + obj->pltrelsize);
395 	for (rel = obj->pltrel; rel < rellim; rel++) {
396 		if (ELF_R_TYPE(rel->r_info) == R_386_IRELATIVE)
397 			reloc_iresolve_one(obj, rel, lockstate);
398 	}
399 	return (0);
400 }
401 
402 int
reloc_iresolve_nonplt(Obj_Entry * obj,RtldLockState * lockstate)403 reloc_iresolve_nonplt(Obj_Entry *obj, RtldLockState *lockstate)
404 {
405 	const Elf_Rel *rellim;
406 	const Elf_Rel *rel;
407 
408 	if (!obj->irelative_nonplt)
409 		return (0);
410 	obj->irelative_nonplt = false;
411 	rellim = (const Elf_Rel *)((const char *)obj->rel + obj->relsize);
412 	for (rel = obj->rel; rel < rellim; rel++) {
413 		if (ELF_R_TYPE(rel->r_info) == R_386_IRELATIVE)
414 			reloc_iresolve_one(obj, rel, lockstate);
415 	}
416 	return (0);
417 }
418 
419 int
reloc_gnu_ifunc(Obj_Entry * obj,int flags,RtldLockState * lockstate)420 reloc_gnu_ifunc(Obj_Entry *obj, int flags, RtldLockState *lockstate)
421 {
422 	const Elf_Rel *rellim;
423 	const Elf_Rel *rel;
424 
425 	if (!obj->gnu_ifunc)
426 		return (0);
427 	rellim = (const Elf_Rel *)((const char *)obj->pltrel + obj->pltrelsize);
428 	for (rel = obj->pltrel; rel < rellim; rel++) {
429 		Elf_Addr *where, target;
430 		const Elf_Sym *def;
431 		const Obj_Entry *defobj;
432 
433 		switch (ELF_R_TYPE(rel->r_info)) {
434 		case R_386_JMP_SLOT:
435 			where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
436 			def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
437 			    SYMLOOK_IN_PLT | flags, NULL, lockstate);
438 			if (def == NULL)
439 				return (-1);
440 			if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC)
441 				continue;
442 			lock_release(rtld_bind_lock, lockstate);
443 			target = (Elf_Addr)rtld_resolve_ifunc(defobj, def);
444 			wlock_acquire(rtld_bind_lock, lockstate);
445 			reloc_jmpslot(where, target, defobj, obj, rel);
446 			break;
447 		}
448 	}
449 
450 	obj->gnu_ifunc = false;
451 	return (0);
452 }
453 
454 uint32_t cpu_feature, cpu_feature2, cpu_stdext_feature, cpu_stdext_feature2;
455 
456 static void
rtld_cpuid_count(int idx,int cnt,u_int * p)457 rtld_cpuid_count(int idx, int cnt, u_int *p)
458 {
459 	__asm __volatile(
460 	    "	pushl	%%ebx\n"
461 	    "	cpuid\n"
462 	    "	movl	%%ebx,%1\n"
463 	    "	popl	%%ebx\n"
464 	    : "=a"(p[0]), "=r"(p[1]), "=c"(p[2]), "=d"(p[3])
465 	    : "0"(idx), "2"(cnt));
466 }
467 
468 void
ifunc_init(Elf_Auxinfo * aux_info[__min_size (AT_COUNT)]__unused)469 ifunc_init(Elf_Auxinfo *aux_info[__min_size(AT_COUNT)] __unused)
470 {
471 	u_int p[4], cpu_high;
472 	int cpuid_supported;
473 
474 	__asm __volatile(
475 	    "	pushfl\n"
476 	    "	popl	%%eax\n"
477 	    "	movl    %%eax,%%ecx\n"
478 	    "	xorl    $0x200000,%%eax\n"
479 	    "	pushl	%%eax\n"
480 	    "	popfl\n"
481 	    "	pushfl\n"
482 	    "	popl    %%eax\n"
483 	    "	xorl    %%eax,%%ecx\n"
484 	    "	je	1f\n"
485 	    "	movl	$1,%0\n"
486 	    "	jmp	2f\n"
487 	    "1:	movl	$0,%0\n"
488 	    "2:\n"
489 	    : "=r"(cpuid_supported)
490 	    :
491 	    : "eax", "ecx");
492 	if (!cpuid_supported)
493 		return;
494 
495 	rtld_cpuid_count(1, 0, p);
496 	cpu_feature = p[3];
497 	cpu_feature2 = p[2];
498 	rtld_cpuid_count(0, 0, p);
499 	cpu_high = p[0];
500 	if (cpu_high >= 7) {
501 		rtld_cpuid_count(7, 0, p);
502 		cpu_stdext_feature = p[1];
503 		cpu_stdext_feature2 = p[2];
504 	}
505 }
506 
507 void
allocate_initial_tls(Obj_Entry * objs)508 allocate_initial_tls(Obj_Entry *objs)
509 {
510 	void *tls;
511 
512 	/*
513 	 * Fix the size of the static TLS block by using the maximum
514 	 * offset allocated so far and adding a bit for dynamic modules to
515 	 * use.
516 	 */
517 	tls_static_space = tls_last_offset + ld_static_tls_extra;
518 	tls = allocate_tls(objs, NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN);
519 	_tcb_set(tls);
520 }
521 
522 /* GNU ABI */
523 __attribute__((__regparm__(1))) void *
___tls_get_addr(tls_index * ti)524 ___tls_get_addr(tls_index *ti)
525 {
526 	uintptr_t **dtvp;
527 
528 	dtvp = &_tcb_get()->tcb_dtv;
529 	return (tls_get_addr_common(dtvp, ti->ti_module, ti->ti_offset));
530 }
531 
532 /* Sun ABI */
533 void *
__tls_get_addr(tls_index * ti)534 __tls_get_addr(tls_index *ti)
535 {
536 	uintptr_t **dtvp;
537 
538 	dtvp = &_tcb_get()->tcb_dtv;
539 	return (tls_get_addr_common(dtvp, ti->ti_module, ti->ti_offset));
540 }
541 
542 size_t
calculate_tls_offset(size_t prev_offset,size_t prev_size __unused,size_t size,size_t align,size_t offset)543 calculate_tls_offset(size_t prev_offset, size_t prev_size __unused, size_t size,
544     size_t align, size_t offset)
545 {
546 	size_t res;
547 
548 	/*
549 	 * res is the smallest integer satisfying res - prev_offset >= size
550 	 * and (-res) % p_align = p_vaddr % p_align (= p_offset % p_align).
551 	 */
552 	res = prev_offset + size + align - 1;
553 	res -= (res + offset) & (align - 1);
554 	return (res);
555 }
556 
557 size_t
calculate_first_tls_offset(size_t size,size_t align,size_t offset)558 calculate_first_tls_offset(size_t size, size_t align, size_t offset)
559 {
560 	return (calculate_tls_offset(0, 0, size, align, offset));
561 }
562