xref: /freebsd/libexec/rtld-elf/powerpc/reloc.c (revision b9dea67fa8c1d0fb1988526e32ca43a946abcca4)
1b9dea67fSPeter Grehan /*      $NetBSD: ppc_reloc.c,v 1.10 2001/09/10 06:09:41 mycroft Exp $   */
2b9dea67fSPeter Grehan 
3b9dea67fSPeter Grehan /*-
4b9dea67fSPeter Grehan  * Copyright (C) 1998   Tsubai Masanari
5b9dea67fSPeter Grehan  * All rights reserved.
6b9dea67fSPeter Grehan  *
7b9dea67fSPeter Grehan  * Redistribution and use in source and binary forms, with or without
8b9dea67fSPeter Grehan  * modification, are permitted provided that the following conditions
9b9dea67fSPeter Grehan  * are met:
10b9dea67fSPeter Grehan  * 1. Redistributions of source code must retain the above copyright
11b9dea67fSPeter Grehan  *    notice, this list of conditions and the following disclaimer.
12b9dea67fSPeter Grehan  * 2. Redistributions in binary form must reproduce the above copyright
13b9dea67fSPeter Grehan  *    notice, this list of conditions and the following disclaimer in the
14b9dea67fSPeter Grehan  *    documentation and/or other materials provided with the distribution.
15b9dea67fSPeter Grehan  * 3. The name of the author may not be used to endorse or promote products
16b9dea67fSPeter Grehan  *    derived from this software without specific prior written permission.
17b9dea67fSPeter Grehan  *
18b9dea67fSPeter Grehan  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19b9dea67fSPeter Grehan  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20b9dea67fSPeter Grehan  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21b9dea67fSPeter Grehan  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22b9dea67fSPeter Grehan  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23b9dea67fSPeter Grehan  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24b9dea67fSPeter Grehan  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25b9dea67fSPeter Grehan  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26b9dea67fSPeter Grehan  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27b9dea67fSPeter Grehan  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28b9dea67fSPeter Grehan  *
29b9dea67fSPeter Grehan  * $FreeBSD$
30b9dea67fSPeter Grehan  */
31b9dea67fSPeter Grehan 
32b9dea67fSPeter Grehan #include <sys/param.h>
33b9dea67fSPeter Grehan #include <sys/mman.h>
34b9dea67fSPeter Grehan 
35b9dea67fSPeter Grehan #include <errno.h>
36b9dea67fSPeter Grehan #include <stdio.h>
37b9dea67fSPeter Grehan #include <stdlib.h>
38b9dea67fSPeter Grehan #include <string.h>
39b9dea67fSPeter Grehan #include <unistd.h>
40b9dea67fSPeter Grehan #include <machine/cpu.h>
41b9dea67fSPeter Grehan 
42b9dea67fSPeter Grehan #include "debug.h"
43b9dea67fSPeter Grehan #include "rtld.h"
44b9dea67fSPeter Grehan 
45b9dea67fSPeter Grehan #define _ppc_ha(x) ((((u_int32_t)(x) & 0x8000) ? \
46b9dea67fSPeter Grehan                         ((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16)
47b9dea67fSPeter Grehan #define _ppc_la(x) ((u_int32_t)(x) & 0xffff)
48b9dea67fSPeter Grehan 
49b9dea67fSPeter Grehan /*
50b9dea67fSPeter Grehan  * Process the R_PPC_COPY relocations
51b9dea67fSPeter Grehan  */
52b9dea67fSPeter Grehan int
53b9dea67fSPeter Grehan do_copy_relocations(Obj_Entry *dstobj)
54b9dea67fSPeter Grehan {
55b9dea67fSPeter Grehan 	const Elf_Rela *relalim;
56b9dea67fSPeter Grehan 	const Elf_Rela *rela;
57b9dea67fSPeter Grehan 
58b9dea67fSPeter Grehan 	/*
59b9dea67fSPeter Grehan 	 * COPY relocs are invalid outside of the main program
60b9dea67fSPeter Grehan 	 */
61b9dea67fSPeter Grehan 	assert(dstobj->mainprog);
62b9dea67fSPeter Grehan 
63b9dea67fSPeter Grehan 	relalim = (const Elf_Rela *) ((caddr_t) dstobj->rela +
64b9dea67fSPeter Grehan 	    dstobj->relasize);
65b9dea67fSPeter Grehan 	for (rela = dstobj->rela;  rela < relalim;  rela++) {
66b9dea67fSPeter Grehan 		void *dstaddr;
67b9dea67fSPeter Grehan 		const Elf_Sym *dstsym;
68b9dea67fSPeter Grehan 		const char *name;
69b9dea67fSPeter Grehan 		unsigned long hash;
70b9dea67fSPeter Grehan 		size_t size;
71b9dea67fSPeter Grehan 		const void *srcaddr;
72b9dea67fSPeter Grehan 		const Elf_Sym *srcsym = NULL;
73b9dea67fSPeter Grehan 		Obj_Entry *srcobj;
74b9dea67fSPeter Grehan 
75b9dea67fSPeter Grehan 		if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) {
76b9dea67fSPeter Grehan 			continue;
77b9dea67fSPeter Grehan 		}
78b9dea67fSPeter Grehan 
79b9dea67fSPeter Grehan 		dstaddr = (void *) (dstobj->relocbase + rela->r_offset);
80b9dea67fSPeter Grehan 		dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
81b9dea67fSPeter Grehan 		name = dstobj->strtab + dstsym->st_name;
82b9dea67fSPeter Grehan 		hash = elf_hash(name);
83b9dea67fSPeter Grehan 		size = dstsym->st_size;
84b9dea67fSPeter Grehan 
85b9dea67fSPeter Grehan 		for (srcobj = dstobj->next;  srcobj != NULL;
86b9dea67fSPeter Grehan 		     srcobj = srcobj->next) {
87b9dea67fSPeter Grehan 			if ((srcsym = symlook_obj(name, hash, srcobj, false))
88b9dea67fSPeter Grehan 			    != NULL) {
89b9dea67fSPeter Grehan 				break;
90b9dea67fSPeter Grehan 			}
91b9dea67fSPeter Grehan 		}
92b9dea67fSPeter Grehan 
93b9dea67fSPeter Grehan 		if (srcobj == NULL) {
94b9dea67fSPeter Grehan 			_rtld_error("Undefined symbol \"%s\" "
95b9dea67fSPeter Grehan 				    " referenced from COPY"
96b9dea67fSPeter Grehan 				    " relocation in %s", name, dstobj->path);
97b9dea67fSPeter Grehan 			return (-1);
98b9dea67fSPeter Grehan 		}
99b9dea67fSPeter Grehan 
100b9dea67fSPeter Grehan 		srcaddr = (const void *) (srcobj->relocbase+srcsym->st_value);
101b9dea67fSPeter Grehan 		memcpy(dstaddr, srcaddr, size);
102b9dea67fSPeter Grehan 		dbg("copy_reloc: src=%p,dst=%p,size=%d\n",srcaddr,dstaddr,size);
103b9dea67fSPeter Grehan 	}
104b9dea67fSPeter Grehan 
105b9dea67fSPeter Grehan 	return (0);
106b9dea67fSPeter Grehan }
107b9dea67fSPeter Grehan 
108b9dea67fSPeter Grehan 
109b9dea67fSPeter Grehan /*
110b9dea67fSPeter Grehan  * Perform early relocation of the run-time linker image
111b9dea67fSPeter Grehan  */
112b9dea67fSPeter Grehan void
113b9dea67fSPeter Grehan reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
114b9dea67fSPeter Grehan {
115b9dea67fSPeter Grehan 	const Elf_Rela *rela = 0, *relalim;
116b9dea67fSPeter Grehan 	Elf_Addr relasz = 0;
117b9dea67fSPeter Grehan 	Elf_Addr *where;
118b9dea67fSPeter Grehan 
119b9dea67fSPeter Grehan 	/*
120b9dea67fSPeter Grehan 	 * Extract the rela/relasz values from the dynamic section
121b9dea67fSPeter Grehan 	 */
122b9dea67fSPeter Grehan 	for (; dynp->d_tag != DT_NULL; dynp++) {
123b9dea67fSPeter Grehan 		switch (dynp->d_tag) {
124b9dea67fSPeter Grehan 		case DT_RELA:
125b9dea67fSPeter Grehan 			rela = (const Elf_Rela *)(relocbase+dynp->d_un.d_ptr);
126b9dea67fSPeter Grehan 			break;
127b9dea67fSPeter Grehan 		case DT_RELASZ:
128b9dea67fSPeter Grehan 			relasz = dynp->d_un.d_val;
129b9dea67fSPeter Grehan 			break;
130b9dea67fSPeter Grehan 		}
131b9dea67fSPeter Grehan 	}
132b9dea67fSPeter Grehan 
133b9dea67fSPeter Grehan 	/*
134b9dea67fSPeter Grehan 	 * Relocate these values
135b9dea67fSPeter Grehan 	 */
136b9dea67fSPeter Grehan 	relalim = (const Elf_Rela *)((caddr_t)rela + relasz);
137b9dea67fSPeter Grehan 	for (; rela < relalim; rela++) {
138b9dea67fSPeter Grehan 		where = (Elf_Addr *)(relocbase + rela->r_offset);
139b9dea67fSPeter Grehan 		*where = (Elf_Addr)(relocbase + rela->r_addend);
140b9dea67fSPeter Grehan 	}
141b9dea67fSPeter Grehan }
142b9dea67fSPeter Grehan 
143b9dea67fSPeter Grehan 
144b9dea67fSPeter Grehan /*
145b9dea67fSPeter Grehan  * Relocate a non-PLT object with addend.
146b9dea67fSPeter Grehan  */
147b9dea67fSPeter Grehan static int
148b9dea67fSPeter Grehan reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
149b9dea67fSPeter Grehan 		    SymCache *cache)
150b9dea67fSPeter Grehan {
151b9dea67fSPeter Grehan 	Elf_Addr        *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
152b9dea67fSPeter Grehan 	const Elf_Sym   *def;
153b9dea67fSPeter Grehan 	const Obj_Entry *defobj;
154b9dea67fSPeter Grehan 	Elf_Addr         tmp;
155b9dea67fSPeter Grehan 
156b9dea67fSPeter Grehan 	switch (ELF_R_TYPE(rela->r_info)) {
157b9dea67fSPeter Grehan 
158b9dea67fSPeter Grehan 	case R_PPC_NONE:
159b9dea67fSPeter Grehan 		break;
160b9dea67fSPeter Grehan 
161b9dea67fSPeter Grehan         case R_PPC_ADDR32:    /* word32 S + A */
162b9dea67fSPeter Grehan         case R_PPC_GLOB_DAT:  /* word32 S + A */
163b9dea67fSPeter Grehan 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
164b9dea67fSPeter Grehan 				  false, cache);
165b9dea67fSPeter Grehan 		if (def == NULL) {
166b9dea67fSPeter Grehan 			return (-1);
167b9dea67fSPeter Grehan 		}
168b9dea67fSPeter Grehan 
169b9dea67fSPeter Grehan                 tmp = (Elf_Addr)(defobj->relocbase + def->st_value +
170b9dea67fSPeter Grehan                     rela->r_addend);
171b9dea67fSPeter Grehan 
172b9dea67fSPeter Grehan 		/* Don't issue write if unnecessary; avoid COW page fault */
173b9dea67fSPeter Grehan                 if (*where != tmp) {
174b9dea67fSPeter Grehan                         *where = tmp;
175b9dea67fSPeter Grehan 		}
176b9dea67fSPeter Grehan                 break;
177b9dea67fSPeter Grehan 
178b9dea67fSPeter Grehan         case R_PPC_RELATIVE:  /* word32 B + A */
179b9dea67fSPeter Grehan 		tmp = (Elf_Addr)(obj->relocbase + rela->r_addend);
180b9dea67fSPeter Grehan 
181b9dea67fSPeter Grehan 		/* As above, don't issue write unnecessarily */
182b9dea67fSPeter Grehan 		if (*where != tmp) {
183b9dea67fSPeter Grehan 			*where = tmp;
184b9dea67fSPeter Grehan 		}
185b9dea67fSPeter Grehan 		break;
186b9dea67fSPeter Grehan 
187b9dea67fSPeter Grehan 	case R_PPC_COPY:
188b9dea67fSPeter Grehan 		/*
189b9dea67fSPeter Grehan 		 * These are deferred until all other relocations
190b9dea67fSPeter Grehan 		 * have been done.  All we do here is make sure
191b9dea67fSPeter Grehan 		 * that the COPY relocation is not in a shared
192b9dea67fSPeter Grehan 		 * library.  They are allowed only in executable
193b9dea67fSPeter Grehan 		 * files.
194b9dea67fSPeter Grehan 		 */
195b9dea67fSPeter Grehan 		if (!obj->mainprog) {
196b9dea67fSPeter Grehan 			_rtld_error("%s: Unexpected R_COPY "
197b9dea67fSPeter Grehan 				    " relocation in shared library",
198b9dea67fSPeter Grehan 				    obj->path);
199b9dea67fSPeter Grehan 			return (-1);
200b9dea67fSPeter Grehan 		}
201b9dea67fSPeter Grehan 		break;
202b9dea67fSPeter Grehan 
203b9dea67fSPeter Grehan 	case R_PPC_JMP_SLOT:
204b9dea67fSPeter Grehan 		/*
205b9dea67fSPeter Grehan 		 * These will be handled by the plt/jmpslot routines
206b9dea67fSPeter Grehan 		 */
207b9dea67fSPeter Grehan 		break;
208b9dea67fSPeter Grehan 
209b9dea67fSPeter Grehan 	default:
210b9dea67fSPeter Grehan 		_rtld_error("%s: Unsupported relocation type %d"
211b9dea67fSPeter Grehan 			    " in non-PLT relocations\n", obj->path,
212b9dea67fSPeter Grehan 			    ELF_R_TYPE(rela->r_info));
213b9dea67fSPeter Grehan 		return (-1);
214b9dea67fSPeter Grehan         }
215b9dea67fSPeter Grehan 	return (0);
216b9dea67fSPeter Grehan }
217b9dea67fSPeter Grehan 
218b9dea67fSPeter Grehan 
219b9dea67fSPeter Grehan /*
220b9dea67fSPeter Grehan  * Process non-PLT relocations
221b9dea67fSPeter Grehan  */
222b9dea67fSPeter Grehan int
223b9dea67fSPeter Grehan reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
224b9dea67fSPeter Grehan {
225b9dea67fSPeter Grehan 	const Elf_Rela *relalim;
226b9dea67fSPeter Grehan 	const Elf_Rela *rela;
227b9dea67fSPeter Grehan 	SymCache *cache;
228b9dea67fSPeter Grehan 	int bytes = obj->nchains * sizeof(SymCache);
229b9dea67fSPeter Grehan 	int r = -1;
230b9dea67fSPeter Grehan 
231b9dea67fSPeter Grehan 	/*
232b9dea67fSPeter Grehan 	 * The dynamic loader may be called from a thread, we have
233b9dea67fSPeter Grehan 	 * limited amounts of stack available so we cannot use alloca().
234b9dea67fSPeter Grehan 	 */
235b9dea67fSPeter Grehan 	cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
236b9dea67fSPeter Grehan 	if (cache == MAP_FAILED) {
237b9dea67fSPeter Grehan 		cache = NULL;
238b9dea67fSPeter Grehan 	}
239b9dea67fSPeter Grehan 	if (cache != NULL) {
240b9dea67fSPeter Grehan 		memset(cache, 0, obj->nchains * sizeof(SymCache));
241b9dea67fSPeter Grehan 	}
242b9dea67fSPeter Grehan 
243b9dea67fSPeter Grehan 	/*
244b9dea67fSPeter Grehan 	 * From the SVR4 PPC ABI:
245b9dea67fSPeter Grehan 	 * "The PowerPC family uses only the Elf32_Rela relocation
246b9dea67fSPeter Grehan 	 *  entries with explicit addends."
247b9dea67fSPeter Grehan 	 */
248b9dea67fSPeter Grehan 	relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize);
249b9dea67fSPeter Grehan 	for (rela = obj->rela; rela < relalim; rela++) {
250b9dea67fSPeter Grehan 		if (reloc_nonplt_object(obj_rtld, obj, rela, cache) < 0)
251b9dea67fSPeter Grehan 			goto done;
252b9dea67fSPeter Grehan 	}
253b9dea67fSPeter Grehan 	r = 0;
254b9dea67fSPeter Grehan done:
255b9dea67fSPeter Grehan 	if (cache) {
256b9dea67fSPeter Grehan 		munmap(cache, bytes);
257b9dea67fSPeter Grehan 	}
258b9dea67fSPeter Grehan 	return (r);
259b9dea67fSPeter Grehan }
260b9dea67fSPeter Grehan 
261b9dea67fSPeter Grehan 
262b9dea67fSPeter Grehan /*
263b9dea67fSPeter Grehan  * Initialise a PLT slot to the resolving trampoline
264b9dea67fSPeter Grehan  */
265b9dea67fSPeter Grehan static int
266b9dea67fSPeter Grehan reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela)
267b9dea67fSPeter Grehan {
268b9dea67fSPeter Grehan 	Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
269b9dea67fSPeter Grehan 	Elf_Addr *pltresolve;
270b9dea67fSPeter Grehan 	Elf_Addr distance;
271b9dea67fSPeter Grehan 	int reloff;
272b9dea67fSPeter Grehan 
273b9dea67fSPeter Grehan 	reloff = rela - obj->pltrela;
274b9dea67fSPeter Grehan 
275b9dea67fSPeter Grehan 	if ((reloff < 0) || (reloff >= 0x8000)) {
276b9dea67fSPeter Grehan 		return (-1);
277b9dea67fSPeter Grehan 	}
278b9dea67fSPeter Grehan 
279b9dea67fSPeter Grehan 	pltresolve = obj->pltgot + 8;
280b9dea67fSPeter Grehan 
281b9dea67fSPeter Grehan 	distance = (Elf_Addr)pltresolve - (Elf_Addr)(where + 1);
282b9dea67fSPeter Grehan 
283b9dea67fSPeter Grehan 	dbg(" reloc_plt_object: where=%p,pltres=%p,reloff=%x,distance=%x",
284b9dea67fSPeter Grehan 	    (void *)where, (void *)pltresolve, reloff, distance);
285b9dea67fSPeter Grehan 
286b9dea67fSPeter Grehan 	/* li   r11,reloff  */
287b9dea67fSPeter Grehan 	/* b    pltresolve  */
288b9dea67fSPeter Grehan 	where[0] = 0x39600000 | reloff;
289b9dea67fSPeter Grehan 	where[1] = 0x48000000 | (distance & 0x03fffffc);
290b9dea67fSPeter Grehan 
291b9dea67fSPeter Grehan 	/*
292b9dea67fSPeter Grehan 	 * The icache will be sync'd in init_pltgot, which is called
293b9dea67fSPeter Grehan 	 * after all the slots have been updated
294b9dea67fSPeter Grehan 	 */
295b9dea67fSPeter Grehan 
296b9dea67fSPeter Grehan 	return (0);
297b9dea67fSPeter Grehan }
298b9dea67fSPeter Grehan 
299b9dea67fSPeter Grehan 
300b9dea67fSPeter Grehan /*
301b9dea67fSPeter Grehan  * Process the PLT relocations.
302b9dea67fSPeter Grehan  */
303b9dea67fSPeter Grehan int
304b9dea67fSPeter Grehan reloc_plt(Obj_Entry *obj)
305b9dea67fSPeter Grehan {
306b9dea67fSPeter Grehan 	const Elf_Rela *relalim;
307b9dea67fSPeter Grehan 	const Elf_Rela *rela;
308b9dea67fSPeter Grehan 
309b9dea67fSPeter Grehan 	if (obj->pltrelasize != 0) {
310b9dea67fSPeter Grehan 
311b9dea67fSPeter Grehan 		relalim = (const Elf_Rela *)((char *)obj->pltrela +
312b9dea67fSPeter Grehan 		    obj->pltrelasize);
313b9dea67fSPeter Grehan 		for (rela = obj->pltrela;  rela < relalim;  rela++) {
314b9dea67fSPeter Grehan 			assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
315b9dea67fSPeter Grehan 
316b9dea67fSPeter Grehan 			if (reloc_plt_object(obj, rela) < 0) {
317b9dea67fSPeter Grehan 				return (-1);
318b9dea67fSPeter Grehan 			}
319b9dea67fSPeter Grehan 		}
320b9dea67fSPeter Grehan 	}
321b9dea67fSPeter Grehan 
322b9dea67fSPeter Grehan 	return (0);
323b9dea67fSPeter Grehan }
324b9dea67fSPeter Grehan 
325b9dea67fSPeter Grehan 
326b9dea67fSPeter Grehan /*
327b9dea67fSPeter Grehan  * LD_BIND_NOW was set - force relocation for all jump slots
328b9dea67fSPeter Grehan  */
329b9dea67fSPeter Grehan int
330b9dea67fSPeter Grehan reloc_jmpslots(Obj_Entry *obj)
331b9dea67fSPeter Grehan {
332b9dea67fSPeter Grehan 	const Obj_Entry *defobj;
333b9dea67fSPeter Grehan 	const Elf_Rela *relalim;
334b9dea67fSPeter Grehan 	const Elf_Rela *rela;
335b9dea67fSPeter Grehan 	const Elf_Sym *def;
336b9dea67fSPeter Grehan 	Elf_Addr *where;
337b9dea67fSPeter Grehan 	Elf_Addr target;
338b9dea67fSPeter Grehan 
339b9dea67fSPeter Grehan 	relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
340b9dea67fSPeter Grehan 	for (rela = obj->pltrela; rela < relalim; rela++) {
341b9dea67fSPeter Grehan 		assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
342b9dea67fSPeter Grehan 		where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
343b9dea67fSPeter Grehan 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
344b9dea67fSPeter Grehan 		   true, NULL);
345b9dea67fSPeter Grehan 		if (def == NULL) {
346b9dea67fSPeter Grehan 			dbg("reloc_jmpslots: sym not found");
347b9dea67fSPeter Grehan 			return (-1);
348b9dea67fSPeter Grehan 		}
349b9dea67fSPeter Grehan 
350b9dea67fSPeter Grehan 		target = (Elf_Addr)(defobj->relocbase + def->st_value);
351b9dea67fSPeter Grehan 
352b9dea67fSPeter Grehan #if 0
353b9dea67fSPeter Grehan 		/* PG XXX */
354b9dea67fSPeter Grehan 		dbg("\"%s\" in \"%s\" --> %p in \"%s\"",
355b9dea67fSPeter Grehan 		    defobj->strtab + def->st_name, basename(obj->path),
356b9dea67fSPeter Grehan 		    (void *)target, basename(defobj->path));
357b9dea67fSPeter Grehan #endif
358b9dea67fSPeter Grehan 
359b9dea67fSPeter Grehan 		reloc_jmpslot(where, target, defobj, obj,
360b9dea67fSPeter Grehan 		    (const Elf_Rel *) rela);
361b9dea67fSPeter Grehan 	}
362b9dea67fSPeter Grehan 
363b9dea67fSPeter Grehan 	obj->jmpslots_done = true;
364b9dea67fSPeter Grehan 
365b9dea67fSPeter Grehan 	return (0);
366b9dea67fSPeter Grehan }
367b9dea67fSPeter Grehan 
368b9dea67fSPeter Grehan 
369b9dea67fSPeter Grehan /*
370b9dea67fSPeter Grehan  * Update the value of a PLT jump slot. Branch directly to the target if
371b9dea67fSPeter Grehan  * it is within +/- 32Mb, otherwise go indirectly via the pltcall
372b9dea67fSPeter Grehan  * trampoline call and jump table.
373b9dea67fSPeter Grehan  */
374b9dea67fSPeter Grehan Elf_Addr
375b9dea67fSPeter Grehan reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj,
376b9dea67fSPeter Grehan 	      const Obj_Entry *obj, const Elf_Rel *rel)
377b9dea67fSPeter Grehan {
378b9dea67fSPeter Grehan 	Elf_Addr offset;
379b9dea67fSPeter Grehan 	const Elf_Rela *rela = (const Elf_Rela *) rel;
380b9dea67fSPeter Grehan 
381b9dea67fSPeter Grehan 	dbg(" reloc_jmpslot: where=%p, target=%p",
382b9dea67fSPeter Grehan 	    (void *)wherep, (void *)target);
383b9dea67fSPeter Grehan 
384b9dea67fSPeter Grehan 	/*
385b9dea67fSPeter Grehan 	 * At the PLT entry pointed at by `wherep', construct
386b9dea67fSPeter Grehan 	 * a direct transfer to the now fully resolved function
387b9dea67fSPeter Grehan 	 * address.
388b9dea67fSPeter Grehan 	 */
389b9dea67fSPeter Grehan 	offset = target - (Elf_Addr)wherep;
390b9dea67fSPeter Grehan 
391b9dea67fSPeter Grehan 	if (abs(offset) < 32*1024*1024) {     /* inside 32MB? */
392b9dea67fSPeter Grehan 		/* b    value   # branch directly */
393b9dea67fSPeter Grehan 		*wherep = 0x48000000 | (offset & 0x03fffffc);
394b9dea67fSPeter Grehan 		__syncicache(wherep, 4);
395b9dea67fSPeter Grehan 	} else {
396b9dea67fSPeter Grehan 		Elf_Addr *pltcall, *jmptab;
397b9dea67fSPeter Grehan 		int distance;
398b9dea67fSPeter Grehan 		int N = obj->pltrelasize / sizeof(Elf_Rela);
399b9dea67fSPeter Grehan 		int reloff = rela - obj->pltrela;
400b9dea67fSPeter Grehan 
401b9dea67fSPeter Grehan 		if ((reloff < 0) || (reloff >= 0x8000)) {
402b9dea67fSPeter Grehan 			return (-1);
403b9dea67fSPeter Grehan 		}
404b9dea67fSPeter Grehan 
405b9dea67fSPeter Grehan 		pltcall = obj->pltgot;
406b9dea67fSPeter Grehan 
407b9dea67fSPeter Grehan 		dbg(" reloc_jmpslot: indir, reloff=%d, N=%d\n",
408b9dea67fSPeter Grehan 		    reloff, N);
409b9dea67fSPeter Grehan 
410b9dea67fSPeter Grehan 		jmptab = obj->pltgot + 18 + N * 2;
411b9dea67fSPeter Grehan 		jmptab[reloff] = target;
412b9dea67fSPeter Grehan 
413b9dea67fSPeter Grehan 		distance = (Elf_Addr)pltcall - (Elf_Addr)(wherep + 1);
414b9dea67fSPeter Grehan 
415b9dea67fSPeter Grehan 		/* li   r11,reloff */
416b9dea67fSPeter Grehan 		/* b    pltcall  # use indirect pltcall routine */
417b9dea67fSPeter Grehan 		wherep[0] = 0x39600000 | reloff;
418b9dea67fSPeter Grehan 		wherep[1] = 0x48000000 | (distance & 0x03fffffc);
419b9dea67fSPeter Grehan 		__syncicache(wherep, 8);
420b9dea67fSPeter Grehan 	}
421b9dea67fSPeter Grehan 
422b9dea67fSPeter Grehan 	return (target);
423b9dea67fSPeter Grehan }
424b9dea67fSPeter Grehan 
425b9dea67fSPeter Grehan 
426b9dea67fSPeter Grehan /*
427b9dea67fSPeter Grehan  * Setup the plt glue routines.
428b9dea67fSPeter Grehan  */
429b9dea67fSPeter Grehan #define PLTCALL_SIZE    20
430b9dea67fSPeter Grehan #define PLTRESOLVE_SIZE 24
431b9dea67fSPeter Grehan 
432b9dea67fSPeter Grehan void
433b9dea67fSPeter Grehan init_pltgot(Obj_Entry *obj)
434b9dea67fSPeter Grehan {
435b9dea67fSPeter Grehan 	Elf_Word *pltcall, *pltresolve;
436b9dea67fSPeter Grehan 	Elf_Word *jmptab;
437b9dea67fSPeter Grehan 	int N = obj->pltrelasize / sizeof(Elf_Rela);
438b9dea67fSPeter Grehan 
439b9dea67fSPeter Grehan 	pltcall = obj->pltgot;
440b9dea67fSPeter Grehan 
441b9dea67fSPeter Grehan 	if (pltcall == NULL) {
442b9dea67fSPeter Grehan 		return;
443b9dea67fSPeter Grehan 	}
444b9dea67fSPeter Grehan 
445b9dea67fSPeter Grehan 	/*
446b9dea67fSPeter Grehan 	 * From the SVR4 PPC ABI:
447b9dea67fSPeter Grehan 	 *
448b9dea67fSPeter Grehan 	 * 'The first 18 words (72 bytes) of the PLT are reserved for
449b9dea67fSPeter Grehan 	 * use by the dynamic linker.
450b9dea67fSPeter Grehan 	 *   ...
451b9dea67fSPeter Grehan 	 * 'If the executable or shared object requires N procedure
452b9dea67fSPeter Grehan 	 *  linkage table entries, the link editor shall reserve 3*N
453b9dea67fSPeter Grehan 	 *  words (12*N bytes) following the 18 reserved words. The
454b9dea67fSPeter Grehan 	 *  first 2*N of these words are the procedure linkage table
455b9dea67fSPeter Grehan 	 *  entries themselves. The static linker directs calls to bytes
456b9dea67fSPeter Grehan 	 *  (72 + (i-1)*8), for i between 1 and N inclusive. The remaining
457b9dea67fSPeter Grehan 	 *  N words (4*N bytes) are reserved for use by the dynamic linker.'
458b9dea67fSPeter Grehan 	 */
459b9dea67fSPeter Grehan 
460b9dea67fSPeter Grehan 	/*
461b9dea67fSPeter Grehan 	 * Copy the absolute-call assembler stub into the first part of
462b9dea67fSPeter Grehan 	 * the reserved PLT area.
463b9dea67fSPeter Grehan 	 */
464b9dea67fSPeter Grehan 	memcpy(pltcall, _rtld_powerpc_pltcall, PLTCALL_SIZE);
465b9dea67fSPeter Grehan 
466b9dea67fSPeter Grehan 	/*
467b9dea67fSPeter Grehan 	 * Determine the address of the jumptable, which is the dyn-linker
468b9dea67fSPeter Grehan 	 * reserved area after the call cells. Write the absolute address
469b9dea67fSPeter Grehan 	 * of the jumptable into the absolute-call assembler code so it
470b9dea67fSPeter Grehan 	 * can determine this address.
471b9dea67fSPeter Grehan 	 */
472b9dea67fSPeter Grehan 	jmptab = pltcall + 18 + N * 2;
473b9dea67fSPeter Grehan 	pltcall[1] |= _ppc_ha(jmptab);	   /* addis 11,11,jmptab@ha */
474b9dea67fSPeter Grehan 	pltcall[2] |= _ppc_la(jmptab);     /* lwz   11,jmptab@l(11) */
475b9dea67fSPeter Grehan 
476b9dea67fSPeter Grehan 	/*
477b9dea67fSPeter Grehan 	 * Skip down 32 bytes into the initial reserved area and copy
478b9dea67fSPeter Grehan 	 * in the standard resolving assembler call. Into this assembler,
479b9dea67fSPeter Grehan 	 * insert the absolute address of the _rtld_bind_start routine
480b9dea67fSPeter Grehan 	 * and the address of the relocation object.
481b9dea67fSPeter Grehan 	 */
482b9dea67fSPeter Grehan 	pltresolve = obj->pltgot + 8;
483b9dea67fSPeter Grehan 
484b9dea67fSPeter Grehan 	memcpy(pltresolve, _rtld_powerpc_pltresolve, PLTRESOLVE_SIZE);
485b9dea67fSPeter Grehan 	pltresolve[0] |= _ppc_ha(_rtld_bind_start);
486b9dea67fSPeter Grehan 	pltresolve[1] |= _ppc_la(_rtld_bind_start);
487b9dea67fSPeter Grehan 	pltresolve[3] |= _ppc_ha(obj);
488b9dea67fSPeter Grehan 	pltresolve[4] |= _ppc_la(obj);
489b9dea67fSPeter Grehan 
490b9dea67fSPeter Grehan 	/*
491b9dea67fSPeter Grehan 	 * Sync the icache for the byte range represented by the
492b9dea67fSPeter Grehan 	 * trampoline routines and call slots.
493b9dea67fSPeter Grehan 	 */
494b9dea67fSPeter Grehan 	__syncicache(pltcall, 72 + N * 8);
495b9dea67fSPeter Grehan }
496