]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - libexec/rtld-elf/powerpc/reloc.c
Copy stable/8 to releng/8.2 in preparation for FreeBSD-8.2 release.
[FreeBSD/releng/8.2.git] / libexec / rtld-elf / powerpc / reloc.c
1 /*      $NetBSD: ppc_reloc.c,v 1.10 2001/09/10 06:09:41 mycroft Exp $   */
2
3 /*-
4  * Copyright (C) 1998   Tsubai Masanari
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31
32 #include <sys/param.h>
33 #include <sys/mman.h>
34
35 #include <errno.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <machine/cpu.h>
41 #include <machine/cpufunc.h>
42 #include <machine/md_var.h>
43
44 #include "debug.h"
45 #include "rtld.h"
46
47 #define _ppc_ha(x) ((((u_int32_t)(x) & 0x8000) ? \
48                         ((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16)
49 #define _ppc_la(x) ((u_int32_t)(x) & 0xffff)
50
51 #define min(a,b) (((a) < (b)) ? (a) : (b))
52 #define max(a,b) (((a) > (b)) ? (a) : (b))
53
54 #define PLT_EXTENDED_BEGIN      (1 << 13)
55 #define JMPTAB_BASE(N)          (18 + N*2 + ((N > PLT_EXTENDED_BEGIN) ? \
56                                     (N - PLT_EXTENDED_BEGIN)*2 : 0))
57
58 /*
59  * Process the R_PPC_COPY relocations
60  */
61 int
62 do_copy_relocations(Obj_Entry *dstobj)
63 {
64         const Elf_Rela *relalim;
65         const Elf_Rela *rela;
66
67         /*
68          * COPY relocs are invalid outside of the main program
69          */
70         assert(dstobj->mainprog);
71
72         relalim = (const Elf_Rela *) ((caddr_t) dstobj->rela +
73             dstobj->relasize);
74         for (rela = dstobj->rela;  rela < relalim;  rela++) {
75                 void *dstaddr;
76                 const Elf_Sym *dstsym;
77                 const char *name;
78                 unsigned long hash;
79                 size_t size;
80                 const void *srcaddr;
81                 const Elf_Sym *srcsym = NULL;
82                 Obj_Entry *srcobj;
83                 const Ver_Entry *ve;
84
85                 if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) {
86                         continue;
87                 }
88
89                 dstaddr = (void *) (dstobj->relocbase + rela->r_offset);
90                 dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
91                 name = dstobj->strtab + dstsym->st_name;
92                 hash = elf_hash(name);
93                 size = dstsym->st_size;
94                 ve = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
95
96                 for (srcobj = dstobj->next;  srcobj != NULL;
97                      srcobj = srcobj->next) {
98                         if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0))
99                             != NULL) {
100                                 break;
101                         }
102                 }
103
104                 if (srcobj == NULL) {
105                         _rtld_error("Undefined symbol \"%s\" "
106                                     " referenced from COPY"
107                                     " relocation in %s", name, dstobj->path);
108                         return (-1);
109                 }
110
111                 srcaddr = (const void *) (srcobj->relocbase+srcsym->st_value);
112                 memcpy(dstaddr, srcaddr, size);
113                 dbg("copy_reloc: src=%p,dst=%p,size=%d\n",srcaddr,dstaddr,size);
114         }
115
116         return (0);
117 }
118
119
120 /*
121  * Perform early relocation of the run-time linker image
122  */
123 void
124 reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
125 {
126         const Elf_Rela *rela = 0, *relalim;
127         Elf_Addr relasz = 0;
128         Elf_Addr *where;
129
130         /*
131          * Extract the rela/relasz values from the dynamic section
132          */
133         for (; dynp->d_tag != DT_NULL; dynp++) {
134                 switch (dynp->d_tag) {
135                 case DT_RELA:
136                         rela = (const Elf_Rela *)(relocbase+dynp->d_un.d_ptr);
137                         break;
138                 case DT_RELASZ:
139                         relasz = dynp->d_un.d_val;
140                         break;
141                 }
142         }
143
144         /*
145          * Relocate these values
146          */
147         relalim = (const Elf_Rela *)((caddr_t)rela + relasz);
148         for (; rela < relalim; rela++) {
149                 where = (Elf_Addr *)(relocbase + rela->r_offset);
150                 *where = (Elf_Addr)(relocbase + rela->r_addend);
151         }
152 }
153
154
155 /*
156  * Relocate a non-PLT object with addend.
157  */
158 static int
159 reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
160                     SymCache *cache)
161 {
162         Elf_Addr        *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
163         const Elf_Sym   *def;
164         const Obj_Entry *defobj;
165         Elf_Addr         tmp;
166
167         switch (ELF_R_TYPE(rela->r_info)) {
168
169         case R_PPC_NONE:
170                 break;
171
172         case R_PPC_ADDR32:    /* word32 S + A */
173         case R_PPC_GLOB_DAT:  /* word32 S + A */
174                 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
175                                   false, cache);
176                 if (def == NULL) {
177                         return (-1);
178                 }
179
180                 tmp = (Elf_Addr)(defobj->relocbase + def->st_value +
181                     rela->r_addend);
182
183                 /* Don't issue write if unnecessary; avoid COW page fault */
184                 if (*where != tmp) {
185                         *where = tmp;
186                 }
187                 break;
188
189         case R_PPC_RELATIVE:  /* word32 B + A */
190                 tmp = (Elf_Addr)(obj->relocbase + rela->r_addend);
191
192                 /* As above, don't issue write unnecessarily */
193                 if (*where != tmp) {
194                         *where = tmp;
195                 }
196                 break;
197
198         case R_PPC_COPY:
199                 /*
200                  * These are deferred until all other relocations
201                  * have been done.  All we do here is make sure
202                  * that the COPY relocation is not in a shared
203                  * library.  They are allowed only in executable
204                  * files.
205                  */
206                 if (!obj->mainprog) {
207                         _rtld_error("%s: Unexpected R_COPY "
208                                     " relocation in shared library",
209                                     obj->path);
210                         return (-1);
211                 }
212                 break;
213
214         case R_PPC_JMP_SLOT:
215                 /*
216                  * These will be handled by the plt/jmpslot routines
217                  */
218                 break;
219
220         case R_PPC_DTPMOD32:
221                 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
222                     false, cache);
223
224                 if (def == NULL)
225                         return (-1);
226
227                 *where = (Elf_Addr) defobj->tlsindex;
228
229                 break;
230
231         case R_PPC_TPREL32:
232                 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
233                     false, cache);
234
235                 if (def == NULL)
236                         return (-1);
237
238                 /*
239                  * We lazily allocate offsets for static TLS as we
240                  * see the first relocation that references the
241                  * TLS block. This allows us to support (small
242                  * amounts of) static TLS in dynamically loaded
243                  * modules. If we run out of space, we generate an
244                  * error.
245                  */
246                 if (!defobj->tls_done) {
247                         if (!allocate_tls_offset((Obj_Entry*) defobj)) {
248                                 _rtld_error("%s: No space available for static "
249                                     "Thread Local Storage", obj->path);
250                                 return (-1);
251                         }
252                 }
253
254                 *(Elf_Addr **)where = *where * sizeof(Elf_Addr)
255                     + (Elf_Addr *)(def->st_value + rela->r_addend 
256                     + defobj->tlsoffset - TLS_TP_OFFSET);
257                 
258                 break;
259                 
260         case R_PPC_DTPREL32:
261                 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
262                     false, cache);
263
264                 if (def == NULL)
265                         return (-1);
266
267                 *where += (Elf_Addr)(def->st_value + rela->r_addend 
268                     - TLS_DTV_OFFSET);
269
270                 break;
271                 
272         default:
273                 _rtld_error("%s: Unsupported relocation type %d"
274                             " in non-PLT relocations\n", obj->path,
275                             ELF_R_TYPE(rela->r_info));
276                 return (-1);
277         }
278         return (0);
279 }
280
281
282 /*
283  * Process non-PLT relocations
284  */
285 int
286 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
287 {
288         const Elf_Rela *relalim;
289         const Elf_Rela *rela;
290         SymCache *cache;
291         int bytes = obj->nchains * sizeof(SymCache);
292         int r = -1;
293
294         /*
295          * The dynamic loader may be called from a thread, we have
296          * limited amounts of stack available so we cannot use alloca().
297          */
298         if (obj != obj_rtld) {
299                 cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON,
300                     -1, 0);
301                 if (cache == MAP_FAILED)
302                         cache = NULL;
303         } else
304                 cache = NULL;
305
306         /*
307          * From the SVR4 PPC ABI:
308          * "The PowerPC family uses only the Elf32_Rela relocation
309          *  entries with explicit addends."
310          */
311         relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize);
312         for (rela = obj->rela; rela < relalim; rela++) {
313                 if (reloc_nonplt_object(obj_rtld, obj, rela, cache) < 0)
314                         goto done;
315         }
316         r = 0;
317 done:
318         if (cache) {
319                 munmap(cache, bytes);
320         }
321         return (r);
322 }
323
324 /*
325  * Initialise a PLT slot to the resolving trampoline
326  */
327 static int
328 reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela)
329 {
330         Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
331         Elf_Addr *pltresolve, *pltlongresolve, *jmptab;
332         Elf_Addr distance;
333         int N = obj->pltrelasize / sizeof(Elf_Rela);
334         int reloff;
335
336         reloff = rela - obj->pltrela;
337
338         if (reloff < 0)
339                 return (-1);
340
341         pltlongresolve = obj->pltgot + 5;
342         pltresolve = pltlongresolve + 5;
343
344         distance = (Elf_Addr)pltresolve - (Elf_Addr)(where + 1);
345
346         dbg(" reloc_plt_object: where=%p,pltres=%p,reloff=%x,distance=%x",
347             (void *)where, (void *)pltresolve, reloff, distance);
348
349         if (reloff < PLT_EXTENDED_BEGIN) {
350                 /* li   r11,reloff  */
351                 /* b    pltresolve  */
352                 where[0] = 0x39600000 | reloff;
353                 where[1] = 0x48000000 | (distance & 0x03fffffc);
354         } else {
355                 jmptab = obj->pltgot + JMPTAB_BASE(N);
356                 jmptab[reloff] = (u_int)pltlongresolve;
357
358                 /* lis  r11,jmptab[reloff]@ha */
359                 /* lwzu r12,jmptab[reloff]@l(r11) */
360                 /* mtctr r12 */
361                 /* bctr */
362                 where[0] = 0x3d600000 | _ppc_ha(&jmptab[reloff]);
363                 where[1] = 0x858b0000 | _ppc_la(&jmptab[reloff]);
364                 where[2] = 0x7d8903a6;
365                 where[3] = 0x4e800420;
366         }
367                 
368
369         /*
370          * The icache will be sync'd in init_pltgot, which is called
371          * after all the slots have been updated
372          */
373
374         return (0);
375 }
376
377
378 /*
379  * Process the PLT relocations.
380  */
381 int
382 reloc_plt(Obj_Entry *obj)
383 {
384         const Elf_Rela *relalim;
385         const Elf_Rela *rela;
386
387         if (obj->pltrelasize != 0) {
388
389                 relalim = (const Elf_Rela *)((char *)obj->pltrela +
390                     obj->pltrelasize);
391                 for (rela = obj->pltrela;  rela < relalim;  rela++) {
392                         assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
393
394                         if (reloc_plt_object(obj, rela) < 0) {
395                                 return (-1);
396                         }
397                 }
398         }
399
400         return (0);
401 }
402
403
404 /*
405  * LD_BIND_NOW was set - force relocation for all jump slots
406  */
407 int
408 reloc_jmpslots(Obj_Entry *obj)
409 {
410         const Obj_Entry *defobj;
411         const Elf_Rela *relalim;
412         const Elf_Rela *rela;
413         const Elf_Sym *def;
414         Elf_Addr *where;
415         Elf_Addr target;
416
417         relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
418         for (rela = obj->pltrela; rela < relalim; rela++) {
419                 assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
420                 where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
421                 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
422                    true, NULL);
423                 if (def == NULL) {
424                         dbg("reloc_jmpslots: sym not found");
425                         return (-1);
426                 }
427
428                 target = (Elf_Addr)(defobj->relocbase + def->st_value);
429
430 #if 0
431                 /* PG XXX */
432                 dbg("\"%s\" in \"%s\" --> %p in \"%s\"",
433                     defobj->strtab + def->st_name, basename(obj->path),
434                     (void *)target, basename(defobj->path));
435 #endif
436
437                 reloc_jmpslot(where, target, defobj, obj,
438                     (const Elf_Rel *) rela);
439         }
440
441         obj->jmpslots_done = true;
442
443         return (0);
444 }
445
446
447 /*
448  * Update the value of a PLT jump slot. Branch directly to the target if
449  * it is within +/- 32Mb, otherwise go indirectly via the pltcall
450  * trampoline call and jump table.
451  */
452 Elf_Addr
453 reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj,
454               const Obj_Entry *obj, const Elf_Rel *rel)
455 {
456         Elf_Addr offset;
457         const Elf_Rela *rela = (const Elf_Rela *) rel;
458
459         dbg(" reloc_jmpslot: where=%p, target=%p",
460             (void *)wherep, (void *)target);
461
462         /*
463          * At the PLT entry pointed at by `wherep', construct
464          * a direct transfer to the now fully resolved function
465          * address.
466          */
467         offset = target - (Elf_Addr)wherep;
468
469         if (abs(offset) < 32*1024*1024) {     /* inside 32MB? */
470                 /* b    value   # branch directly */
471                 *wherep = 0x48000000 | (offset & 0x03fffffc);
472                 __syncicache(wherep, 4);
473         } else {
474                 Elf_Addr *pltcall, *jmptab;
475                 int distance;
476                 int N = obj->pltrelasize / sizeof(Elf_Rela);
477                 int reloff = rela - obj->pltrela;
478
479                 if (reloff < 0)
480                         return (-1);
481
482                 pltcall = obj->pltgot;
483
484                 dbg(" reloc_jmpslot: indir, reloff=%x, N=%x\n",
485                     reloff, N);
486
487                 jmptab = obj->pltgot + JMPTAB_BASE(N);
488                 jmptab[reloff] = target;
489                 powerpc_mb(); /* Order jmptab update before next changes */
490
491                 if (reloff < PLT_EXTENDED_BEGIN) {
492                         /* for extended PLT entries, we keep the old code */
493
494                         distance = (Elf_Addr)pltcall - (Elf_Addr)(wherep + 1);
495
496                         /* li   r11,reloff */
497                         /* b    pltcall  # use indirect pltcall routine */
498
499                         /* first instruction same as before */
500                         wherep[1] = 0x48000000 | (distance & 0x03fffffc);
501                         __syncicache(wherep, 8);
502                 }
503         }
504
505         return (target);
506 }
507
508
509 /*
510  * Setup the plt glue routines.
511  */
512 #define PLTCALL_SIZE            20
513 #define PLTLONGRESOLVE_SIZE     20
514 #define PLTRESOLVE_SIZE         24
515
516 void
517 init_pltgot(Obj_Entry *obj)
518 {
519         Elf_Word *pltcall, *pltresolve, *pltlongresolve;
520         Elf_Word *jmptab;
521         int N = obj->pltrelasize / sizeof(Elf_Rela);
522
523         pltcall = obj->pltgot;
524
525         if (pltcall == NULL) {
526                 return;
527         }
528
529         /*
530          * From the SVR4 PPC ABI:
531          *
532          * 'The first 18 words (72 bytes) of the PLT are reserved for
533          * use by the dynamic linker.
534          *   ...
535          * 'If the executable or shared object requires N procedure
536          *  linkage table entries, the link editor shall reserve 3*N
537          *  words (12*N bytes) following the 18 reserved words. The
538          *  first 2*N of these words are the procedure linkage table
539          *  entries themselves. The static linker directs calls to bytes
540          *  (72 + (i-1)*8), for i between 1 and N inclusive. The remaining
541          *  N words (4*N bytes) are reserved for use by the dynamic linker.'
542          */
543
544         /*
545          * Copy the absolute-call assembler stub into the first part of
546          * the reserved PLT area.
547          */
548         memcpy(pltcall, _rtld_powerpc_pltcall, PLTCALL_SIZE);
549
550         /*
551          * Determine the address of the jumptable, which is the dyn-linker
552          * reserved area after the call cells. Write the absolute address
553          * of the jumptable into the absolute-call assembler code so it
554          * can determine this address.
555          */
556         jmptab = obj->pltgot + JMPTAB_BASE(N);
557         pltcall[1] |= _ppc_ha(jmptab);     /* addis 11,11,jmptab@ha */
558         pltcall[2] |= _ppc_la(jmptab);     /* lwz   11,jmptab@l(11) */
559
560         /*
561          * Skip down 20 bytes into the initial reserved area and copy
562          * in the standard resolving assembler call. Into this assembler,
563          * insert the absolute address of the _rtld_bind_start routine
564          * and the address of the relocation object.
565          *
566          * We place pltlongresolve first, so it can fix up its arguments
567          * and then fall through to the regular PLT resolver.
568          */
569         pltlongresolve = obj->pltgot + 5;
570
571         memcpy(pltlongresolve, _rtld_powerpc_pltlongresolve,
572             PLTLONGRESOLVE_SIZE);
573         pltlongresolve[0] |= _ppc_ha(jmptab);   /* lis  12,jmptab@ha    */
574         pltlongresolve[1] |= _ppc_la(jmptab);   /* addi 12,12,jmptab@l  */
575
576         pltresolve = pltlongresolve + PLTLONGRESOLVE_SIZE/sizeof(uint32_t);
577         memcpy(pltresolve, _rtld_powerpc_pltresolve, PLTRESOLVE_SIZE);
578         pltresolve[0] |= _ppc_ha(_rtld_bind_start);
579         pltresolve[1] |= _ppc_la(_rtld_bind_start);
580         pltresolve[3] |= _ppc_ha(obj);
581         pltresolve[4] |= _ppc_la(obj);
582
583         /*
584          * Sync the icache for the byte range represented by the
585          * trampoline routines and call slots.
586          */
587         __syncicache(obj->pltgot, JMPTAB_BASE(N)*4);
588 }
589
590 void
591 allocate_initial_tls(Obj_Entry *list)
592 {
593         register Elf_Addr **tp __asm__("r2");
594         Elf_Addr **_tp;
595
596         /*
597         * Fix the size of the static TLS block by using the maximum
598         * offset allocated so far and adding a bit for dynamic modules to
599         * use.
600         */
601
602         tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA;
603
604         _tp = (Elf_Addr **) ((char *) allocate_tls(list, NULL, TLS_TCB_SIZE, 8) 
605             + TLS_TP_OFFSET + TLS_TCB_SIZE);
606
607         /*
608          * XXX gcc seems to ignore 'tp = _tp;' 
609          */
610          
611         __asm __volatile("mr %0,%1" : "=r"(tp) : "r"(_tp));
612 }
613
614 void*
615 __tls_get_addr(tls_index* ti)
616 {
617         register Elf_Addr **tp __asm__("r2");
618         char *p;
619
620         p = tls_get_addr_common((Elf_Addr**)((Elf_Addr)tp - TLS_TP_OFFSET 
621             - TLS_TCB_SIZE), ti->ti_module, ti->ti_offset);
622
623         return (p + TLS_DTV_OFFSET);
624 }