xref: /minix3/libexec/ld.elf_so/arch/hppa/hppa_reloc.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: hppa_reloc.c,v 1.43 2014/08/25 20:40:52 joerg Exp $	*/
2e83f7ba2SBen Gras 
3e83f7ba2SBen Gras /*-
4e83f7ba2SBen Gras  * Copyright (c) 2002, 2004 The NetBSD Foundation, Inc.
5e83f7ba2SBen Gras  * All rights reserved.
6e83f7ba2SBen Gras  *
7e83f7ba2SBen Gras  * This code is derived from software contributed to The NetBSD Foundation
8e83f7ba2SBen Gras  * by Matt Fredette and Nick Hudson.
9e83f7ba2SBen Gras  *
10e83f7ba2SBen Gras  * Redistribution and use in source and binary forms, with or without
11e83f7ba2SBen Gras  * modification, are permitted provided that the following conditions
12e83f7ba2SBen Gras  * are met:
13e83f7ba2SBen Gras  * 1. Redistributions of source code must retain the above copyright
14e83f7ba2SBen Gras  *    notice, this list of conditions and the following disclaimer.
15e83f7ba2SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
16e83f7ba2SBen Gras  *    notice, this list of conditions and the following disclaimer in the
17e83f7ba2SBen Gras  *    documentation and/or other materials provided with the distribution.
18e83f7ba2SBen Gras  *
19e83f7ba2SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20e83f7ba2SBen Gras  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21e83f7ba2SBen Gras  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22e83f7ba2SBen Gras  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23e83f7ba2SBen Gras  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24e83f7ba2SBen Gras  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25e83f7ba2SBen Gras  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26e83f7ba2SBen Gras  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27e83f7ba2SBen Gras  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28e83f7ba2SBen Gras  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29e83f7ba2SBen Gras  * POSSIBILITY OF SUCH DAMAGE.
30e83f7ba2SBen Gras  */
31e83f7ba2SBen Gras 
32e83f7ba2SBen Gras #include <sys/cdefs.h>
33e83f7ba2SBen Gras #ifndef lint
34*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: hppa_reloc.c,v 1.43 2014/08/25 20:40:52 joerg Exp $");
35e83f7ba2SBen Gras #endif /* not lint */
36e83f7ba2SBen Gras 
37e83f7ba2SBen Gras #include <stdlib.h>
38e83f7ba2SBen Gras #include <sys/types.h>
39e83f7ba2SBen Gras #include <sys/queue.h>
40e83f7ba2SBen Gras 
41e83f7ba2SBen Gras #include <string.h>
42e83f7ba2SBen Gras 
43e83f7ba2SBen Gras #include "rtld.h"
44e83f7ba2SBen Gras #include "debug.h"
45e83f7ba2SBen Gras 
46e83f7ba2SBen Gras #ifdef RTLD_DEBUG_HPPA
47e83f7ba2SBen Gras #define	hdbg(x)		xprintf x
48e83f7ba2SBen Gras #else
49e83f7ba2SBen Gras #define	hdbg(x)		/* nothing */
50e83f7ba2SBen Gras #endif
51e83f7ba2SBen Gras 
52e83f7ba2SBen Gras caddr_t _rtld_bind(const Obj_Entry *, const Elf_Addr);
53e83f7ba2SBen Gras void _rtld_bind_start(void);
54e83f7ba2SBen Gras void __rtld_setup_hppa_pltgot(const Obj_Entry *, Elf_Addr *);
55e83f7ba2SBen Gras 
56e83f7ba2SBen Gras /*
57e83f7ba2SBen Gras  * It is possible for the compiler to emit relocations for unaligned data.
58e83f7ba2SBen Gras  * We handle this situation with these inlines.
59e83f7ba2SBen Gras  */
60e83f7ba2SBen Gras #define	RELOC_ALIGNED_P(x) \
61e83f7ba2SBen Gras 	(((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
62e83f7ba2SBen Gras 
63e83f7ba2SBen Gras static inline Elf_Addr
load_ptr(void * where)64e83f7ba2SBen Gras load_ptr(void *where)
65e83f7ba2SBen Gras {
66e83f7ba2SBen Gras 	if (__predict_true(RELOC_ALIGNED_P(where)))
67e83f7ba2SBen Gras 		return *(Elf_Addr *)where;
68e83f7ba2SBen Gras 	else {
69e83f7ba2SBen Gras 		Elf_Addr res;
70e83f7ba2SBen Gras 
71e83f7ba2SBen Gras 		(void)memcpy(&res, where, sizeof(res));
72e83f7ba2SBen Gras 		return res;
73e83f7ba2SBen Gras 	}
74e83f7ba2SBen Gras }
75e83f7ba2SBen Gras 
76e83f7ba2SBen Gras static inline void
store_ptr(void * where,Elf_Addr val)77e83f7ba2SBen Gras store_ptr(void *where, Elf_Addr val)
78e83f7ba2SBen Gras {
79e83f7ba2SBen Gras 	if (__predict_true(RELOC_ALIGNED_P(where)))
80e83f7ba2SBen Gras 		*(Elf_Addr *)where = val;
81e83f7ba2SBen Gras 	else
82e83f7ba2SBen Gras 		(void)memcpy(where, &val, sizeof(val));
83e83f7ba2SBen Gras }
84e83f7ba2SBen Gras 
85f14fb602SLionel Sambuc static __inline void
fdc(void * addr)86f14fb602SLionel Sambuc fdc(void *addr)
87f14fb602SLionel Sambuc {
88f14fb602SLionel Sambuc 	__asm volatile("fdc %%r0(%%sr0, %0)" : : "r" (addr));
89f14fb602SLionel Sambuc }
90f14fb602SLionel Sambuc 
91f14fb602SLionel Sambuc static __inline void
fic(void * addr)92f14fb602SLionel Sambuc fic(void *addr)
93f14fb602SLionel Sambuc {
94f14fb602SLionel Sambuc 	__asm volatile("fic %%r0(%%sr0,%0)" : : "r" (addr));
95f14fb602SLionel Sambuc }
96f14fb602SLionel Sambuc 
97f14fb602SLionel Sambuc static __inline void
sync(void)98f14fb602SLionel Sambuc sync(void)
99f14fb602SLionel Sambuc {
100f14fb602SLionel Sambuc 	__asm volatile("sync" : : : "memory");
101f14fb602SLionel Sambuc }
102f14fb602SLionel Sambuc 
103f14fb602SLionel Sambuc #define PLT_STUB_MAGIC1	0x00c0ffee
104f14fb602SLionel Sambuc #define PLT_STUB_MAGIC2	0xdeadbeef
105f14fb602SLionel Sambuc 
106f14fb602SLionel Sambuc #define PLT_STUB_INSN1	0x0e801081	/* ldw	0(%r20), %r1 */
107f14fb602SLionel Sambuc #define PLT_STUB_INSN2	0xe820c000	/* bv	%r0(%r1) */
108f14fb602SLionel Sambuc 
109e83f7ba2SBen Gras /*
110e83f7ba2SBen Gras  * In the runtime architecture (ABI), PLABEL function pointers are
111e83f7ba2SBen Gras  * distinguished from normal function pointers by having the next-least-
112e83f7ba2SBen Gras  * significant bit set.  (This bit is referred to as the L field in HP
113e83f7ba2SBen Gras  * documentation).  The $$dyncall millicode is aware of this.
114e83f7ba2SBen Gras  */
115e83f7ba2SBen Gras #define	RTLD_MAKE_PLABEL(plabel)	(((Elf_Addr)(plabel)) | (1 << 1))
116e83f7ba2SBen Gras #define RTLD_IS_PLABEL(addr)		(((Elf_Addr)(addr)) & (1 << 1))
117e83f7ba2SBen Gras #define	RTLD_GET_PLABEL(addr)	((hppa_plabel *) (((Elf_Addr)addr) & ~3))
118e83f7ba2SBen Gras 
119e83f7ba2SBen Gras /*
120e83f7ba2SBen Gras  * This is the PLABEL structure.  The function PC and
121e83f7ba2SBen Gras  * shared linkage members must come first, as they are
122e83f7ba2SBen Gras  * the actual PLABEL.
123e83f7ba2SBen Gras  */
124e83f7ba2SBen Gras typedef struct _hppa_plabel {
125e83f7ba2SBen Gras 	Elf_Addr	hppa_plabel_pc;
126e83f7ba2SBen Gras 	Elf_Addr	hppa_plabel_sl;
127e83f7ba2SBen Gras 	SLIST_ENTRY(_hppa_plabel)	hppa_plabel_next;
128e83f7ba2SBen Gras } hppa_plabel;
129e83f7ba2SBen Gras 
130e83f7ba2SBen Gras /*
131e83f7ba2SBen Gras  * For now allocated PLABEL structures are tracked on a
132e83f7ba2SBen Gras  * singly linked list.  This maybe should be revisited.
133e83f7ba2SBen Gras  */
134e83f7ba2SBen Gras static SLIST_HEAD(hppa_plabel_head, _hppa_plabel) hppa_plabel_list
135e83f7ba2SBen Gras     = SLIST_HEAD_INITIALIZER(hppa_plabel_list);
136e83f7ba2SBen Gras 
137e83f7ba2SBen Gras /*
138e83f7ba2SBen Gras  * Because I'm hesitant to use NEW while relocating self,
139e83f7ba2SBen Gras  * this is a small pool of preallocated PLABELs.
140e83f7ba2SBen Gras  */
141f14fb602SLionel Sambuc #define	HPPA_PLABEL_PRE	(32)
142e83f7ba2SBen Gras static hppa_plabel hppa_plabel_pre[HPPA_PLABEL_PRE];
143e83f7ba2SBen Gras static int hppa_plabel_pre_next = 0;
144e83f7ba2SBen Gras 
145e83f7ba2SBen Gras void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
146e83f7ba2SBen Gras int _rtld_relocate_plt_objects(const Obj_Entry *);
147e83f7ba2SBen Gras static inline int _rtld_relocate_plt_object(const Obj_Entry *,
148e83f7ba2SBen Gras     const Elf_Rela *, Elf_Addr *);
149e83f7ba2SBen Gras 
150e83f7ba2SBen Gras /*
151e83f7ba2SBen Gras  * This bootstraps the dynamic linker by relocating its GOT.
152e83f7ba2SBen Gras  * On the hppa, unlike on other architectures, static strings
153e83f7ba2SBen Gras  * are found through the GOT.  Static strings are essential
154e83f7ba2SBen Gras  * for RTLD_DEBUG, and I suspect they're used early even when
155e83f7ba2SBen Gras  * !defined(RTLD_DEBUG), making relocating the GOT essential.
156e83f7ba2SBen Gras  *
157e83f7ba2SBen Gras  * It gets worse.  Relocating the GOT doesn't mean just walking
158e83f7ba2SBen Gras  * it and adding the relocbase to all of the entries.  You must
159e83f7ba2SBen Gras  * find and use the GOT relocations, since those RELA relocations
160e83f7ba2SBen Gras  * have the necessary addends - the GOT comes initialized as
161e83f7ba2SBen Gras  * zeroes.
162e83f7ba2SBen Gras  */
163e83f7ba2SBen Gras void
_rtld_relocate_nonplt_self(Elf_Dyn * dynp,Elf_Addr relocbase)164e83f7ba2SBen Gras _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
165e83f7ba2SBen Gras {
166e83f7ba2SBen Gras 	const Elf_Rela	*relafirst, *rela, *relalim;
167e83f7ba2SBen Gras 	Elf_Addr        relasz;
168e83f7ba2SBen Gras 	void		*where;
169e83f7ba2SBen Gras 	Elf_Addr	*pltgot;
170e83f7ba2SBen Gras 	const Elf_Rela	*plabel_relocs[HPPA_PLABEL_PRE];
171e83f7ba2SBen Gras 	int		nplabel_relocs = 0;
172e83f7ba2SBen Gras 	int		i;
173e83f7ba2SBen Gras 	const Elf_Sym	*symtab, *sym;
174e83f7ba2SBen Gras 	unsigned long	symnum;
175e83f7ba2SBen Gras 	hppa_plabel	*plabel;
176e83f7ba2SBen Gras 
177e83f7ba2SBen Gras 	/*
178e83f7ba2SBen Gras 	 * Process the DYNAMIC section, looking for the non-PLT relocations.
179e83f7ba2SBen Gras 	 */
180e83f7ba2SBen Gras 	relafirst = NULL;
181e83f7ba2SBen Gras 	relasz = 0;
182e83f7ba2SBen Gras 	symtab = NULL;
183e83f7ba2SBen Gras 	pltgot = NULL;
184e83f7ba2SBen Gras 	for (; dynp->d_tag != DT_NULL; ++dynp) {
185e83f7ba2SBen Gras 		switch (dynp->d_tag) {
186e83f7ba2SBen Gras 
187e83f7ba2SBen Gras 		case DT_RELA:
188e83f7ba2SBen Gras 			relafirst = (const Elf_Rela *)
189e83f7ba2SBen Gras 			    (relocbase + dynp->d_un.d_ptr);
190e83f7ba2SBen Gras 			break;
191e83f7ba2SBen Gras 
192e83f7ba2SBen Gras 		case DT_RELASZ:
193e83f7ba2SBen Gras 			relasz = dynp->d_un.d_val;
194e83f7ba2SBen Gras 			break;
195e83f7ba2SBen Gras 
196e83f7ba2SBen Gras 		case DT_SYMTAB:
197e83f7ba2SBen Gras 			symtab = (const Elf_Sym *)
198e83f7ba2SBen Gras 			    (relocbase + dynp->d_un.d_ptr);
199e83f7ba2SBen Gras 			break;
200e83f7ba2SBen Gras 
201e83f7ba2SBen Gras 		case DT_PLTGOT:
202e83f7ba2SBen Gras 			pltgot = (Elf_Addr *)
203e83f7ba2SBen Gras 			    (relocbase + dynp->d_un.d_ptr);
204e83f7ba2SBen Gras 			break;
205e83f7ba2SBen Gras 		}
206e83f7ba2SBen Gras 	}
207e83f7ba2SBen Gras 	relalim = (const Elf_Rela *)((const char *)relafirst + relasz);
208e83f7ba2SBen Gras 
209e83f7ba2SBen Gras 	for (rela = relafirst; rela < relalim; rela++) {
210e83f7ba2SBen Gras 		symnum = ELF_R_SYM(rela->r_info);
211e83f7ba2SBen Gras 		where = (void *)(relocbase + rela->r_offset);
212e83f7ba2SBen Gras 
213e83f7ba2SBen Gras 		switch (ELF_R_TYPE(rela->r_info)) {
214e83f7ba2SBen Gras 		case R_TYPE(DIR32):
215e83f7ba2SBen Gras 			if (symnum == 0)
216e83f7ba2SBen Gras 				store_ptr(where,
217e83f7ba2SBen Gras 				    relocbase + rela->r_addend);
218e83f7ba2SBen Gras 			else {
219e83f7ba2SBen Gras 				sym = symtab + symnum;
220e83f7ba2SBen Gras 				store_ptr(where,
221e83f7ba2SBen Gras 				    relocbase + rela->r_addend + sym->st_value);
222e83f7ba2SBen Gras 			}
223e83f7ba2SBen Gras 			break;
224e83f7ba2SBen Gras 
225e83f7ba2SBen Gras 		case R_TYPE(PLABEL32):
226e83f7ba2SBen Gras 			/*
227e83f7ba2SBen Gras 			 * PLABEL32 relocation processing is done in two phases
228e83f7ba2SBen Gras 			 *
229e83f7ba2SBen Gras 			 *  i) local function relocations (symbol number == 0)
230e83f7ba2SBen Gras 			 *     can be resolved immediately.
231e83f7ba2SBen Gras 			 *
232e83f7ba2SBen Gras 			 * ii) external function relocations are deferred until
233e83f7ba2SBen Gras 			 *     we finish all other relocations so that global
234e83f7ba2SBen Gras 			 *     data isn't accessed until all other non-PLT
235e83f7ba2SBen Gras 			 *     relocations have been done.
236e83f7ba2SBen Gras 			 */
237e83f7ba2SBen Gras 			if (symnum == 0)
238e83f7ba2SBen Gras 				*((Elf_Addr *)where) =
239e83f7ba2SBen Gras 				    relocbase + rela->r_addend;
240e83f7ba2SBen Gras 			else
241e83f7ba2SBen Gras 				plabel_relocs[nplabel_relocs++] = rela;
242e83f7ba2SBen Gras 			break;
243e83f7ba2SBen Gras 
244e83f7ba2SBen Gras 		default:
245e83f7ba2SBen Gras 			break;
246e83f7ba2SBen Gras 		}
247e83f7ba2SBen Gras 	}
248e83f7ba2SBen Gras 
249e83f7ba2SBen Gras 	assert(nplabel_relocs < HPPA_PLABEL_PRE);
250e83f7ba2SBen Gras 	for (i = 0; i < nplabel_relocs; i++) {
251e83f7ba2SBen Gras 		rela = plabel_relocs[i];
252e83f7ba2SBen Gras 		where = (void *)(relocbase + rela->r_offset);
253e83f7ba2SBen Gras 		sym = symtab + ELF_R_SYM(rela->r_info);
254e83f7ba2SBen Gras 
255e83f7ba2SBen Gras 		plabel = &hppa_plabel_pre[hppa_plabel_pre_next++];
256e83f7ba2SBen Gras 
257e83f7ba2SBen Gras 		plabel->hppa_plabel_pc = (Elf_Addr)
258e83f7ba2SBen Gras 		    (relocbase + sym->st_value + rela->r_addend);
259e83f7ba2SBen Gras 		plabel->hppa_plabel_sl = (Elf_Addr)pltgot;
260e83f7ba2SBen Gras 
261e83f7ba2SBen Gras 		SLIST_INSERT_HEAD(&hppa_plabel_list, plabel, hppa_plabel_next);
262e83f7ba2SBen Gras 		*((Elf_Addr *)where) = (Elf_Addr)(RTLD_MAKE_PLABEL(plabel));
263e83f7ba2SBen Gras 	}
264e83f7ba2SBen Gras 
265e83f7ba2SBen Gras #if defined(RTLD_DEBUG_HPPA)
266e83f7ba2SBen Gras 	for (rela = relafirst; rela < relalim; rela++) {
267e83f7ba2SBen Gras 		where = (void *)(relocbase + rela->r_offset);
268e83f7ba2SBen Gras 
269e83f7ba2SBen Gras 		switch (ELF_R_TYPE(rela->r_info)) {
270e83f7ba2SBen Gras 		case R_TYPE(DIR32):
271e83f7ba2SBen Gras 			hdbg(("DIR32 rela @%p(%p) -> %p(%p)\n",
272e83f7ba2SBen Gras 			    (void *)rela->r_offset,
273e83f7ba2SBen Gras 			    (void *)where,
274e83f7ba2SBen Gras 			    (void *)rela->r_addend,
275e83f7ba2SBen Gras 			    (void *)*((Elf_Addr *)where) ));
276e83f7ba2SBen Gras 			break;
277e83f7ba2SBen Gras 
278e83f7ba2SBen Gras 		case R_TYPE(PLABEL32):
279e83f7ba2SBen Gras 			symnum = ELF_R_SYM(rela->r_info);
280e83f7ba2SBen Gras 			if (symnum == 0) {
281e83f7ba2SBen Gras 				hdbg(("PLABEL rela @%p(%p) -> %p(%p)\n",
282e83f7ba2SBen Gras 		    		    (void *)rela->r_offset,
283e83f7ba2SBen Gras 		    		    (void *)where,
284e83f7ba2SBen Gras 		    		    (void *)rela->r_addend,
285e83f7ba2SBen Gras 		    		    (void *)*((Elf_Addr *)where) ));
286e83f7ba2SBen Gras 			} else {
287e83f7ba2SBen Gras 				sym = symtab + symnum;
288e83f7ba2SBen Gras 
289e83f7ba2SBen Gras 				hdbg(("PLABEL32 rela @%p(%p), symnum=%ld(%p) -> %p(%p)\n",
290e83f7ba2SBen Gras 			    	    (void *)rela->r_offset,
291e83f7ba2SBen Gras 				    (void *)where,
292e83f7ba2SBen Gras 				    symnum,
293e83f7ba2SBen Gras 				    (void *)sym->st_value,
294e83f7ba2SBen Gras 			    	    (void *)rela->r_addend,
295e83f7ba2SBen Gras 				    (void *)*((Elf_Addr *)where) ));
296e83f7ba2SBen Gras 			}
297e83f7ba2SBen Gras 			break;
298e83f7ba2SBen Gras 		default:
299e83f7ba2SBen Gras 			hdbg(("rela XXX reloc\n"));
300e83f7ba2SBen Gras 			break;
301e83f7ba2SBen Gras 		}
302e83f7ba2SBen Gras 	}
303e83f7ba2SBen Gras #endif /* RTLD_DEBUG_HPPA */
304e83f7ba2SBen Gras }
305e83f7ba2SBen Gras 
306e83f7ba2SBen Gras /*
307e83f7ba2SBen Gras  * This allocates a PLABEL.  If called with a non-NULL def, the
308e83f7ba2SBen Gras  * plabel is for the function associated with that definition
309e83f7ba2SBen Gras  * in the defining object defobj, plus the given addend.  If
310e83f7ba2SBen Gras  * called with a NULL def, the plabel is for the function at
311e83f7ba2SBen Gras  * the (unrelocated) address in addend in the object defobj.
312e83f7ba2SBen Gras  */
313e83f7ba2SBen Gras Elf_Addr
_rtld_function_descriptor_alloc(const Obj_Entry * defobj,const Elf_Sym * def,Elf_Addr addend)314e83f7ba2SBen Gras _rtld_function_descriptor_alloc(const Obj_Entry *defobj, const Elf_Sym *def,
315e83f7ba2SBen Gras     Elf_Addr addend)
316e83f7ba2SBen Gras {
317e83f7ba2SBen Gras 	Elf_Addr	func_pc, func_sl;
318e83f7ba2SBen Gras 	hppa_plabel	*plabel;
319e83f7ba2SBen Gras 
320e83f7ba2SBen Gras 	if (def != NULL) {
321e83f7ba2SBen Gras 
322e83f7ba2SBen Gras 		/*
323e83f7ba2SBen Gras 		 * We assume that symbols of type STT_NOTYPE
324e83f7ba2SBen Gras 		 * are undefined.  Return NULL for these.
325e83f7ba2SBen Gras 		 */
326e83f7ba2SBen Gras 		if (ELF_ST_TYPE(def->st_info) == STT_NOTYPE)
327e83f7ba2SBen Gras 			return (Elf_Addr)NULL;
328e83f7ba2SBen Gras 
329e83f7ba2SBen Gras 		/* Otherwise assert that this symbol must be a function. */
330e83f7ba2SBen Gras 		assert(ELF_ST_TYPE(def->st_info) == STT_FUNC);
331e83f7ba2SBen Gras 
332e83f7ba2SBen Gras 		func_pc = (Elf_Addr)(defobj->relocbase + def->st_value +
333e83f7ba2SBen Gras 		    addend);
334e83f7ba2SBen Gras 	} else
335e83f7ba2SBen Gras 		func_pc = (Elf_Addr)(defobj->relocbase + addend);
336e83f7ba2SBen Gras 
337e83f7ba2SBen Gras 	/*
338e83f7ba2SBen Gras 	 * Search the existing PLABELs for one matching
339e83f7ba2SBen Gras 	 * this function.  If there is one, return it.
340e83f7ba2SBen Gras 	 */
341e83f7ba2SBen Gras 	func_sl = (Elf_Addr)(defobj->pltgot);
342e83f7ba2SBen Gras 	SLIST_FOREACH(plabel, &hppa_plabel_list, hppa_plabel_next)
343e83f7ba2SBen Gras 		if (plabel->hppa_plabel_pc == func_pc &&
344e83f7ba2SBen Gras 		    plabel->hppa_plabel_sl == func_sl)
345e83f7ba2SBen Gras 			return RTLD_MAKE_PLABEL(plabel);
346e83f7ba2SBen Gras 
347e83f7ba2SBen Gras 	/*
348e83f7ba2SBen Gras 	 * Once we've used up the preallocated set, we start
349e83f7ba2SBen Gras 	 * using NEW to allocate plabels.
350e83f7ba2SBen Gras 	 */
351e83f7ba2SBen Gras 	if (hppa_plabel_pre_next < HPPA_PLABEL_PRE)
352e83f7ba2SBen Gras 		plabel = &hppa_plabel_pre[hppa_plabel_pre_next++];
353e83f7ba2SBen Gras 	else {
354e83f7ba2SBen Gras 		plabel = NEW(hppa_plabel);
355e83f7ba2SBen Gras 		if (plabel == NULL)
356e83f7ba2SBen Gras 			return (Elf_Addr)-1;
357e83f7ba2SBen Gras 	}
358e83f7ba2SBen Gras 
359e83f7ba2SBen Gras 	/* Fill the new entry and insert it on the list. */
360e83f7ba2SBen Gras 	plabel->hppa_plabel_pc = func_pc;
361e83f7ba2SBen Gras 	plabel->hppa_plabel_sl = func_sl;
362e83f7ba2SBen Gras 	SLIST_INSERT_HEAD(&hppa_plabel_list, plabel, hppa_plabel_next);
363e83f7ba2SBen Gras 
364e83f7ba2SBen Gras 	return RTLD_MAKE_PLABEL(plabel);
365e83f7ba2SBen Gras }
366e83f7ba2SBen Gras 
367e83f7ba2SBen Gras /*
368e83f7ba2SBen Gras  * If a pointer is a PLABEL, this unwraps it.
369e83f7ba2SBen Gras  */
370e83f7ba2SBen Gras const void *
_rtld_function_descriptor_function(const void * addr)371e83f7ba2SBen Gras _rtld_function_descriptor_function(const void *addr)
372e83f7ba2SBen Gras {
373e83f7ba2SBen Gras 	return (RTLD_IS_PLABEL(addr) ?
374e83f7ba2SBen Gras 	    (const void *) RTLD_GET_PLABEL(addr)->hppa_plabel_pc :
375e83f7ba2SBen Gras 	    addr);
376e83f7ba2SBen Gras }
377e83f7ba2SBen Gras 
378e83f7ba2SBen Gras /* This sets up an object's GOT. */
379e83f7ba2SBen Gras void
_rtld_setup_pltgot(const Obj_Entry * obj)380e83f7ba2SBen Gras _rtld_setup_pltgot(const Obj_Entry *obj)
381e83f7ba2SBen Gras {
382f14fb602SLionel Sambuc 	Elf_Word *got = obj->pltgot;
383f14fb602SLionel Sambuc 
384f14fb602SLionel Sambuc 	assert(got[-2] == PLT_STUB_MAGIC1);
385f14fb602SLionel Sambuc 	assert(got[-1] == PLT_STUB_MAGIC2);
386f14fb602SLionel Sambuc 
387f14fb602SLionel Sambuc 	__rtld_setup_hppa_pltgot(obj, got);
388f14fb602SLionel Sambuc 
389f14fb602SLionel Sambuc 	fdc(&got[-2]);
390f14fb602SLionel Sambuc 	fdc(&got[-1]);
391f14fb602SLionel Sambuc 	fdc(&got[1]);
392f14fb602SLionel Sambuc 	sync();
393f14fb602SLionel Sambuc 	fic(&got[-2]);
394f14fb602SLionel Sambuc 	fic(&got[-1]);
395f14fb602SLionel Sambuc 	fic(&got[1]);
396f14fb602SLionel Sambuc 	sync();
397f14fb602SLionel Sambuc 
398f14fb602SLionel Sambuc 	/*
399f14fb602SLionel Sambuc 	 * libc makes use of %t1 (%r22) to pass errno values to __cerror. Fixup
400f14fb602SLionel Sambuc 	 * the PLT stub to not use %r22.
401f14fb602SLionel Sambuc 	 */
402f14fb602SLionel Sambuc 	got[-7] = PLT_STUB_INSN1;
403f14fb602SLionel Sambuc 	got[-6] = PLT_STUB_INSN2;
404f14fb602SLionel Sambuc 	fdc(&got[-7]);
405f14fb602SLionel Sambuc 	fdc(&got[-6]);
406f14fb602SLionel Sambuc 	sync();
407f14fb602SLionel Sambuc 	fic(&got[-7]);
408f14fb602SLionel Sambuc 	fic(&got[-6]);
409f14fb602SLionel Sambuc 	sync();
410e83f7ba2SBen Gras }
411e83f7ba2SBen Gras 
412e83f7ba2SBen Gras int
_rtld_relocate_nonplt_objects(Obj_Entry * obj)413e83f7ba2SBen Gras _rtld_relocate_nonplt_objects(Obj_Entry *obj)
414e83f7ba2SBen Gras {
415e83f7ba2SBen Gras 	const Elf_Rela *rela;
416e83f7ba2SBen Gras 
417e83f7ba2SBen Gras 	for (rela = obj->rela; rela < obj->relalim; rela++) {
418e83f7ba2SBen Gras 		Elf_Addr        *where;
419e83f7ba2SBen Gras 		const Elf_Sym   *def;
420e83f7ba2SBen Gras 		const Obj_Entry *defobj;
421e83f7ba2SBen Gras 		Elf_Addr         tmp;
422e83f7ba2SBen Gras 		unsigned long	 symnum;
423e83f7ba2SBen Gras 
424e83f7ba2SBen Gras 		where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
425e83f7ba2SBen Gras 		symnum = ELF_R_SYM(rela->r_info);
426e83f7ba2SBen Gras 
427e83f7ba2SBen Gras 		switch (ELF_R_TYPE(rela->r_info)) {
428e83f7ba2SBen Gras 		case R_TYPE(NONE):
429e83f7ba2SBen Gras 			break;
430e83f7ba2SBen Gras 
431e83f7ba2SBen Gras 		case R_TYPE(DIR32):
432e83f7ba2SBen Gras 			if (symnum) {
433e83f7ba2SBen Gras 				/*
434e83f7ba2SBen Gras 				 * This is either a DIR32 against a symbol
435e83f7ba2SBen Gras 				 * (def->st_name != 0), or against a local
436e83f7ba2SBen Gras 				 * section (def->st_name == 0).
437e83f7ba2SBen Gras 				 */
438e83f7ba2SBen Gras 				def = obj->symtab + symnum;
439e83f7ba2SBen Gras 				defobj = obj;
440e83f7ba2SBen Gras 				if (def->st_name != 0)
441e83f7ba2SBen Gras 					def = _rtld_find_symdef(symnum, obj,
442e83f7ba2SBen Gras 					    &defobj, false);
443e83f7ba2SBen Gras 				if (def == NULL)
444e83f7ba2SBen Gras 					return -1;
445e83f7ba2SBen Gras 
446e83f7ba2SBen Gras 				tmp = (Elf_Addr)(defobj->relocbase +
447e83f7ba2SBen Gras 				    def->st_value + rela->r_addend);
448e83f7ba2SBen Gras 
449e83f7ba2SBen Gras 				if (load_ptr(where) != tmp)
450e83f7ba2SBen Gras 					store_ptr(where, tmp);
451e83f7ba2SBen Gras 				rdbg(("DIR32 %s in %s --> %p in %s",
452e83f7ba2SBen Gras 				    obj->strtab + obj->symtab[symnum].st_name,
453e83f7ba2SBen Gras 				    obj->path, (void *)load_ptr(where),
454e83f7ba2SBen Gras 				    defobj->path));
455e83f7ba2SBen Gras 			} else {
456e83f7ba2SBen Gras 				tmp = (Elf_Addr)(obj->relocbase +
457e83f7ba2SBen Gras 				    rela->r_addend);
458e83f7ba2SBen Gras 
459e83f7ba2SBen Gras 				if (load_ptr(where) != tmp)
460e83f7ba2SBen Gras 					store_ptr(where, tmp);
461e83f7ba2SBen Gras 				rdbg(("DIR32 in %s --> %p", obj->path,
462e83f7ba2SBen Gras 					    (void *)load_ptr(where)));
463e83f7ba2SBen Gras 			}
464e83f7ba2SBen Gras 			break;
465e83f7ba2SBen Gras 
466e83f7ba2SBen Gras 		case R_TYPE(PLABEL32):
467e83f7ba2SBen Gras 			if (symnum) {
468e83f7ba2SBen Gras 				def = _rtld_find_symdef(symnum, obj, &defobj,
469e83f7ba2SBen Gras 				    false);
470e83f7ba2SBen Gras 				if (def == NULL)
471e83f7ba2SBen Gras 					return -1;
472e83f7ba2SBen Gras 
473e83f7ba2SBen Gras 				tmp = _rtld_function_descriptor_alloc(defobj,
474e83f7ba2SBen Gras 				    def, rela->r_addend);
475e83f7ba2SBen Gras 				if (tmp == (Elf_Addr)-1)
476e83f7ba2SBen Gras 					return -1;
477e83f7ba2SBen Gras 
478e83f7ba2SBen Gras 				if (*where != tmp)
479e83f7ba2SBen Gras 					*where = tmp;
480e83f7ba2SBen Gras 				rdbg(("PLABEL32 %s in %s --> %p in %s",
481e83f7ba2SBen Gras 				    obj->strtab + obj->symtab[symnum].st_name,
482e83f7ba2SBen Gras 				    obj->path, (void *)*where, defobj->path));
483e83f7ba2SBen Gras 			} else {
484e83f7ba2SBen Gras 				/*
485e83f7ba2SBen Gras 				 * This is a PLABEL for a static function, and
486e83f7ba2SBen Gras 				 * the dynamic linker has both allocated a PLT
487e83f7ba2SBen Gras 				 * entry for this function and told us where it
488e83f7ba2SBen Gras 				 * is.  We can safely use the PLT entry as the
489e83f7ba2SBen Gras 				 * PLABEL because there should be no other
490e83f7ba2SBen Gras 				 * PLABEL reloc referencing this function.
491e83f7ba2SBen Gras 				 * This object should also have an IPLT
492e83f7ba2SBen Gras 				 * relocation to initialize the PLT entry.
493e83f7ba2SBen Gras 				 *
494e83f7ba2SBen Gras 				 * The dynamic linker should also have ensured
495e83f7ba2SBen Gras 				 * that the addend has the
496e83f7ba2SBen Gras 				 * next-least-significant bit set; the
497e83f7ba2SBen Gras 				 * $$dyncall millicode uses this to distinguish
498e83f7ba2SBen Gras 				 * a PLABEL pointer from a plain function
499e83f7ba2SBen Gras 				 * pointer.
500e83f7ba2SBen Gras 				 */
501e83f7ba2SBen Gras 				tmp = (Elf_Addr)
502e83f7ba2SBen Gras 				    (obj->relocbase + rela->r_addend);
503e83f7ba2SBen Gras 
504e83f7ba2SBen Gras 				if (*where != tmp)
505e83f7ba2SBen Gras 					*where = tmp;
506e83f7ba2SBen Gras 				rdbg(("PLABEL32 in %s --> %p", obj->path,
507e83f7ba2SBen Gras 				    (void *)*where));
508e83f7ba2SBen Gras 			}
509e83f7ba2SBen Gras 			break;
510e83f7ba2SBen Gras 
511e83f7ba2SBen Gras 		case R_TYPE(COPY):
512e83f7ba2SBen Gras 			/*
513e83f7ba2SBen Gras 			 * These are deferred until all other relocations have
514e83f7ba2SBen Gras 			 * been done.  All we do here is make sure that the
515e83f7ba2SBen Gras 			 * COPY relocation is not in a shared library.  They
516e83f7ba2SBen Gras 			 * are allowed only in executable files.
517e83f7ba2SBen Gras 			 */
518e83f7ba2SBen Gras 			if (obj->isdynamic) {
519e83f7ba2SBen Gras 				_rtld_error(
520e83f7ba2SBen Gras 			"%s: Unexpected R_COPY relocation in shared library",
521e83f7ba2SBen Gras 				    obj->path);
522e83f7ba2SBen Gras 				return -1;
523e83f7ba2SBen Gras 			}
524e83f7ba2SBen Gras 			rdbg(("COPY (avoid in main)"));
525e83f7ba2SBen Gras 			break;
526e83f7ba2SBen Gras 
527f14fb602SLionel Sambuc 		case R_TYPE(TLS_TPREL32):
528f14fb602SLionel Sambuc 			def = _rtld_find_symdef(symnum, obj, &defobj, false);
529f14fb602SLionel Sambuc 			if (def == NULL)
530f14fb602SLionel Sambuc 				return -1;
531f14fb602SLionel Sambuc 
532f14fb602SLionel Sambuc 			if (!defobj->tls_done && _rtld_tls_offset_allocate(obj))
533f14fb602SLionel Sambuc 				return -1;
534f14fb602SLionel Sambuc 
535f14fb602SLionel Sambuc 			*where = (Elf_Addr)(defobj->tlsoffset + def->st_value +
536f14fb602SLionel Sambuc 			    rela->r_addend + sizeof(struct tls_tcb));
537f14fb602SLionel Sambuc 
538f14fb602SLionel Sambuc 			rdbg(("TPREL32 %s in %s --> %p in %s",
539f14fb602SLionel Sambuc 			    obj->strtab + obj->symtab[symnum].st_name,
540f14fb602SLionel Sambuc 			    obj->path, (void *)*where, defobj->path));
541f14fb602SLionel Sambuc 			break;
542f14fb602SLionel Sambuc 
543f14fb602SLionel Sambuc 		case R_TYPE(TLS_DTPMOD32):
544f14fb602SLionel Sambuc 			def = _rtld_find_symdef(symnum, obj, &defobj, false);
545f14fb602SLionel Sambuc 			if (def == NULL)
546f14fb602SLionel Sambuc 				return -1;
547f14fb602SLionel Sambuc 
548f14fb602SLionel Sambuc 			*where = (Elf_Addr)(defobj->tlsindex);
549f14fb602SLionel Sambuc 
550f14fb602SLionel Sambuc 			rdbg(("TLS_DTPMOD32 %s in %s --> %p",
551f14fb602SLionel Sambuc 			    obj->strtab + obj->symtab[symnum].st_name,
552f14fb602SLionel Sambuc 			    obj->path, (void *)*where));
553f14fb602SLionel Sambuc 
554f14fb602SLionel Sambuc 			break;
555f14fb602SLionel Sambuc 
556f14fb602SLionel Sambuc 		case R_TYPE(TLS_DTPOFF32):
557f14fb602SLionel Sambuc 			def = _rtld_find_symdef(symnum, obj, &defobj, false);
558f14fb602SLionel Sambuc 			if (def == NULL)
559f14fb602SLionel Sambuc 				return -1;
560f14fb602SLionel Sambuc 
561f14fb602SLionel Sambuc 			*where = (Elf_Addr)(def->st_value);
562f14fb602SLionel Sambuc 
563f14fb602SLionel Sambuc 			rdbg(("TLS_DTPOFF32 %s in %s --> %p",
564f14fb602SLionel Sambuc 			    obj->strtab + obj->symtab[symnum].st_name,
565f14fb602SLionel Sambuc 			    obj->path, (void *)*where));
566f14fb602SLionel Sambuc 
567f14fb602SLionel Sambuc 			break;
568f14fb602SLionel Sambuc 
569e83f7ba2SBen Gras 		default:
570e83f7ba2SBen Gras 			rdbg(("sym = %lu, type = %lu, offset = %p, "
571e83f7ba2SBen Gras 			    "addend = %p, contents = %p, symbol = %s",
572e83f7ba2SBen Gras 			    symnum, (u_long)ELF_R_TYPE(rela->r_info),
573e83f7ba2SBen Gras 			    (void *)rela->r_offset, (void *)rela->r_addend,
574e83f7ba2SBen Gras 			    (void *)load_ptr(where),
575e83f7ba2SBen Gras 			    obj->strtab + obj->symtab[symnum].st_name));
576e83f7ba2SBen Gras 			_rtld_error("%s: Unsupported relocation type %ld "
577e83f7ba2SBen Gras 			    "in non-PLT relocations",
578e83f7ba2SBen Gras 			    obj->path, (u_long) ELF_R_TYPE(rela->r_info));
579e83f7ba2SBen Gras 			return -1;
580e83f7ba2SBen Gras 		}
581e83f7ba2SBen Gras 	}
582e83f7ba2SBen Gras 	return 0;
583e83f7ba2SBen Gras }
584e83f7ba2SBen Gras 
585e83f7ba2SBen Gras int
_rtld_relocate_plt_lazy(const Obj_Entry * obj)586e83f7ba2SBen Gras _rtld_relocate_plt_lazy(const Obj_Entry *obj)
587e83f7ba2SBen Gras {
588e83f7ba2SBen Gras 	const Elf_Rela *rela;
589e83f7ba2SBen Gras 
590e83f7ba2SBen Gras 	for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) {
591e83f7ba2SBen Gras 		Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
592e83f7ba2SBen Gras 		Elf_Addr func_pc, func_sl;
593e83f7ba2SBen Gras 
594e83f7ba2SBen Gras 		assert(ELF_R_TYPE(rela->r_info) == R_TYPE(IPLT));
595e83f7ba2SBen Gras 
596e83f7ba2SBen Gras 		/*
597e83f7ba2SBen Gras 		 * If this is an IPLT reloc for a static function,
598e83f7ba2SBen Gras 		 * fully resolve the PLT entry now.
599e83f7ba2SBen Gras 		 */
600e83f7ba2SBen Gras 		if (ELF_R_SYM(rela->r_info) == 0) {
601e83f7ba2SBen Gras 			func_pc = (Elf_Addr)(obj->relocbase + rela->r_addend);
602e83f7ba2SBen Gras 			func_sl = (Elf_Addr)(obj->pltgot);
603e83f7ba2SBen Gras 		}
604e83f7ba2SBen Gras 
605e83f7ba2SBen Gras 		/*
606e83f7ba2SBen Gras 		 * Otherwise set up for lazy binding.
607e83f7ba2SBen Gras 		 */
608e83f7ba2SBen Gras 		else {
609e83f7ba2SBen Gras 			/*
610e83f7ba2SBen Gras 			 * This function pointer points to the PLT
611e83f7ba2SBen Gras 			 * stub added by the linker, and instead of
612e83f7ba2SBen Gras 			 * a shared linkage value, we stash this
613e83f7ba2SBen Gras 			 * relocation's offset.  The PLT stub has
614e83f7ba2SBen Gras 			 * already been set up to transfer to
615e83f7ba2SBen Gras 			 * _rtld_bind_start.
616e83f7ba2SBen Gras 			 */
617e83f7ba2SBen Gras 			func_pc = ((Elf_Addr)(obj->pltgot)) - 16;
618e83f7ba2SBen Gras 			func_sl = (Elf_Addr)
619e83f7ba2SBen Gras 			    ((const char *)rela - (const char *)(obj->pltrela));
620e83f7ba2SBen Gras 		}
621e83f7ba2SBen Gras 		rdbg(("lazy bind %s(%p) --> old=(%p,%p) new=(%p,%p)",
622e83f7ba2SBen Gras 		    obj->path,
623e83f7ba2SBen Gras 		    (void *)where,
624e83f7ba2SBen Gras 		    (void *)where[0], (void *)where[1],
625e83f7ba2SBen Gras 		    (void *)func_pc, (void *)func_sl));
626e83f7ba2SBen Gras 
627e83f7ba2SBen Gras 		/*
628e83f7ba2SBen Gras 		 * Fill this PLT entry and return.
629e83f7ba2SBen Gras 		 */
630e83f7ba2SBen Gras 		where[0] = func_pc;
631e83f7ba2SBen Gras 		where[1] = func_sl;
632e83f7ba2SBen Gras 	}
633e83f7ba2SBen Gras 	return 0;
634e83f7ba2SBen Gras }
635e83f7ba2SBen Gras 
636e83f7ba2SBen Gras static inline int
_rtld_relocate_plt_object(const Obj_Entry * obj,const Elf_Rela * rela,Elf_Addr * tp)637e83f7ba2SBen Gras _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela,
638e83f7ba2SBen Gras     Elf_Addr *tp)
639e83f7ba2SBen Gras {
640e83f7ba2SBen Gras 	Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
641e83f7ba2SBen Gras 	const Elf_Sym *def;
642e83f7ba2SBen Gras 	const Obj_Entry *defobj;
643e83f7ba2SBen Gras 	Elf_Addr	func_pc, func_sl;
644e83f7ba2SBen Gras 	unsigned long info = rela->r_info;
645e83f7ba2SBen Gras 
646e83f7ba2SBen Gras 	assert(ELF_R_TYPE(info) == R_TYPE(IPLT));
647e83f7ba2SBen Gras 
648e83f7ba2SBen Gras 	if (ELF_R_SYM(info) == 0) {
649e83f7ba2SBen Gras 		func_pc = (Elf_Addr)(obj->relocbase + rela->r_addend);
650e83f7ba2SBen Gras 		func_sl = (Elf_Addr)(obj->pltgot);
651e83f7ba2SBen Gras 	} else {
652e83f7ba2SBen Gras 		def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj,
653e83f7ba2SBen Gras 		    tp != NULL);
654e83f7ba2SBen Gras 		if (__predict_false(def == NULL))
655e83f7ba2SBen Gras 			return -1;
656e83f7ba2SBen Gras 		if (__predict_false(def == &_rtld_sym_zero))
657e83f7ba2SBen Gras 			return 0;
658e83f7ba2SBen Gras 
659*0a6a1f1dSLionel Sambuc 		if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
660*0a6a1f1dSLionel Sambuc 			if (tp == NULL)
661*0a6a1f1dSLionel Sambuc 				return 0;
662*0a6a1f1dSLionel Sambuc 			Elf_Addr ptr = _rtld_resolve_ifunc(defobj, def);
663*0a6a1f1dSLionel Sambuc 			assert(RTLD_IS_PLABEL(ptr));
664*0a6a1f1dSLionel Sambuc 			hppa_plabel *label = RTLD_GET_PLABEL(ptr);
665*0a6a1f1dSLionel Sambuc 			func_pc = label->hppa_plabel_pc;
666*0a6a1f1dSLionel Sambuc 			func_sl = label->hppa_plabel_sl;
667*0a6a1f1dSLionel Sambuc 		} else {
668e83f7ba2SBen Gras 			func_pc = (Elf_Addr)(defobj->relocbase + def->st_value +
669e83f7ba2SBen Gras 			    rela->r_addend);
670e83f7ba2SBen Gras 			func_sl = (Elf_Addr)(defobj->pltgot);
671*0a6a1f1dSLionel Sambuc 		}
672e83f7ba2SBen Gras 
673e83f7ba2SBen Gras 		rdbg(("bind now/fixup in %s --> old=(%p,%p) new=(%p,%p)",
674e83f7ba2SBen Gras 		    defobj->strtab + def->st_name,
675e83f7ba2SBen Gras 		    (void *)where[0], (void *)where[1],
676e83f7ba2SBen Gras 		    (void *)func_pc, (void *)func_sl));
677e83f7ba2SBen Gras 	}
678e83f7ba2SBen Gras 	/*
679e83f7ba2SBen Gras 	 * Fill this PLT entry and return.
680e83f7ba2SBen Gras 	 */
681e83f7ba2SBen Gras 	if (where[0] != func_pc)
682e83f7ba2SBen Gras 		where[0] = func_pc;
683e83f7ba2SBen Gras 	if (where[1] != func_sl)
684e83f7ba2SBen Gras 		where[1] = func_sl;
685e83f7ba2SBen Gras 
686e83f7ba2SBen Gras 	if (tp)
687e83f7ba2SBen Gras 		*tp = (Elf_Addr)where;
688e83f7ba2SBen Gras 
689e83f7ba2SBen Gras 	return 0;
690e83f7ba2SBen Gras }
691e83f7ba2SBen Gras 
692e83f7ba2SBen Gras caddr_t
_rtld_bind(const Obj_Entry * obj,Elf_Word reloff)693e83f7ba2SBen Gras _rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
694e83f7ba2SBen Gras {
695e83f7ba2SBen Gras 	const Elf_Rela *rela;
696e83f7ba2SBen Gras 	Elf_Addr new_value = 0;	/* XXX gcc */
697e83f7ba2SBen Gras 	int err;
698e83f7ba2SBen Gras 
699e83f7ba2SBen Gras 	rela = (const Elf_Rela *)((const char *)obj->pltrela + reloff);
700e83f7ba2SBen Gras 
701e83f7ba2SBen Gras 	assert(ELF_R_SYM(rela->r_info) != 0);
702e83f7ba2SBen Gras 
703f14fb602SLionel Sambuc 	_rtld_shared_enter();
704e83f7ba2SBen Gras 	err = _rtld_relocate_plt_object(obj, rela, &new_value);
705e83f7ba2SBen Gras 	if (err)
706e83f7ba2SBen Gras 		_rtld_die();
707f14fb602SLionel Sambuc 	_rtld_shared_exit();
708e83f7ba2SBen Gras 
709e83f7ba2SBen Gras 	return (caddr_t)new_value;
710e83f7ba2SBen Gras }
711e83f7ba2SBen Gras 
712e83f7ba2SBen Gras int
_rtld_relocate_plt_objects(const Obj_Entry * obj)713e83f7ba2SBen Gras _rtld_relocate_plt_objects(const Obj_Entry *obj)
714e83f7ba2SBen Gras {
715e83f7ba2SBen Gras 	const Elf_Rela *rela = obj->pltrela;
716e83f7ba2SBen Gras 
717e83f7ba2SBen Gras 	for (; rela < obj->pltrelalim; rela++) {
718e83f7ba2SBen Gras 		if (_rtld_relocate_plt_object(obj, rela, NULL) < 0)
719e83f7ba2SBen Gras 			return -1;
720e83f7ba2SBen Gras 	}
721e83f7ba2SBen Gras 	return 0;
722e83f7ba2SBen Gras }
723*0a6a1f1dSLionel Sambuc 
724*0a6a1f1dSLionel Sambuc void
_rtld_call_function_void(const Obj_Entry * obj,Elf_Addr ptr)725*0a6a1f1dSLionel Sambuc _rtld_call_function_void(const Obj_Entry *obj, Elf_Addr ptr)
726*0a6a1f1dSLionel Sambuc {
727*0a6a1f1dSLionel Sambuc 	volatile hppa_plabel plabel;
728*0a6a1f1dSLionel Sambuc 	void (*f)(void);
729*0a6a1f1dSLionel Sambuc 
730*0a6a1f1dSLionel Sambuc 	plabel.hppa_plabel_pc = (Elf_Addr)ptr;
731*0a6a1f1dSLionel Sambuc 	plabel.hppa_plabel_sl = (Elf_Addr)(obj->pltgot);
732*0a6a1f1dSLionel Sambuc 	f = (void (*)(void))RTLD_MAKE_PLABEL(&plabel);
733*0a6a1f1dSLionel Sambuc 
734*0a6a1f1dSLionel Sambuc 	f();
735*0a6a1f1dSLionel Sambuc }
736*0a6a1f1dSLionel Sambuc 
737*0a6a1f1dSLionel Sambuc Elf_Addr
_rtld_call_function_addr(const Obj_Entry * obj,Elf_Addr ptr)738*0a6a1f1dSLionel Sambuc _rtld_call_function_addr(const Obj_Entry *obj, Elf_Addr ptr)
739*0a6a1f1dSLionel Sambuc {
740*0a6a1f1dSLionel Sambuc 	volatile hppa_plabel plabel;
741*0a6a1f1dSLionel Sambuc 	Elf_Addr (*f)(void);
742*0a6a1f1dSLionel Sambuc 
743*0a6a1f1dSLionel Sambuc 	plabel.hppa_plabel_pc = (Elf_Addr)ptr;
744*0a6a1f1dSLionel Sambuc 	plabel.hppa_plabel_sl = (Elf_Addr)(obj->pltgot);
745*0a6a1f1dSLionel Sambuc 	f = (Elf_Addr (*)(void))RTLD_MAKE_PLABEL(&plabel);
746*0a6a1f1dSLionel Sambuc 
747*0a6a1f1dSLionel Sambuc 	return f();
748*0a6a1f1dSLionel Sambuc }
749