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