xref: /freebsd/libexec/rtld-elf/powerpc64/reloc.c (revision 895f86f15fbf6540071feb9328c3c50ed1f027b8)
1 /*      $NetBSD: ppc_reloc.c,v 1.10 2001/09/10 06:09:41 mycroft Exp $   */
2 
3 /*-
4  * Copyright (C) 1998   Tsubai Masanari
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  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 
32 #include <sys/param.h>
33 #include <sys/mman.h>
34 
35 #include <errno.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <machine/cpu.h>
41 #include <machine/md_var.h>
42 
43 #include "debug.h"
44 #include "rtld.h"
45 
46 #if !defined(_CALL_ELF) || _CALL_ELF == 1
47 struct funcdesc {
48 	Elf_Addr addr;
49 	Elf_Addr toc;
50 	Elf_Addr env;
51 };
52 #endif
53 
54 /*
55  * Process the R_PPC_COPY relocations
56  */
57 int
58 do_copy_relocations(Obj_Entry *dstobj)
59 {
60 	const Elf_Rela *relalim;
61 	const Elf_Rela *rela;
62 
63 	/*
64 	 * COPY relocs are invalid outside of the main program
65 	 */
66 	assert(dstobj->mainprog);
67 
68 	relalim = (const Elf_Rela *) ((caddr_t) dstobj->rela +
69 	    dstobj->relasize);
70 	for (rela = dstobj->rela;  rela < relalim;  rela++) {
71 		void *dstaddr;
72 		const Elf_Sym *dstsym;
73 		const char *name;
74 		size_t size;
75 		const void *srcaddr;
76 		const Elf_Sym *srcsym = NULL;
77 		const Obj_Entry *srcobj, *defobj;
78 		SymLook req;
79 		int res;
80 
81 		if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) {
82 			continue;
83 		}
84 
85 		dstaddr = (void *) (dstobj->relocbase + rela->r_offset);
86 		dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
87 		name = dstobj->strtab + dstsym->st_name;
88 		size = dstsym->st_size;
89 		symlook_init(&req, name);
90 		req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
91 		req.flags = SYMLOOK_EARLY;
92 
93 		for (srcobj = dstobj->next;  srcobj != NULL;
94 		     srcobj = srcobj->next) {
95 			res = symlook_obj(&req, srcobj);
96 			if (res == 0) {
97 				srcsym = req.sym_out;
98 				defobj = req.defobj_out;
99 				break;
100 			}
101 		}
102 
103 		if (srcobj == NULL) {
104 			_rtld_error("Undefined symbol \"%s\" "
105 				    " referenced from COPY"
106 				    " relocation in %s", name, dstobj->path);
107 			return (-1);
108 		}
109 
110 		srcaddr = (const void *) (defobj->relocbase+srcsym->st_value);
111 		memcpy(dstaddr, srcaddr, size);
112 		dbg("copy_reloc: src=%p,dst=%p,size=%zd\n",srcaddr,dstaddr,size);
113 	}
114 
115 	return (0);
116 }
117 
118 
119 /*
120  * Perform early relocation of the run-time linker image
121  */
122 void
123 reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
124 {
125 	const Elf_Rela *rela = 0, *relalim;
126 	Elf_Addr relasz = 0;
127 	Elf_Addr *where;
128 
129 	/*
130 	 * Extract the rela/relasz values from the dynamic section
131 	 */
132 	for (; dynp->d_tag != DT_NULL; dynp++) {
133 		switch (dynp->d_tag) {
134 		case DT_RELA:
135 			rela = (const Elf_Rela *)(relocbase+dynp->d_un.d_ptr);
136 			break;
137 		case DT_RELASZ:
138 			relasz = dynp->d_un.d_val;
139 			break;
140 		}
141 	}
142 
143 	/*
144 	 * Relocate these values
145 	 */
146 	relalim = (const Elf_Rela *)((caddr_t)rela + relasz);
147 	for (; rela < relalim; rela++) {
148 		where = (Elf_Addr *)(relocbase + rela->r_offset);
149 		*where = (Elf_Addr)(relocbase + rela->r_addend);
150 	}
151 }
152 
153 
154 /*
155  * Relocate a non-PLT object with addend.
156  */
157 static int
158 reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
159     SymCache *cache, int flags, RtldLockState *lockstate)
160 {
161 	Elf_Addr        *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
162 	const Elf_Sym   *def;
163 	const Obj_Entry *defobj;
164 	Elf_Addr         tmp;
165 
166 	switch (ELF_R_TYPE(rela->r_info)) {
167 
168 	case R_PPC_NONE:
169 		break;
170 
171         case R_PPC64_UADDR64:    /* doubleword64 S + A */
172         case R_PPC64_ADDR64:
173         case R_PPC_GLOB_DAT:
174 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
175 		    flags, cache, lockstate);
176 		if (def == NULL) {
177 			return (-1);
178 		}
179 
180                 tmp = (Elf_Addr)(defobj->relocbase + def->st_value +
181                     rela->r_addend);
182 
183 		/* Don't issue write if unnecessary; avoid COW page fault */
184                 if (*where != tmp) {
185                         *where = tmp;
186 		}
187                 break;
188 
189         case R_PPC_RELATIVE:  /* doubleword64 B + A */
190 		tmp = (Elf_Addr)(obj->relocbase + rela->r_addend);
191 
192 		/* As above, don't issue write unnecessarily */
193 		if (*where != tmp) {
194 			*where = tmp;
195 		}
196 		break;
197 
198 	case R_PPC_COPY:
199 		/*
200 		 * These are deferred until all other relocations
201 		 * have been done.  All we do here is make sure
202 		 * that the COPY relocation is not in a shared
203 		 * library.  They are allowed only in executable
204 		 * files.
205 		 */
206 		if (!obj->mainprog) {
207 			_rtld_error("%s: Unexpected R_COPY "
208 				    " relocation in shared library",
209 				    obj->path);
210 			return (-1);
211 		}
212 		break;
213 
214 	case R_PPC_JMP_SLOT:
215 		/*
216 		 * These will be handled by the plt/jmpslot routines
217 		 */
218 		break;
219 
220 	case R_PPC64_DTPMOD64:
221 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
222 		    flags, cache, lockstate);
223 
224 		if (def == NULL)
225 			return (-1);
226 
227 		*where = (Elf_Addr) defobj->tlsindex;
228 
229 		break;
230 
231 	case R_PPC64_TPREL64:
232 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
233 		    flags, cache, lockstate);
234 
235 		if (def == NULL)
236 			return (-1);
237 
238 		/*
239 		 * We lazily allocate offsets for static TLS as we
240 		 * see the first relocation that references the
241 		 * TLS block. This allows us to support (small
242 		 * amounts of) static TLS in dynamically loaded
243 		 * modules. If we run out of space, we generate an
244 		 * error.
245 		 */
246 		if (!defobj->tls_done) {
247 			if (!allocate_tls_offset((Obj_Entry*) defobj)) {
248 				_rtld_error("%s: No space available for static "
249 				    "Thread Local Storage", obj->path);
250 				return (-1);
251 			}
252 		}
253 
254 		*(Elf_Addr **)where = *where * sizeof(Elf_Addr)
255 		    + (Elf_Addr *)(def->st_value + rela->r_addend
256 		    + defobj->tlsoffset - TLS_TP_OFFSET);
257 
258 		break;
259 
260 	case R_PPC64_DTPREL64:
261 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
262 		    flags, cache, lockstate);
263 
264 		if (def == NULL)
265 			return (-1);
266 
267 		*where += (Elf_Addr)(def->st_value + rela->r_addend
268 		    - TLS_DTV_OFFSET);
269 
270 		break;
271 
272 	default:
273 		_rtld_error("%s: Unsupported relocation type %ld"
274 			    " in non-PLT relocations\n", obj->path,
275 			    ELF_R_TYPE(rela->r_info));
276 		return (-1);
277         }
278 	return (0);
279 }
280 
281 
282 /*
283  * Process non-PLT relocations
284  */
285 int
286 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
287     RtldLockState *lockstate)
288 {
289 	const Elf_Rela *relalim;
290 	const Elf_Rela *rela;
291 	SymCache *cache;
292 	int bytes = obj->dynsymcount * sizeof(SymCache);
293 	int r = -1;
294 
295 	if ((flags & SYMLOOK_IFUNC) != 0)
296 		/* XXX not implemented */
297 		return (0);
298 
299 	/*
300 	 * The dynamic loader may be called from a thread, we have
301 	 * limited amounts of stack available so we cannot use alloca().
302 	 */
303 	if (obj != obj_rtld) {
304 		cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON,
305 		    -1, 0);
306 		if (cache == MAP_FAILED)
307 			cache = NULL;
308 	} else
309 		cache = NULL;
310 
311 	/*
312 	 * From the SVR4 PPC ABI:
313 	 * "The PowerPC family uses only the Elf32_Rela relocation
314 	 *  entries with explicit addends."
315 	 */
316 	relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize);
317 	for (rela = obj->rela; rela < relalim; rela++) {
318 		if (reloc_nonplt_object(obj_rtld, obj, rela, cache, flags,
319 		    lockstate) < 0)
320 			goto done;
321 	}
322 	r = 0;
323 done:
324 	if (cache)
325 		munmap(cache, bytes);
326 
327 	/* Synchronize icache for text seg in case we made any changes */
328 	__syncicache(obj->mapbase, obj->textsize);
329 
330 	return (r);
331 }
332 
333 
334 /*
335  * Initialise a PLT slot to the resolving trampoline
336  */
337 static int
338 reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela)
339 {
340 	Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
341 #if !defined(_CALL_ELF) || _CALL_ELF == 1
342 	Elf_Addr *glink;
343 #endif
344 	long reloff;
345 
346 	reloff = rela - obj->pltrela;
347 
348 #if !defined(_CALL_ELF) || _CALL_ELF == 1
349 	if (obj->priv == NULL)
350 		obj->priv = xmalloc(obj->pltrelasize);
351 	glink = obj->priv + reloff*sizeof(Elf_Addr)*2;
352 
353 	dbg(" reloc_plt_object: where=%p,reloff=%lx,glink=%p", (void *)where, reloff, glink);
354 
355 	memcpy(where, _rtld_bind_start, sizeof(struct funcdesc));
356 	((struct funcdesc *)(where))->env = (Elf_Addr)glink;
357 	*(glink++) = (Elf_Addr)obj;
358 	*(glink++) = reloff*sizeof(Elf_Rela);
359 #else
360 	dbg(" reloc_plt_object: where=%p,reloff=%lx,glink=%#lx", (void *)where, reloff, obj->glink);
361 	*where = (Elf_Addr)obj->glink + 4*reloff + 32;
362 #endif
363 
364 	return (0);
365 }
366 
367 
368 /*
369  * Process the PLT relocations.
370  */
371 int
372 reloc_plt(Obj_Entry *obj)
373 {
374 	const Elf_Rela *relalim;
375 	const Elf_Rela *rela;
376 
377 	if (obj->pltrelasize != 0) {
378 		relalim = (const Elf_Rela *)((char *)obj->pltrela +
379 		    obj->pltrelasize);
380 		for (rela = obj->pltrela;  rela < relalim;  rela++) {
381 			assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
382 
383 			if (reloc_plt_object(obj, rela) < 0) {
384 				return (-1);
385 			}
386 		}
387 	}
388 
389 	return (0);
390 }
391 
392 
393 /*
394  * LD_BIND_NOW was set - force relocation for all jump slots
395  */
396 int
397 reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
398 {
399 	const Obj_Entry *defobj;
400 	const Elf_Rela *relalim;
401 	const Elf_Rela *rela;
402 	const Elf_Sym *def;
403 	Elf_Addr *where;
404 	Elf_Addr target;
405 
406 	relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
407 	for (rela = obj->pltrela; rela < relalim; rela++) {
408 		assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
409 		where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
410 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
411 		    SYMLOOK_IN_PLT | flags, NULL, lockstate);
412 		if (def == NULL) {
413 			dbg("reloc_jmpslots: sym not found");
414 			return (-1);
415 		}
416 
417 		target = (Elf_Addr)(defobj->relocbase + def->st_value);
418 
419 #if 0
420 		/* PG XXX */
421 		dbg("\"%s\" in \"%s\" --> %p in \"%s\"",
422 		    defobj->strtab + def->st_name, basename(obj->path),
423 		    (void *)target, basename(defobj->path));
424 #endif
425 
426 		if (def == &sym_zero) {
427 			/* Zero undefined weak symbols */
428 #if !defined(_CALL_ELF) || _CALL_ELF == 1
429 			bzero(where, sizeof(struct funcdesc));
430 #else
431 			*where = 0;
432 #endif
433 		} else {
434 			reloc_jmpslot(where, target, defobj, obj,
435 			    (const Elf_Rel *) rela);
436 		}
437 	}
438 
439 	obj->jmpslots_done = true;
440 
441 	return (0);
442 }
443 
444 
445 /*
446  * Update the value of a PLT jump slot.
447  */
448 Elf_Addr
449 reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj,
450 	      const Obj_Entry *obj, const Elf_Rel *rel)
451 {
452 
453 	/*
454 	 * At the PLT entry pointed at by `wherep', construct
455 	 * a direct transfer to the now fully resolved function
456 	 * address.
457 	 */
458 
459 #if !defined(_CALL_ELF) || _CALL_ELF == 1
460 	dbg(" reloc_jmpslot: where=%p, target=%p (%#lx + %#lx)",
461 	    (void *)wherep, (void *)target, *(Elf_Addr *)target,
462 	    (Elf_Addr)defobj->relocbase);
463 
464 	memcpy(wherep, (void *)target, sizeof(struct funcdesc));
465 	if (((struct funcdesc *)(wherep))->addr < (Elf_Addr)defobj->relocbase) {
466 		/*
467 		 * XXX: It is possible (e.g. LD_BIND_NOW) that the function
468 		 * descriptor we are copying has not yet been relocated.
469 		 * If this happens, fix it.
470 		 */
471 
472 		((struct funcdesc *)(wherep))->addr +=
473 		    (Elf_Addr)defobj->relocbase;
474 		((struct funcdesc *)(wherep))->toc +=
475 		    (Elf_Addr)defobj->relocbase;
476 	}
477 #else
478 	dbg(" reloc_jmpslot: where=%p, target=%p", (void *)wherep,
479 	    (void *)target);
480 
481 	*wherep = target;
482 #endif
483 
484 	__asm __volatile("sync" ::: "memory");
485 
486 	return (target);
487 }
488 
489 int
490 reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
491 {
492 
493 	/* XXX not implemented */
494 	return (0);
495 }
496 
497 int
498 reloc_gnu_ifunc(Obj_Entry *obj, int flags,
499     struct Struct_RtldLockState *lockstate)
500 {
501 
502 	/* XXX not implemented */
503 	return (0);
504 }
505 
506 void
507 init_pltgot(Obj_Entry *obj)
508 {
509 #if defined(_CALL_ELF) && _CALL_ELF == 2
510 	Elf_Addr *pltcall;
511 
512 	pltcall = obj->pltgot;
513 
514 	if (pltcall == NULL) {
515 		return;
516 	}
517 
518 	pltcall[0] = (Elf_Addr)&_rtld_bind_start;
519 	pltcall[1] = (Elf_Addr)obj;
520 
521 	__asm __volatile("sync" ::: "memory");
522 #endif
523 }
524 
525 void
526 allocate_initial_tls(Obj_Entry *list)
527 {
528 	Elf_Addr **tp;
529 
530 	/*
531 	* Fix the size of the static TLS block by using the maximum
532 	* offset allocated so far and adding a bit for dynamic modules to
533 	* use.
534 	*/
535 
536 	tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA;
537 
538 	tp = (Elf_Addr **) ((char *)allocate_tls(list, NULL, TLS_TCB_SIZE, 16)
539 	    + TLS_TP_OFFSET + TLS_TCB_SIZE);
540 
541 	__asm __volatile("mr 13,%0" :: "r"(tp));
542 }
543 
544 void*
545 __tls_get_addr(tls_index* ti)
546 {
547 	Elf_Addr **tp;
548 	char *p;
549 
550 	__asm __volatile("mr %0,13" : "=r"(tp));
551 	p = tls_get_addr_common((Elf_Addr**)((Elf_Addr)tp - TLS_TP_OFFSET
552 	    - TLS_TCB_SIZE), ti->ti_module, ti->ti_offset);
553 
554 	return (p + TLS_DTV_OFFSET);
555 }
556