xref: /minix3/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: ppc_reloc.c,v 1.53 2014/08/25 20:40:52 joerg Exp $	*/
2e83f7ba2SBen Gras 
3e83f7ba2SBen Gras /*-
4e83f7ba2SBen Gras  * Copyright (C) 1998	Tsubai Masanari
5e83f7ba2SBen Gras  * Portions copyright 2002 Charles M. Hannum <root@ihack.net>
6e83f7ba2SBen Gras  * All rights reserved.
7e83f7ba2SBen Gras  *
8e83f7ba2SBen Gras  * Redistribution and use in source and binary forms, with or without
9e83f7ba2SBen Gras  * modification, are permitted provided that the following conditions
10e83f7ba2SBen Gras  * are met:
11e83f7ba2SBen Gras  * 1. Redistributions of source code must retain the above copyright
12e83f7ba2SBen Gras  *    notice, this list of conditions and the following disclaimer.
13e83f7ba2SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
14e83f7ba2SBen Gras  *    notice, this list of conditions and the following disclaimer in the
15e83f7ba2SBen Gras  *    documentation and/or other materials provided with the distribution.
16e83f7ba2SBen Gras  * 3. The name of the author may not be used to endorse or promote products
17e83f7ba2SBen Gras  *    derived from this software without specific prior written permission.
18e83f7ba2SBen Gras  *
19e83f7ba2SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20e83f7ba2SBen Gras  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21e83f7ba2SBen Gras  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22e83f7ba2SBen Gras  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23e83f7ba2SBen Gras  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24e83f7ba2SBen Gras  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25e83f7ba2SBen Gras  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26e83f7ba2SBen Gras  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27e83f7ba2SBen Gras  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28e83f7ba2SBen Gras  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29e83f7ba2SBen Gras  */
30e83f7ba2SBen Gras 
31e83f7ba2SBen Gras #include <sys/cdefs.h>
32e83f7ba2SBen Gras #ifndef lint
33*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: ppc_reloc.c,v 1.53 2014/08/25 20:40:52 joerg Exp $");
34e83f7ba2SBen Gras #endif /* not lint */
35e83f7ba2SBen Gras 
36e83f7ba2SBen Gras #include <stdarg.h>
37e83f7ba2SBen Gras #include <stdio.h>
38e83f7ba2SBen Gras #include <stdlib.h>
39e83f7ba2SBen Gras #include <string.h>
40e83f7ba2SBen Gras #include <sys/types.h>
41e83f7ba2SBen Gras #include <machine/cpu.h>
42e83f7ba2SBen Gras 
43e83f7ba2SBen Gras #include "debug.h"
44e83f7ba2SBen Gras #include "rtld.h"
45e83f7ba2SBen Gras 
46e83f7ba2SBen Gras void _rtld_powerpc_pltcall(Elf_Word);
47e83f7ba2SBen Gras void _rtld_powerpc_pltresolve(Elf_Word, Elf_Word);
48e83f7ba2SBen Gras 
49*0a6a1f1dSLionel Sambuc #define __u64(x)	((uint64_t)(x))
50*0a6a1f1dSLionel Sambuc #define __u32(x)	((uint32_t)(x))
51*0a6a1f1dSLionel Sambuc #define __ha48		__u64(0xffffffff8000)
52*0a6a1f1dSLionel Sambuc #define __ha32		__u64(0xffff8000)
53*0a6a1f1dSLionel Sambuc #define __ha16		__u32(0x8000)
54*0a6a1f1dSLionel Sambuc #define __ha(x,n) ((((x) >> (n)) + (((x) & __ha##n) == __ha##n)) & 0xffff)
55*0a6a1f1dSLionel Sambuc #define __hi(x,n) (((x) >> (n)) & 0xffff)
56*0a6a1f1dSLionel Sambuc #ifdef __LP64
57*0a6a1f1dSLionel Sambuc #define highesta(x)	__ha(__u64(x), 48)
58*0a6a1f1dSLionel Sambuc #define highest(x)	__hi(__u64(x), 48)
59*0a6a1f1dSLionel Sambuc #define higher(x)	__ha(__u64(x), 32)
60*0a6a1f1dSLionel Sambuc #define higher(x)	__hi(__u64(x), 32)
61*0a6a1f1dSLionel Sambuc #endif
62*0a6a1f1dSLionel Sambuc #define ha(x)		__ha(__u32(x), 16)
63*0a6a1f1dSLionel Sambuc #define hi(x)		__hi(__u32(x), 16)
64*0a6a1f1dSLionel Sambuc #define lo(x)		(__u32(x) & 0xffff)
65e83f7ba2SBen Gras 
66*0a6a1f1dSLionel Sambuc #ifdef _LP64
67*0a6a1f1dSLionel Sambuc /* function descriptor for _rtld_bind_start */
68*0a6a1f1dSLionel Sambuc extern const uint64_t _rtld_bind_start[3];
69*0a6a1f1dSLionel Sambuc #else
70e83f7ba2SBen Gras void _rtld_bind_bssplt_start(void);
71e83f7ba2SBen Gras void _rtld_bind_secureplt_start(void);
72*0a6a1f1dSLionel Sambuc #endif
73*0a6a1f1dSLionel Sambuc Elf_Addr _rtld_bind(const Obj_Entry *, Elf_Word);
74e83f7ba2SBen Gras void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
75e83f7ba2SBen Gras static int _rtld_relocate_plt_object(const Obj_Entry *,
76e83f7ba2SBen Gras     const Elf_Rela *, int, Elf_Addr *);
77e83f7ba2SBen Gras 
78e83f7ba2SBen Gras /*
79*0a6a1f1dSLionel Sambuc  * The PPC32 PLT format consists of three sections:
80e83f7ba2SBen Gras  * (1) The "pltcall" and "pltresolve" glue code.  This is always 18 words.
81e83f7ba2SBen Gras  * (2) The code part of the PLT entries.  There are 2 words per entry for
82e83f7ba2SBen Gras  *     up to 8192 entries, then 4 words per entry for any additional entries.
83e83f7ba2SBen Gras  * (3) The data part of the PLT entries, comprising a jump table.
84e83f7ba2SBen Gras  *     This section is half the size of the second section (ie. 1 or 2 words
85e83f7ba2SBen Gras  *     per entry).
86e83f7ba2SBen Gras  */
87e83f7ba2SBen Gras 
88e83f7ba2SBen Gras void
_rtld_setup_pltgot(const Obj_Entry * obj)89e83f7ba2SBen Gras _rtld_setup_pltgot(const Obj_Entry *obj)
90e83f7ba2SBen Gras {
91*0a6a1f1dSLionel Sambuc #ifdef _LP64
92*0a6a1f1dSLionel Sambuc 	/*
93*0a6a1f1dSLionel Sambuc 	 * For powerpc64, just copy the function descriptor to pltgot[0].
94*0a6a1f1dSLionel Sambuc 	 */
95*0a6a1f1dSLionel Sambuc 	if (obj->pltgot != NULL) {
96*0a6a1f1dSLionel Sambuc 		obj->pltgot[0] = (Elf_Addr) _rtld_bind_start[0];
97*0a6a1f1dSLionel Sambuc 		obj->pltgot[1] = (Elf_Addr) _rtld_bind_start[1];
98*0a6a1f1dSLionel Sambuc 		obj->pltgot[2] = (Elf_Addr) obj;
99*0a6a1f1dSLionel Sambuc 	}
100*0a6a1f1dSLionel Sambuc #else
101e83f7ba2SBen Gras 	/*
102e83f7ba2SBen Gras 	 * Secure-PLT is much more sane.
103e83f7ba2SBen Gras 	 */
104e83f7ba2SBen Gras 	if (obj->gotptr != NULL) {
105e83f7ba2SBen Gras 		obj->gotptr[1] = (Elf_Addr) _rtld_bind_secureplt_start;
106e83f7ba2SBen Gras 		obj->gotptr[2] = (Elf_Addr) obj;
107f14fb602SLionel Sambuc 		dbg(("obj %s secure-plt gotptr=%p start=%p obj=%p",
108f14fb602SLionel Sambuc 		    obj->path, obj->gotptr,
109f14fb602SLionel Sambuc 		    (void *) obj->gotptr[1], (void *) obj->gotptr[2]));
110e83f7ba2SBen Gras 	} else {
111*0a6a1f1dSLionel Sambuc /*
112*0a6a1f1dSLionel Sambuc  * Setup the plt glue routines (for bss-plt).
113*0a6a1f1dSLionel Sambuc  */
114*0a6a1f1dSLionel Sambuc #define BSSPLTCALL_SIZE		20
115*0a6a1f1dSLionel Sambuc #define BSSPLTRESOLVE_SIZE	24
116*0a6a1f1dSLionel Sambuc 
117e83f7ba2SBen Gras 		Elf_Word *pltcall, *pltresolve;
118e83f7ba2SBen Gras 		Elf_Word *jmptab;
119e83f7ba2SBen Gras 		int N = obj->pltrelalim - obj->pltrela;
120e83f7ba2SBen Gras 
121e83f7ba2SBen Gras 		/* Entries beyond 8192 take twice as much space. */
122e83f7ba2SBen Gras 		if (N > 8192)
123e83f7ba2SBen Gras 			N += N-8192;
124e83f7ba2SBen Gras 
125f14fb602SLionel Sambuc 		dbg(("obj %s bss-plt pltgot=%p jmptab=%u start=%p obj=%p",
126f14fb602SLionel Sambuc 		    obj->path, obj->pltgot, 18 + N * 2,
127f14fb602SLionel Sambuc 		    _rtld_bind_bssplt_start, obj));
128f14fb602SLionel Sambuc 
129e83f7ba2SBen Gras 		pltcall = obj->pltgot;
130e83f7ba2SBen Gras 		jmptab = pltcall + 18 + N * 2;
131e83f7ba2SBen Gras 
132*0a6a1f1dSLionel Sambuc 		memcpy(pltcall, _rtld_powerpc_pltcall, BSSPLTCALL_SIZE);
133e83f7ba2SBen Gras 		pltcall[1] |= ha(jmptab);
134*0a6a1f1dSLionel Sambuc 		pltcall[2] |= lo(jmptab);
135e83f7ba2SBen Gras 
136e83f7ba2SBen Gras 		pltresolve = obj->pltgot + 8;
137e83f7ba2SBen Gras 
138*0a6a1f1dSLionel Sambuc 		memcpy(pltresolve, _rtld_powerpc_pltresolve, BSSPLTRESOLVE_SIZE);
139e83f7ba2SBen Gras 		pltresolve[0] |= ha(_rtld_bind_bssplt_start);
140*0a6a1f1dSLionel Sambuc 		pltresolve[1] |= lo(_rtld_bind_bssplt_start);
141e83f7ba2SBen Gras 		pltresolve[3] |= ha(obj);
142*0a6a1f1dSLionel Sambuc 		pltresolve[4] |= lo(obj);
143e83f7ba2SBen Gras 
144e83f7ba2SBen Gras 		/*
145e83f7ba2SBen Gras 		 * Invalidate the icache for only the code part of the PLT
146e83f7ba2SBen Gras 		 * (and not the jump table at the end).
147e83f7ba2SBen Gras 		 */
148e83f7ba2SBen Gras 		__syncicache(pltcall, (char *)jmptab - (char *)pltcall);
149e83f7ba2SBen Gras 	}
150*0a6a1f1dSLionel Sambuc #endif
151e83f7ba2SBen Gras }
152e83f7ba2SBen Gras 
153e83f7ba2SBen Gras void
_rtld_relocate_nonplt_self(Elf_Dyn * dynp,Elf_Addr relocbase)154e83f7ba2SBen Gras _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
155e83f7ba2SBen Gras {
156e83f7ba2SBen Gras 	const Elf_Rela *rela = 0, *relalim;
157e83f7ba2SBen Gras 	Elf_Addr relasz = 0;
158e83f7ba2SBen Gras 	Elf_Addr *where;
159e83f7ba2SBen Gras 
160e83f7ba2SBen Gras 	for (; dynp->d_tag != DT_NULL; dynp++) {
161e83f7ba2SBen Gras 		switch (dynp->d_tag) {
162e83f7ba2SBen Gras 		case DT_RELA:
163e83f7ba2SBen Gras 			rela = (const Elf_Rela *)(relocbase + dynp->d_un.d_ptr);
164e83f7ba2SBen Gras 			break;
165e83f7ba2SBen Gras 		case DT_RELASZ:
166e83f7ba2SBen Gras 			relasz = dynp->d_un.d_val;
167e83f7ba2SBen Gras 			break;
168e83f7ba2SBen Gras 		}
169e83f7ba2SBen Gras 	}
170e83f7ba2SBen Gras 	relalim = (const Elf_Rela *)((const uint8_t *)rela + relasz);
171e83f7ba2SBen Gras 	for (; rela < relalim; rela++) {
172e83f7ba2SBen Gras 		where = (Elf_Addr *)(relocbase + rela->r_offset);
173e83f7ba2SBen Gras 		*where = (Elf_Addr)(relocbase + rela->r_addend);
174e83f7ba2SBen Gras 	}
175e83f7ba2SBen Gras }
176e83f7ba2SBen Gras 
177e83f7ba2SBen Gras int
_rtld_relocate_nonplt_objects(Obj_Entry * obj)178e83f7ba2SBen Gras _rtld_relocate_nonplt_objects(Obj_Entry *obj)
179e83f7ba2SBen Gras {
180e83f7ba2SBen Gras 	const Elf_Rela *rela;
181e83f7ba2SBen Gras 
182e83f7ba2SBen Gras 	for (rela = obj->rela; rela < obj->relalim; rela++) {
183e83f7ba2SBen Gras 		Elf_Addr        *where;
184e83f7ba2SBen Gras 		const Elf_Sym   *def;
185e83f7ba2SBen Gras 		const Obj_Entry *defobj;
186e83f7ba2SBen Gras 		Elf_Addr         tmp;
187e83f7ba2SBen Gras 		unsigned long	 symnum;
188e83f7ba2SBen Gras 
189e83f7ba2SBen Gras 		where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
190e83f7ba2SBen Gras 		symnum = ELF_R_SYM(rela->r_info);
191e83f7ba2SBen Gras 
192e83f7ba2SBen Gras 		switch (ELF_R_TYPE(rela->r_info)) {
193e83f7ba2SBen Gras #if 1 /* XXX Should not be necessary. */
194e83f7ba2SBen Gras 		case R_TYPE(JMP_SLOT):
195e83f7ba2SBen Gras #endif
196e83f7ba2SBen Gras 		case R_TYPE(NONE):
197e83f7ba2SBen Gras 			break;
198e83f7ba2SBen Gras 
199*0a6a1f1dSLionel Sambuc #ifdef _LP64
200*0a6a1f1dSLionel Sambuc 		case R_TYPE(ADDR64):	/* <address> S + A */
201*0a6a1f1dSLionel Sambuc #else
202*0a6a1f1dSLionel Sambuc 		case R_TYPE(ADDR32):	/* <address> S + A */
203*0a6a1f1dSLionel Sambuc #endif
204*0a6a1f1dSLionel Sambuc 		case R_TYPE(GLOB_DAT):	/* <address> S + A */
205e83f7ba2SBen Gras 			def = _rtld_find_symdef(symnum, obj, &defobj, false);
206e83f7ba2SBen Gras 			if (def == NULL)
207e83f7ba2SBen Gras 				return -1;
208e83f7ba2SBen Gras 
209e83f7ba2SBen Gras 			tmp = (Elf_Addr)(defobj->relocbase + def->st_value +
210e83f7ba2SBen Gras 			    rela->r_addend);
211e83f7ba2SBen Gras 			if (*where != tmp)
212e83f7ba2SBen Gras 				*where = tmp;
213e83f7ba2SBen Gras 			rdbg(("32/GLOB_DAT %s in %s --> %p in %s",
214e83f7ba2SBen Gras 			    obj->strtab + obj->symtab[symnum].st_name,
215e83f7ba2SBen Gras 			    obj->path, (void *)*where, defobj->path));
216e83f7ba2SBen Gras 			break;
217e83f7ba2SBen Gras 
218*0a6a1f1dSLionel Sambuc 		case R_TYPE(RELATIVE):	/* <address> B + A */
219e83f7ba2SBen Gras 			*where = (Elf_Addr)(obj->relocbase + rela->r_addend);
220e83f7ba2SBen Gras 			rdbg(("RELATIVE in %s --> %p", obj->path,
221e83f7ba2SBen Gras 			    (void *)*where));
222e83f7ba2SBen Gras 			break;
223e83f7ba2SBen Gras 
224e83f7ba2SBen Gras 		case R_TYPE(COPY):
225e83f7ba2SBen Gras 			/*
226e83f7ba2SBen Gras 			 * These are deferred until all other relocations have
227e83f7ba2SBen Gras 			 * been done.  All we do here is make sure that the
228e83f7ba2SBen Gras 			 * COPY relocation is not in a shared library.  They
229e83f7ba2SBen Gras 			 * are allowed only in executable files.
230e83f7ba2SBen Gras 			 */
231e83f7ba2SBen Gras 			if (obj->isdynamic) {
232e83f7ba2SBen Gras 				_rtld_error(
233e83f7ba2SBen Gras 			"%s: Unexpected R_COPY relocation in shared library",
234e83f7ba2SBen Gras 				    obj->path);
235e83f7ba2SBen Gras 				return -1;
236e83f7ba2SBen Gras 			}
237e83f7ba2SBen Gras 			rdbg(("COPY (avoid in main)"));
238e83f7ba2SBen Gras 			break;
239e83f7ba2SBen Gras 
240*0a6a1f1dSLionel Sambuc 		case R_TYPE(DTPMOD):
241f14fb602SLionel Sambuc 			def = _rtld_find_symdef(symnum, obj, &defobj, false);
242f14fb602SLionel Sambuc 			if (def == NULL)
243f14fb602SLionel Sambuc 				return -1;
244f14fb602SLionel Sambuc 
245f14fb602SLionel Sambuc 			*where = (Elf_Addr)defobj->tlsindex;
246f14fb602SLionel Sambuc 			rdbg(("DTPMOD32 %s in %s --> %p in %s",
247f14fb602SLionel Sambuc 			    obj->strtab + obj->symtab[symnum].st_name,
248f14fb602SLionel Sambuc 			    obj->path, (void *)*where, defobj->path));
249f14fb602SLionel Sambuc 			break;
250f14fb602SLionel Sambuc 
251*0a6a1f1dSLionel Sambuc 		case R_TYPE(DTPREL):
252f14fb602SLionel Sambuc 			def = _rtld_find_symdef(symnum, obj, &defobj, false);
253f14fb602SLionel Sambuc 			if (def == NULL)
254f14fb602SLionel Sambuc 				return -1;
255f14fb602SLionel Sambuc 
256f14fb602SLionel Sambuc 			if (!defobj->tls_done && _rtld_tls_offset_allocate(obj))
257f14fb602SLionel Sambuc 				return -1;
258f14fb602SLionel Sambuc 
259f14fb602SLionel Sambuc 			*where = (Elf_Addr)(def->st_value + rela->r_addend
260f14fb602SLionel Sambuc 			    - TLS_DTV_OFFSET);
261f14fb602SLionel Sambuc 			rdbg(("DTPREL32 %s in %s --> %p in %s",
262f14fb602SLionel Sambuc 			    obj->strtab + obj->symtab[symnum].st_name,
263f14fb602SLionel Sambuc 			    obj->path, (void *)*where, defobj->path));
264f14fb602SLionel Sambuc 			break;
265f14fb602SLionel Sambuc 
266*0a6a1f1dSLionel Sambuc 		case R_TYPE(TPREL):
267f14fb602SLionel Sambuc 			def = _rtld_find_symdef(symnum, obj, &defobj, false);
268f14fb602SLionel Sambuc 			if (def == NULL)
269f14fb602SLionel Sambuc 				return -1;
270f14fb602SLionel Sambuc 
271f14fb602SLionel Sambuc 			if (!defobj->tls_done && _rtld_tls_offset_allocate(obj))
272f14fb602SLionel Sambuc 				return -1;
273f14fb602SLionel Sambuc 
274f14fb602SLionel Sambuc 			*where = (Elf_Addr)(def->st_value + rela->r_addend
275f14fb602SLionel Sambuc 			    + defobj->tlsoffset - TLS_TP_OFFSET);
276f14fb602SLionel Sambuc 			rdbg(("TPREL32 %s in %s --> %p in %s",
277f14fb602SLionel Sambuc 			    obj->strtab + obj->symtab[symnum].st_name,
278f14fb602SLionel Sambuc 			    obj->path, (void *)*where, defobj->path));
279f14fb602SLionel Sambuc 			break;
280f14fb602SLionel Sambuc 
281e83f7ba2SBen Gras 		default:
282e83f7ba2SBen Gras 			rdbg(("sym = %lu, type = %lu, offset = %p, "
283e83f7ba2SBen Gras 			    "addend = %p, contents = %p, symbol = %s",
284e83f7ba2SBen Gras 			    symnum, (u_long)ELF_R_TYPE(rela->r_info),
285e83f7ba2SBen Gras 			    (void *)rela->r_offset, (void *)rela->r_addend,
286e83f7ba2SBen Gras 			    (void *)*where,
287e83f7ba2SBen Gras 			    obj->strtab + obj->symtab[symnum].st_name));
288e83f7ba2SBen Gras 			_rtld_error("%s: Unsupported relocation type %ld "
289e83f7ba2SBen Gras 			    "in non-PLT relocations",
290e83f7ba2SBen Gras 			    obj->path, (u_long) ELF_R_TYPE(rela->r_info));
291e83f7ba2SBen Gras 			return -1;
292e83f7ba2SBen Gras 		}
293e83f7ba2SBen Gras 	}
294e83f7ba2SBen Gras 	return 0;
295e83f7ba2SBen Gras }
296e83f7ba2SBen Gras 
297e83f7ba2SBen Gras int
_rtld_relocate_plt_lazy(const Obj_Entry * obj)298e83f7ba2SBen Gras _rtld_relocate_plt_lazy(const Obj_Entry *obj)
299e83f7ba2SBen Gras {
300*0a6a1f1dSLionel Sambuc #ifdef _LP64
301*0a6a1f1dSLionel Sambuc 	/*
302*0a6a1f1dSLionel Sambuc 	 * For PowerPC64, the plt stubs handle an empty function descriptor
303*0a6a1f1dSLionel Sambuc 	 * so there's nothing to do.
304*0a6a1f1dSLionel Sambuc 	 */
305*0a6a1f1dSLionel Sambuc #else
306e83f7ba2SBen Gras 	Elf_Addr * const pltresolve = obj->pltgot + 8;
307e83f7ba2SBen Gras 	const Elf_Rela *rela;
308e83f7ba2SBen Gras 	int reloff;
309e83f7ba2SBen Gras 
310e83f7ba2SBen Gras 	for (rela = obj->pltrela, reloff = 0;
311e83f7ba2SBen Gras 	     rela < obj->pltrelalim;
312e83f7ba2SBen Gras 	     rela++, reloff++) {
313e83f7ba2SBen Gras 		Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
314e83f7ba2SBen Gras 
315e83f7ba2SBen Gras 		assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT));
316e83f7ba2SBen Gras 
317e83f7ba2SBen Gras 		if (obj->gotptr != NULL) {
318e83f7ba2SBen Gras 			/*
319e83f7ba2SBen Gras 			 * For now, simply treat then as relative.
320e83f7ba2SBen Gras 			 */
321e83f7ba2SBen Gras 			*where += (Elf_Addr)obj->relocbase;
322e83f7ba2SBen Gras 		} else {
323e83f7ba2SBen Gras 			int distance;
324e83f7ba2SBen Gras 
325e83f7ba2SBen Gras 			if (reloff < 32768) {
326e83f7ba2SBen Gras 				/* li	r11,reloff */
327e83f7ba2SBen Gras 				*where++ = 0x39600000 | reloff;
328e83f7ba2SBen Gras 			} else {
329e83f7ba2SBen Gras 				/* lis  r11,ha(reloff) */
330*0a6a1f1dSLionel Sambuc 				/* addi	r11,lo(reloff) */
331e83f7ba2SBen Gras 				*where++ = 0x3d600000 | ha(reloff);
332*0a6a1f1dSLionel Sambuc 				*where++ = 0x396b0000 | lo(reloff);
333e83f7ba2SBen Gras 			}
334e83f7ba2SBen Gras 			/* b	pltresolve */
335e83f7ba2SBen Gras 			distance = (Elf_Addr)pltresolve - (Elf_Addr)where;
336e83f7ba2SBen Gras 			*where++ = 0x48000000 | (distance & 0x03fffffc);
337e83f7ba2SBen Gras 
338e83f7ba2SBen Gras 			/*
339e83f7ba2SBen Gras 			 * Icache invalidation is not done for each entry here
340e83f7ba2SBen Gras 			 * because we sync the entire code part of the PLT once
341e83f7ba2SBen Gras 			 * in _rtld_setup_pltgot() after all the entries have been
342e83f7ba2SBen Gras 			 * initialized.
343e83f7ba2SBen Gras 			 */
344e83f7ba2SBen Gras 			/* __syncicache(where - 3, 12); */
345e83f7ba2SBen Gras 		}
346e83f7ba2SBen Gras 	}
347*0a6a1f1dSLionel Sambuc #endif /* !_LP64 */
348e83f7ba2SBen Gras 
349e83f7ba2SBen Gras 	return 0;
350e83f7ba2SBen Gras }
351e83f7ba2SBen Gras 
352e83f7ba2SBen Gras static int
_rtld_relocate_plt_object(const Obj_Entry * obj,const Elf_Rela * rela,int reloff,Elf_Addr * tp)353e83f7ba2SBen Gras _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, int reloff, Elf_Addr *tp)
354e83f7ba2SBen Gras {
355e83f7ba2SBen Gras 	Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
356e83f7ba2SBen Gras 	Elf_Addr value;
357e83f7ba2SBen Gras 	const Elf_Sym *def;
358e83f7ba2SBen Gras 	const Obj_Entry *defobj;
359e83f7ba2SBen Gras 	unsigned long info = rela->r_info;
360e83f7ba2SBen Gras 
361e83f7ba2SBen Gras 	assert(ELF_R_TYPE(info) == R_TYPE(JMP_SLOT));
362e83f7ba2SBen Gras 
363e83f7ba2SBen Gras 	def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, tp != NULL);
364e83f7ba2SBen Gras 	if (__predict_false(def == NULL))
365e83f7ba2SBen Gras 		return -1;
366e83f7ba2SBen Gras 	if (__predict_false(def == &_rtld_sym_zero))
367e83f7ba2SBen Gras 		return 0;
368e83f7ba2SBen Gras 
369*0a6a1f1dSLionel Sambuc 	if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
370*0a6a1f1dSLionel Sambuc 		if (tp == NULL)
371*0a6a1f1dSLionel Sambuc 			return 0;
372*0a6a1f1dSLionel Sambuc 		value = _rtld_resolve_ifunc(defobj, def);
373*0a6a1f1dSLionel Sambuc 	} else {
374e83f7ba2SBen Gras 		value = (Elf_Addr)(defobj->relocbase + def->st_value);
375*0a6a1f1dSLionel Sambuc 	}
376e83f7ba2SBen Gras 	rdbg(("bind now/fixup in %s --> new=%p",
377e83f7ba2SBen Gras 	    defobj->strtab + def->st_name, (void *)value));
378e83f7ba2SBen Gras 
379*0a6a1f1dSLionel Sambuc #ifdef _LP64
380*0a6a1f1dSLionel Sambuc 	/*
381*0a6a1f1dSLionel Sambuc 	 * For PowerPC64 we simply replace the function descriptor in the
382*0a6a1f1dSLionel Sambuc 	 * PLTGOT with the one from source object.
383*0a6a1f1dSLionel Sambuc 	 */
384*0a6a1f1dSLionel Sambuc 	assert(where >= (Elf_Word *)obj->pltgot);
385*0a6a1f1dSLionel Sambuc 	assert(where < (Elf_Word *)obj->pltgot + (obj->pltrelalim - obj->pltrela));
386*0a6a1f1dSLionel Sambuc 	const Elf_Addr * const fdesc = (Elf_Addr *) value;
387*0a6a1f1dSLionel Sambuc 	where[0] = fdesc[0];
388*0a6a1f1dSLionel Sambuc 	where[1] = fdesc[1];
389*0a6a1f1dSLionel Sambuc 	where[2] = fdesc[2];
390*0a6a1f1dSLionel Sambuc #else
391*0a6a1f1dSLionel Sambuc 	ptrdiff_t distance = value - (Elf_Addr)where;
392e83f7ba2SBen Gras 	if (obj->gotptr != NULL) {
393e83f7ba2SBen Gras 		/*
394*0a6a1f1dSLionel Sambuc 		 * For Secure-PLT we simply replace the entry in GOT with the
395*0a6a1f1dSLionel Sambuc 		 * address of the routine.
396e83f7ba2SBen Gras 		 */
397e83f7ba2SBen Gras 		assert(where >= (Elf_Word *)obj->pltgot);
398e83f7ba2SBen Gras 		assert(where < (Elf_Word *)obj->pltgot + (obj->pltrelalim - obj->pltrela));
399e83f7ba2SBen Gras 		*where = value;
400*0a6a1f1dSLionel Sambuc 	} else if (labs(distance) < 32*1024*1024) {	/* inside 32MB? */
401e83f7ba2SBen Gras 		/* b	value	# branch directly */
402e83f7ba2SBen Gras 		*where = 0x48000000 | (distance & 0x03fffffc);
403e83f7ba2SBen Gras 		__syncicache(where, 4);
404e83f7ba2SBen Gras 	} else {
405e83f7ba2SBen Gras 		Elf_Addr *pltcall, *jmptab;
406e83f7ba2SBen Gras 		int N = obj->pltrelalim - obj->pltrela;
407e83f7ba2SBen Gras 
408e83f7ba2SBen Gras 		/* Entries beyond 8192 take twice as much space. */
409e83f7ba2SBen Gras 		if (N > 8192)
410e83f7ba2SBen Gras 			N += N-8192;
411e83f7ba2SBen Gras 
412e83f7ba2SBen Gras 		pltcall = obj->pltgot;
413e83f7ba2SBen Gras 		jmptab = pltcall + 18 + N * 2;
414e83f7ba2SBen Gras 
415e83f7ba2SBen Gras 		jmptab[reloff] = value;
416e83f7ba2SBen Gras 
417e83f7ba2SBen Gras 		if (reloff < 32768) {
418e83f7ba2SBen Gras 			/* li	r11,reloff */
419e83f7ba2SBen Gras 			*where++ = 0x39600000 | reloff;
420e83f7ba2SBen Gras 		} else {
421e83f7ba2SBen Gras #ifdef notyet
422e83f7ba2SBen Gras 			/* lis  r11,ha(value) */
423*0a6a1f1dSLionel Sambuc 			/* addi	r11,lo(value) */
424e83f7ba2SBen Gras 			/* mtctr r11 */
425e83f7ba2SBen Gras 			/* bctr */
426e83f7ba2SBen Gras 			*where++ = 0x3d600000 | ha(value);
427*0a6a1f1dSLionel Sambuc 			*where++ = 0x396b0000 | lo(value);
428e83f7ba2SBen Gras 			*where++ = 0x7d6903a6;
429e83f7ba2SBen Gras 			*where++ = 0x4e800420;
430e83f7ba2SBen Gras #else
431e83f7ba2SBen Gras 			/* lis  r11,ha(reloff) */
432*0a6a1f1dSLionel Sambuc 			/* addi	r11,lo(reloff) */
433e83f7ba2SBen Gras 			*where++ = 0x3d600000 | ha(reloff);
434*0a6a1f1dSLionel Sambuc 			*where++ = 0x396b0000 | lo(reloff);
435e83f7ba2SBen Gras #endif
436e83f7ba2SBen Gras 		}
437e83f7ba2SBen Gras 		/* b	pltcall	*/
438e83f7ba2SBen Gras 		distance = (Elf_Addr)pltcall - (Elf_Addr)where;
439e83f7ba2SBen Gras 		*where++ = 0x48000000 | (distance & 0x03fffffc);
440e83f7ba2SBen Gras 		__syncicache(where - 3, 12);
441e83f7ba2SBen Gras 	}
442*0a6a1f1dSLionel Sambuc #endif /* _LP64 */
443e83f7ba2SBen Gras 
444e83f7ba2SBen Gras 	if (tp)
445e83f7ba2SBen Gras 		*tp = value;
446e83f7ba2SBen Gras 	return 0;
447e83f7ba2SBen Gras }
448e83f7ba2SBen Gras 
449*0a6a1f1dSLionel Sambuc Elf_Addr
_rtld_bind(const Obj_Entry * obj,Elf_Word reloff)450e83f7ba2SBen Gras _rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
451e83f7ba2SBen Gras {
452f14fb602SLionel Sambuc 	const Elf_Rela *rela = obj->pltrela + reloff;
453e83f7ba2SBen Gras 	Elf_Addr new_value;
454e83f7ba2SBen Gras 	int err;
455e83f7ba2SBen Gras 
456e83f7ba2SBen Gras 	new_value = 0;	/* XXX gcc */
457e83f7ba2SBen Gras 
458f14fb602SLionel Sambuc 	_rtld_shared_enter();
459e83f7ba2SBen Gras 	err = _rtld_relocate_plt_object(obj, rela, reloff, &new_value);
460e83f7ba2SBen Gras 	if (err)
461e83f7ba2SBen Gras 		_rtld_die();
462f14fb602SLionel Sambuc 	_rtld_shared_exit();
463e83f7ba2SBen Gras 
464*0a6a1f1dSLionel Sambuc #ifdef _LP64
465*0a6a1f1dSLionel Sambuc 	return obj->glink;
466*0a6a1f1dSLionel Sambuc #else
467*0a6a1f1dSLionel Sambuc 	return new_value;
468*0a6a1f1dSLionel Sambuc #endif
469e83f7ba2SBen Gras }
470e83f7ba2SBen Gras 
471e83f7ba2SBen Gras int
_rtld_relocate_plt_objects(const Obj_Entry * obj)472e83f7ba2SBen Gras _rtld_relocate_plt_objects(const Obj_Entry *obj)
473e83f7ba2SBen Gras {
474e83f7ba2SBen Gras 	const Elf_Rela *rela;
475e83f7ba2SBen Gras 	int reloff;
476e83f7ba2SBen Gras 
477e83f7ba2SBen Gras 	for (rela = obj->pltrela, reloff = 0; rela < obj->pltrelalim; rela++, reloff++) {
478e83f7ba2SBen Gras 		if (_rtld_relocate_plt_object(obj, rela, reloff, NULL) < 0)
479e83f7ba2SBen Gras 			return -1;
480e83f7ba2SBen Gras 	}
481e83f7ba2SBen Gras 	return 0;
482e83f7ba2SBen Gras }
483