]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - libexec/rtld-elf/powerpc64/reloc.c
rtld-elf: Fix powerpc64 TLS handling, matching powerpc's fix
[FreeBSD/FreeBSD.git] / libexec / rtld-elf / powerpc64 / reloc.c
1 /*      $NetBSD: ppc_reloc.c,v 1.10 2001/09/10 06:09:41 mycroft Exp $   */
2
3 /*-
4  * SPDX-License-Identifier: BSD-2-Clause-NetBSD
5  *
6  * Copyright (C) 1998   Tsubai Masanari
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * $FreeBSD$
32  */
33
34 #include <sys/param.h>
35 #include <sys/mman.h>
36
37 #include <errno.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <machine/cpu.h>
43 #include <machine/md_var.h>
44
45 #include "debug.h"
46 #include "rtld.h"
47
48 #if !defined(_CALL_ELF) || _CALL_ELF == 1
49 struct funcdesc {
50         Elf_Addr addr;
51         Elf_Addr toc;
52         Elf_Addr env;
53 };
54 #endif
55
56 /*
57  * Process the R_PPC_COPY relocations
58  */
59 int
60 do_copy_relocations(Obj_Entry *dstobj)
61 {
62         const Elf_Rela *relalim;
63         const Elf_Rela *rela;
64
65         /*
66          * COPY relocs are invalid outside of the main program
67          */
68         assert(dstobj->mainprog);
69
70         relalim = (const Elf_Rela *)((const char *) dstobj->rela +
71             dstobj->relasize);
72         for (rela = dstobj->rela;  rela < relalim;  rela++) {
73                 void *dstaddr;
74                 const Elf_Sym *dstsym;
75                 const char *name;
76                 size_t size;
77                 const void *srcaddr;
78                 const Elf_Sym *srcsym = NULL;
79                 const Obj_Entry *srcobj, *defobj;
80                 SymLook req;
81                 int res;
82
83                 if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) {
84                         continue;
85                 }
86
87                 dstaddr = (void *)(dstobj->relocbase + rela->r_offset);
88                 dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
89                 name = dstobj->strtab + dstsym->st_name;
90                 size = dstsym->st_size;
91                 symlook_init(&req, name);
92                 req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
93                 req.flags = SYMLOOK_EARLY;
94
95                 for (srcobj = globallist_next(dstobj); srcobj != NULL;
96                      srcobj = globallist_next(srcobj)) {
97                         res = symlook_obj(&req, srcobj);
98                         if (res == 0) {
99                                 srcsym = req.sym_out;
100                                 defobj = req.defobj_out;
101                                 break;
102                         }
103                 }
104
105                 if (srcobj == NULL) {
106                         _rtld_error("Undefined symbol \"%s\" "
107                                     " referenced from COPY"
108                                     " relocation in %s", name, dstobj->path);
109                         return (-1);
110                 }
111
112                 srcaddr = (const void *)(defobj->relocbase+srcsym->st_value);
113                 memcpy(dstaddr, srcaddr, size);
114                 dbg("copy_reloc: src=%p,dst=%p,size=%zd\n",srcaddr,dstaddr,size);
115         }
116
117         return (0);
118 }
119
120
121 /*
122  * Perform early relocation of the run-time linker image
123  */
124 void
125 reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
126 {
127         const Elf_Rela *rela = NULL, *relalim;
128         Elf_Addr relasz = 0;
129         Elf_Addr *where;
130
131         /*
132          * Extract the rela/relasz values from the dynamic section
133          */
134         for (; dynp->d_tag != DT_NULL; dynp++) {
135                 switch (dynp->d_tag) {
136                 case DT_RELA:
137                         rela = (const Elf_Rela *)(relocbase+dynp->d_un.d_ptr);
138                         break;
139                 case DT_RELASZ:
140                         relasz = dynp->d_un.d_val;
141                         break;
142                 }
143         }
144
145         /*
146          * Relocate these values
147          */
148         relalim = (const Elf_Rela *)((const char *)rela + relasz);
149         for (; rela < relalim; rela++) {
150                 where = (Elf_Addr *)(relocbase + rela->r_offset);
151                 *where = (Elf_Addr)(relocbase + rela->r_addend);
152         }
153 }
154
155
156 /*
157  * Relocate a non-PLT object with addend.
158  */
159 static int
160 reloc_nonplt_object(Obj_Entry *obj_rtld __unused, Obj_Entry *obj,
161     const Elf_Rela *rela, SymCache *cache, int flags, RtldLockState *lockstate)
162 {
163         Elf_Addr        *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
164         const Elf_Sym   *def;
165         const Obj_Entry *defobj;
166         Elf_Addr         tmp;
167
168         switch (ELF_R_TYPE(rela->r_info)) {
169
170         case R_PPC_NONE:
171                 break;
172
173         case R_PPC64_UADDR64:    /* doubleword64 S + A */
174         case R_PPC64_ADDR64:
175         case R_PPC_GLOB_DAT:
176                 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
177                     flags, cache, lockstate);
178                 if (def == NULL) {
179                         return (-1);
180                 }
181
182                 tmp = (Elf_Addr)(defobj->relocbase + def->st_value +
183                     rela->r_addend);
184
185                 /* Don't issue write if unnecessary; avoid COW page fault */
186                 if (*where != tmp) {
187                         *where = tmp;
188                 }
189                 break;
190
191         case R_PPC_RELATIVE:  /* doubleword64 B + A */
192                 tmp = (Elf_Addr)(obj->relocbase + rela->r_addend);
193
194                 /* As above, don't issue write unnecessarily */
195                 if (*where != tmp) {
196                         *where = tmp;
197                 }
198                 break;
199
200         case R_PPC_COPY:
201                 /*
202                  * These are deferred until all other relocations
203                  * have been done.  All we do here is make sure
204                  * that the COPY relocation is not in a shared
205                  * library.  They are allowed only in executable
206                  * files.
207                  */
208                 if (!obj->mainprog) {
209                         _rtld_error("%s: Unexpected R_COPY "
210                                     " relocation in shared library",
211                                     obj->path);
212                         return (-1);
213                 }
214                 break;
215
216         case R_PPC_JMP_SLOT:
217                 /*
218                  * These will be handled by the plt/jmpslot routines
219                  */
220                 break;
221
222         case R_PPC64_DTPMOD64:
223                 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
224                     flags, cache, lockstate);
225
226                 if (def == NULL)
227                         return (-1);
228
229                 *where = (Elf_Addr) defobj->tlsindex;
230
231                 break;
232
233         case R_PPC64_TPREL64:
234                 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
235                     flags, cache, lockstate);
236
237                 if (def == NULL)
238                         return (-1);
239
240                 /*
241                  * We lazily allocate offsets for static TLS as we
242                  * see the first relocation that references the
243                  * TLS block. This allows us to support (small
244                  * amounts of) static TLS in dynamically loaded
245                  * modules. If we run out of space, we generate an
246                  * error.
247                  */
248                 if (!defobj->tls_done) {
249                         if (!allocate_tls_offset(
250                                     __DECONST(Obj_Entry *, defobj))) {
251                                 _rtld_error("%s: No space available for static "
252                                     "Thread Local Storage", obj->path);
253                                 return (-1);
254                         }
255                 }
256
257                 *(Elf_Addr **)where = *where * sizeof(Elf_Addr)
258                     + (Elf_Addr *)(def->st_value + rela->r_addend
259                     + defobj->tlsoffset - TLS_TP_OFFSET - TLS_TCB_SIZE);
260
261                 break;
262
263         case R_PPC64_DTPREL64:
264                 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
265                     flags, cache, lockstate);
266
267                 if (def == NULL)
268                         return (-1);
269
270                 *where += (Elf_Addr)(def->st_value + rela->r_addend
271                     - TLS_DTV_OFFSET);
272
273                 break;
274
275         default:
276                 _rtld_error("%s: Unsupported relocation type %ld"
277                             " in non-PLT relocations\n", obj->path,
278                             ELF_R_TYPE(rela->r_info));
279                 return (-1);
280         }
281         return (0);
282 }
283
284
285 /*
286  * Process non-PLT relocations
287  */
288 int
289 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
290     RtldLockState *lockstate)
291 {
292         const Elf_Rela *relalim;
293         const Elf_Rela *rela;
294         const Elf_Phdr *phdr;
295         SymCache *cache;
296         int bytes = obj->dynsymcount * sizeof(SymCache);
297         int r = -1;
298
299         if ((flags & SYMLOOK_IFUNC) != 0)
300                 /* XXX not implemented */
301                 return (0);
302
303         /*
304          * The dynamic loader may be called from a thread, we have
305          * limited amounts of stack available so we cannot use alloca().
306          */
307         if (obj != obj_rtld) {
308                 cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON,
309                     -1, 0);
310                 if (cache == MAP_FAILED)
311                         cache = NULL;
312         } else
313                 cache = NULL;
314
315         /*
316          * From the SVR4 PPC ABI:
317          * "The PowerPC family uses only the Elf32_Rela relocation
318          *  entries with explicit addends."
319          */
320         relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize);
321         for (rela = obj->rela; rela < relalim; rela++) {
322                 if (reloc_nonplt_object(obj_rtld, obj, rela, cache, flags,
323                     lockstate) < 0)
324                         goto done;
325         }
326         r = 0;
327 done:
328         if (cache)
329                 munmap(cache, bytes);
330
331         /*
332          * Synchronize icache for executable segments in case we made
333          * any changes.
334          */
335         for (phdr = obj->phdr;
336             (const char *)phdr < (const char *)obj->phdr + obj->phsize;
337             phdr++) {
338                 if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X) != 0) {
339                         __syncicache(obj->relocbase + phdr->p_vaddr,
340                             phdr->p_memsz);
341                 }
342         }
343
344         return (r);
345 }
346
347
348 /*
349  * Initialise a PLT slot to the resolving trampoline
350  */
351 static int
352 reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela)
353 {
354         Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
355         long reloff;
356
357         reloff = rela - obj->pltrela;
358
359         dbg(" reloc_plt_object: where=%p,reloff=%lx,glink=%#lx", (void *)where,
360             reloff, obj->glink);
361
362 #if !defined(_CALL_ELF) || _CALL_ELF == 1
363         /* Glink code is 3 instructions after the first 32k, 2 before */
364         *where = (Elf_Addr)obj->glink + 32 + 
365             8*((reloff < 0x8000) ? reloff : 0x8000) + 
366             12*((reloff < 0x8000) ? 0 : (reloff - 0x8000));
367 #else
368         *where = (Elf_Addr)obj->glink + 4*reloff + 32;
369 #endif
370
371         return (0);
372 }
373
374
375 /*
376  * Process the PLT relocations.
377  */
378 int
379 reloc_plt(Obj_Entry *obj, int flags __unused, RtldLockState *lockstate __unused)
380 {
381         const Elf_Rela *relalim;
382         const Elf_Rela *rela;
383
384         if (obj->pltrelasize != 0) {
385                 relalim = (const Elf_Rela *)((const char *)obj->pltrela +
386                     obj->pltrelasize);
387                 for (rela = obj->pltrela;  rela < relalim;  rela++) {
388                         assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
389
390                         if (reloc_plt_object(obj, rela) < 0) {
391                                 return (-1);
392                         }
393                 }
394         }
395
396         return (0);
397 }
398
399
400 /*
401  * LD_BIND_NOW was set - force relocation for all jump slots
402  */
403 int
404 reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
405 {
406         const Obj_Entry *defobj;
407         const Elf_Rela *relalim;
408         const Elf_Rela *rela;
409         const Elf_Sym *def;
410         Elf_Addr *where;
411         Elf_Addr target;
412
413         relalim = (const Elf_Rela *)((const char *)obj->pltrela +
414             obj->pltrelasize);
415         for (rela = obj->pltrela; rela < relalim; rela++) {
416                 assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
417                 where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
418                 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
419                     SYMLOOK_IN_PLT | flags, NULL, lockstate);
420                 if (def == NULL) {
421                         dbg("reloc_jmpslots: sym not found");
422                         return (-1);
423                 }
424
425                 target = (Elf_Addr)(defobj->relocbase + def->st_value);
426
427                 if (def == &sym_zero) {
428                         /* Zero undefined weak symbols */
429 #if !defined(_CALL_ELF) || _CALL_ELF == 1
430                         bzero(where, sizeof(struct funcdesc));
431 #else
432                         *where = 0;
433 #endif
434                 } else {
435                         reloc_jmpslot(where, target, defobj, obj,
436                             (const Elf_Rel *) rela);
437                 }
438         }
439
440         obj->jmpslots_done = true;
441
442         return (0);
443 }
444
445
446 /*
447  * Update the value of a PLT jump slot.
448  */
449 Elf_Addr
450 reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj,
451     const Obj_Entry *obj __unused, const Elf_Rel *rel __unused)
452 {
453
454         /*
455          * At the PLT entry pointed at by `wherep', construct
456          * a direct transfer to the now fully resolved function
457          * address.
458          */
459
460 #if !defined(_CALL_ELF) || _CALL_ELF == 1
461         dbg(" reloc_jmpslot: where=%p, target=%p (%#lx + %#lx)",
462             (void *)wherep, (void *)target, *(Elf_Addr *)target,
463             (Elf_Addr)defobj->relocbase);
464
465         if (ld_bind_not)
466                 goto out;
467
468         /*
469          * For the trampoline, the second two elements of the function
470          * descriptor are unused, so we are fine replacing those at any time
471          * with the real ones with no thread safety implications. However, we
472          * need to make sure the main entry point pointer ([0]) is seen to be
473          * modified *after* the second two elements. This can't be done in
474          * general, since there are no barriers in the reading code, but put in
475          * some isyncs to at least make it a little better.
476          */
477         memcpy(wherep, (void *)target, sizeof(struct funcdesc));
478         wherep[2] = ((Elf_Addr *)target)[2];
479         wherep[1] = ((Elf_Addr *)target)[1];
480         __asm __volatile ("isync" : : : "memory");
481         wherep[0] = ((Elf_Addr *)target)[0];
482         __asm __volatile ("isync" : : : "memory");
483
484         if (((struct funcdesc *)(wherep))->addr < (Elf_Addr)defobj->relocbase) {
485                 /*
486                  * It is possible (LD_BIND_NOW) that the function
487                  * descriptor we are copying has not yet been relocated.
488                  * If this happens, fix it. Don't worry about threading in
489                  * this case since LD_BIND_NOW makes it irrelevant.
490                  */
491
492                 ((struct funcdesc *)(wherep))->addr +=
493                     (Elf_Addr)defobj->relocbase;
494                 ((struct funcdesc *)(wherep))->toc +=
495                     (Elf_Addr)defobj->relocbase;
496         }
497 out:
498 #else
499         dbg(" reloc_jmpslot: where=%p, target=%p", (void *)wherep,
500             (void *)target);
501
502         if (!ld_bind_not)
503                 *wherep = target;
504 #endif
505
506         return (target);
507 }
508
509 int
510 reloc_iresolve(Obj_Entry *obj __unused,
511     struct Struct_RtldLockState *lockstate __unused)
512 {
513
514         /* XXX not implemented */
515         return (0);
516 }
517
518 int
519 reloc_gnu_ifunc(Obj_Entry *obj __unused, int flags __unused,
520     struct Struct_RtldLockState *lockstate __unused)
521 {
522
523         /* XXX not implemented */
524         return (0);
525 }
526
527 void
528 init_pltgot(Obj_Entry *obj)
529 {
530         Elf_Addr *pltcall;
531
532         pltcall = obj->pltgot;
533
534         if (pltcall == NULL) {
535                 return;
536         }
537
538 #if defined(_CALL_ELF) && _CALL_ELF == 2
539         pltcall[0] = (Elf_Addr)&_rtld_bind_start; 
540         pltcall[1] = (Elf_Addr)obj;
541 #else
542         memcpy(pltcall, _rtld_bind_start, sizeof(struct funcdesc));
543         pltcall[2] = (Elf_Addr)obj;
544 #endif
545 }
546
547 void
548 ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused)
549 {
550
551 }
552
553 void
554 pre_init(void)
555 {
556
557 }
558
559 void
560 allocate_initial_tls(Obj_Entry *list)
561 {
562         Elf_Addr **tp;
563
564         /*
565         * Fix the size of the static TLS block by using the maximum
566         * offset allocated so far and adding a bit for dynamic modules to
567         * use.
568         */
569
570         tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA;
571
572         tp = (Elf_Addr **)((char *)allocate_tls(list, NULL, TLS_TCB_SIZE, 16)
573             + TLS_TP_OFFSET + TLS_TCB_SIZE);
574
575         __asm __volatile("mr 13,%0" :: "r"(tp));
576 }
577
578 void*
579 __tls_get_addr(tls_index* ti)
580 {
581         Elf_Addr **tp;
582         char *p;
583
584         __asm __volatile("mr %0,13" : "=r"(tp));
585         p = tls_get_addr_common((Elf_Addr**)((Elf_Addr)tp - TLS_TP_OFFSET 
586             - TLS_TCB_SIZE), ti->ti_module, ti->ti_offset);
587
588         return (p + TLS_DTV_OFFSET);
589 }