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