]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - libexec/rtld-elf/ia64/reloc.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / libexec / rtld-elf / ia64 / reloc.c
1 /*-
2  * Copyright 1996, 1997, 1998, 1999 John D. Polstra.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  * $FreeBSD$
26  */
27
28 /*
29  * Dynamic linker for ELF.
30  *
31  * John Polstra <jdp@polstra.com>.
32  */
33
34 #include <sys/param.h>
35 #include <sys/mman.h>
36 #include <machine/ia64_cpu.h>
37
38 #include <dlfcn.h>
39 #include <err.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <stdarg.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47
48 #include "debug.h"
49 #include "rtld.h"
50
51 extern Elf_Dyn _DYNAMIC;
52
53 /*
54  * Macros for loading/storing unaligned 64-bit values.  These are
55  * needed because relocations can point to unaligned data.  This
56  * occurs in the DWARF2 exception frame tables generated by the
57  * compiler, for instance.
58  *
59  * We don't use these when relocating jump slots and GOT entries,
60  * since they are guaranteed to be aligned.
61  *
62  * XXX dfr stub for now.
63  */
64 #define load64(p)       (*(u_int64_t *) (p))
65 #define store64(p, v)   (*(u_int64_t *) (p) = (v))
66
67 /* Allocate an @fptr. */
68
69 #define FPTR_CHUNK_SIZE         64
70
71 struct fptr_chunk {
72         struct fptr fptrs[FPTR_CHUNK_SIZE];
73 };
74
75 static struct fptr_chunk first_chunk;
76 static struct fptr_chunk *current_chunk = &first_chunk;
77 static struct fptr *next_fptr = &first_chunk.fptrs[0];
78 static struct fptr *last_fptr = &first_chunk.fptrs[FPTR_CHUNK_SIZE];
79
80 /*
81  * We use static storage initially so that we don't have to call
82  * malloc during init_rtld().
83  */
84 static struct fptr *
85 alloc_fptr(Elf_Addr target, Elf_Addr gp)
86 {
87         struct fptr* fptr;
88
89         if (next_fptr == last_fptr) {
90                 current_chunk = malloc(sizeof(struct fptr_chunk));
91                 next_fptr = &current_chunk->fptrs[0];
92                 last_fptr = &current_chunk->fptrs[FPTR_CHUNK_SIZE];
93         }
94         fptr = next_fptr;
95         next_fptr++;
96         fptr->target = target;
97         fptr->gp = gp;
98         return fptr;
99 }
100
101 static struct fptr **
102 alloc_fptrs(Obj_Entry *obj, bool mapped)
103 {
104         struct fptr **fptrs;
105         size_t fbytes;
106
107         fbytes = obj->nchains * sizeof(struct fptr *);
108
109         /*
110          * Avoid malloc, if requested. Happens when relocating
111          * rtld itself on startup.
112          */
113         if (mapped) {
114                 fptrs = mmap(NULL, fbytes, PROT_READ|PROT_WRITE,
115                     MAP_ANON, -1, 0);
116                 if (fptrs == MAP_FAILED)
117                         fptrs = NULL;
118         } else {
119                 fptrs = malloc(fbytes);
120                 if (fptrs != NULL)
121                         memset(fptrs, 0, fbytes);
122         }
123
124         /*
125          * This assertion is necessary to guarantee function pointer
126          * uniqueness
127          */
128         assert(fptrs != NULL);
129
130         return (obj->priv = fptrs);
131 }
132
133 static void
134 free_fptrs(Obj_Entry *obj, bool mapped)
135 {
136         struct fptr **fptrs;
137         size_t fbytes;
138
139         fptrs  = obj->priv;
140         if (fptrs == NULL)
141                 return;
142
143         fbytes = obj->nchains * sizeof(struct fptr *);
144         if (mapped)
145                 munmap(fptrs, fbytes);
146         else
147                 free(fptrs);
148         obj->priv = NULL;
149 }
150
151 /* Relocate a non-PLT object with addend. */
152 static int
153 reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
154                   SymCache *cache)
155 {
156         struct fptr **fptrs;
157         Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset);
158
159         switch (ELF_R_TYPE(rela->r_info)) {
160         case R_IA_64_REL64LSB:
161                 /*
162                  * We handle rtld's relocations in rtld_start.S
163                  */
164                 if (obj != obj_rtld)
165                         store64(where,
166                                 load64(where) + (Elf_Addr) obj->relocbase);
167                 break;
168
169         case R_IA_64_DIR64LSB: {
170                 const Elf_Sym *def;
171                 const Obj_Entry *defobj;
172                 Elf_Addr target;
173
174                 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
175                                   false, cache);
176                 if (def == NULL)
177                         return -1;
178
179                 target = (def->st_shndx != SHN_UNDEF)
180                     ? (Elf_Addr)(defobj->relocbase + def->st_value) : 0;
181                 store64(where, target + rela->r_addend);
182                 break;
183         }
184
185         case R_IA_64_FPTR64LSB: {
186                 /*
187                  * We have to make sure that all @fptr references to
188                  * the same function are identical so that code can
189                  * compare function pointers.
190                  */
191                 const Elf_Sym *def;
192                 const Obj_Entry *defobj;
193                 struct fptr *fptr = 0;
194                 Elf_Addr target, gp;
195                 int sym_index;
196
197                 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
198                                   false, cache);
199                 if (def == NULL)
200                         return -1;
201
202                 if (def->st_shndx != SHN_UNDEF) {
203                         target = (Elf_Addr)(defobj->relocbase + def->st_value);
204                         gp = (Elf_Addr)defobj->pltgot;
205
206                         /* rtld is allowed to reference itself only */
207                         assert(!obj->rtld || obj == defobj);
208                         fptrs = defobj->priv;
209                         if (fptrs == NULL)
210                                 fptrs = alloc_fptrs((Obj_Entry *) defobj, 
211                                     obj->rtld);
212
213                         sym_index = def - defobj->symtab;
214
215                         /*
216                          * Find the @fptr, using fptrs as a helper.
217                          */
218                         if (fptrs)
219                                 fptr = fptrs[sym_index];
220                         if (!fptr) {
221                                 fptr = alloc_fptr(target, gp);
222                                 if (fptrs)
223                                         fptrs[sym_index] = fptr;
224                         }
225                 } else
226                         fptr = NULL;
227
228                 store64(where, (Elf_Addr)fptr);
229                 break;
230         }
231
232         case R_IA_64_IPLTLSB: {
233                 /*
234                  * Relocation typically used to populate C++ virtual function
235                  * tables. It creates a 128-bit function descriptor at the
236                  * specified memory address.
237                  */
238                 const Elf_Sym *def;
239                 const Obj_Entry *defobj;
240                 struct fptr *fptr;
241                 Elf_Addr target, gp;
242
243                 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
244                                   false, cache);
245                 if (def == NULL)
246                         return -1;
247
248                 if (def->st_shndx != SHN_UNDEF) {
249                         target = (Elf_Addr)(defobj->relocbase + def->st_value);
250                         gp = (Elf_Addr)defobj->pltgot;
251                 } else {
252                         target = 0;
253                         gp = 0;
254                 }
255
256                 fptr = (void*)where;
257                 store64(&fptr->target, target);
258                 store64(&fptr->gp, gp);
259                 break;
260         }
261
262         case R_IA_64_DTPMOD64LSB: {
263                 const Elf_Sym *def;
264                 const Obj_Entry *defobj;
265
266                 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
267                                   false, cache);
268                 if (def == NULL)
269                         return -1;
270
271                 store64(where, defobj->tlsindex);
272                 break;
273         }
274
275         case R_IA_64_DTPREL64LSB: {
276                 const Elf_Sym *def;
277                 const Obj_Entry *defobj;
278
279                 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
280                                   false, cache);
281                 if (def == NULL)
282                         return -1;
283
284                 store64(where, def->st_value + rela->r_addend);
285                 break;
286         }
287
288         case R_IA_64_TPREL64LSB: {
289                 const Elf_Sym *def;
290                 const Obj_Entry *defobj;
291
292                 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
293                                   false, cache);
294                 if (def == NULL)
295                         return -1;
296
297                 /*
298                  * We lazily allocate offsets for static TLS as we
299                  * see the first relocation that references the
300                  * TLS block. This allows us to support (small
301                  * amounts of) static TLS in dynamically loaded
302                  * modules. If we run out of space, we generate an
303                  * error.
304                  */
305                 if (!defobj->tls_done) {
306                         if (!allocate_tls_offset((Obj_Entry*) defobj)) {
307                                 _rtld_error("%s: No space available for static "
308                                     "Thread Local Storage", obj->path);
309                                 return -1;
310                         }
311                 }
312
313                 store64(where, defobj->tlsoffset + def->st_value + rela->r_addend);
314                 break;
315         }
316
317         case R_IA_64_NONE:
318                 break;
319
320         default:
321                 _rtld_error("%s: Unsupported relocation type %u"
322                             " in non-PLT relocations\n", obj->path,
323                             (unsigned int)ELF_R_TYPE(rela->r_info));
324                 return -1;
325         }
326
327         return(0);
328 }
329
330 /* Process the non-PLT relocations. */
331 int
332 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
333 {
334         const Elf_Rel *rellim;
335         const Elf_Rel *rel;
336         const Elf_Rela *relalim;
337         const Elf_Rela *rela;
338         SymCache *cache;
339         int bytes = obj->nchains * sizeof(SymCache);
340         int r = -1;
341
342         /*
343          * The dynamic loader may be called from a thread, we have
344          * limited amounts of stack available so we cannot use alloca().
345          */
346         cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
347         if (cache == MAP_FAILED)
348                 cache = NULL;
349
350         /* Perform relocations without addend if there are any: */
351         rellim = (const Elf_Rel *) ((caddr_t) obj->rel + obj->relsize);
352         for (rel = obj->rel;  obj->rel != NULL && rel < rellim;  rel++) {
353                 Elf_Rela locrela;
354
355                 locrela.r_info = rel->r_info;
356                 locrela.r_offset = rel->r_offset;
357                 locrela.r_addend = 0;
358                 if (reloc_non_plt_obj(obj_rtld, obj, &locrela, cache))
359                         goto done;
360         }
361
362         /* Perform relocations with addend if there are any: */
363         relalim = (const Elf_Rela *) ((caddr_t) obj->rela + obj->relasize);
364         for (rela = obj->rela;  obj->rela != NULL && rela < relalim;  rela++) {
365                 if (reloc_non_plt_obj(obj_rtld, obj, rela, cache))
366                         goto done;
367         }
368
369         r = 0;
370 done:
371         if (cache)
372                 munmap(cache, bytes);
373
374         /*
375          * Release temporarily mapped fptrs if relocating
376          * rtld object itself. A new table will be created
377          * in make_function_pointer using malloc when needed.
378          */
379         if (obj->rtld && obj->priv)
380                 free_fptrs(obj, true);
381
382         return (r);
383 }
384
385 /* Process the PLT relocations. */
386 int
387 reloc_plt(Obj_Entry *obj)
388 {
389         /* All PLT relocations are the same kind: Elf_Rel or Elf_Rela. */
390         if (obj->pltrelsize != 0) {
391                 const Elf_Rel *rellim;
392                 const Elf_Rel *rel;
393
394                 rellim = (const Elf_Rel *)
395                         ((char *)obj->pltrel + obj->pltrelsize);
396                 for (rel = obj->pltrel;  rel < rellim;  rel++) {
397                         Elf_Addr *where;
398
399                         assert(ELF_R_TYPE(rel->r_info) == R_IA_64_IPLTLSB);
400
401                         /* Relocate the @fptr pointing into the PLT. */
402                         where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
403                         *where += (Elf_Addr)obj->relocbase;
404                 }
405         } else {
406                 const Elf_Rela *relalim;
407                 const Elf_Rela *rela;
408
409                 relalim = (const Elf_Rela *)
410                         ((char *)obj->pltrela + obj->pltrelasize);
411                 for (rela = obj->pltrela;  rela < relalim;  rela++) {
412                         Elf_Addr *where;
413
414                         assert(ELF_R_TYPE(rela->r_info) == R_IA_64_IPLTLSB);
415
416                         /* Relocate the @fptr pointing into the PLT. */
417                         where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
418                         *where += (Elf_Addr)obj->relocbase;
419                 }
420         }
421         return 0;
422 }
423
424 /* Relocate the jump slots in an object. */
425 int
426 reloc_jmpslots(Obj_Entry *obj)
427 {
428         if (obj->jmpslots_done)
429                 return 0;
430         /* All PLT relocations are the same kind: Elf_Rel or Elf_Rela. */
431         if (obj->pltrelsize != 0) {
432                 const Elf_Rel *rellim;
433                 const Elf_Rel *rel;
434
435                 rellim = (const Elf_Rel *)
436                         ((char *)obj->pltrel + obj->pltrelsize);
437                 for (rel = obj->pltrel;  rel < rellim;  rel++) {
438                         Elf_Addr *where;
439                         const Elf_Sym *def;
440                         const Obj_Entry *defobj;
441
442                         assert(ELF_R_TYPE(rel->r_info) == R_IA_64_IPLTLSB);
443                         where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
444                         def = find_symdef(ELF_R_SYM(rel->r_info), obj,
445                                           &defobj, true, NULL);
446                         if (def == NULL)
447                                 return -1;
448                         reloc_jmpslot(where,
449                                       (Elf_Addr)(defobj->relocbase
450                                                  + def->st_value),
451                                       defobj, obj, rel);
452                 }
453         } else {
454                 const Elf_Rela *relalim;
455                 const Elf_Rela *rela;
456
457                 relalim = (const Elf_Rela *)
458                         ((char *)obj->pltrela + obj->pltrelasize);
459                 for (rela = obj->pltrela;  rela < relalim;  rela++) {
460                         Elf_Addr *where;
461                         const Elf_Sym *def;
462                         const Obj_Entry *defobj;
463
464                         where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
465                         def = find_symdef(ELF_R_SYM(rela->r_info), obj,
466                                           &defobj, true, NULL);
467                         if (def == NULL)
468                                 return -1;
469                         reloc_jmpslot(where,
470                                       (Elf_Addr)(defobj->relocbase
471                                                  + def->st_value),
472                                       defobj, obj, (Elf_Rel *)rela);
473                 }
474         }
475         obj->jmpslots_done = true;
476         return 0;
477 }
478
479 /* Fixup the jump slot at "where" to transfer control to "target". */
480 Elf_Addr
481 reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *obj,
482               const Obj_Entry *refobj, const Elf_Rel *rel)
483 {
484         Elf_Addr stubaddr;
485
486         dbg(" reloc_jmpslot: where=%p, target=%p, gp=%p",
487             (void *)where, (void *)target, (void *)obj->pltgot);
488         stubaddr = *where;
489         if (stubaddr != target) {
490
491                 /*
492                  * Point this @fptr directly at the target. Update the
493                  * gp value first so that we don't break another cpu
494                  * which is currently executing the PLT entry.
495                  */
496                 where[1] = (Elf_Addr) obj->pltgot;
497                 ia64_mf();
498                 where[0] = target;
499                 ia64_mf();
500         }
501
502         /*
503          * The caller needs an @fptr for the adjusted entry. The PLT
504          * entry serves this purpose nicely.
505          */
506         return (Elf_Addr) where;
507 }
508
509 /*
510  * XXX ia64 doesn't seem to have copy relocations.
511  *
512  * Returns 0 on success, -1 on failure.
513  */
514 int
515 do_copy_relocations(Obj_Entry *dstobj)
516 {
517
518         return 0;
519 }
520
521 /*
522  * Return the @fptr representing a given function symbol.
523  */
524 void *
525 make_function_pointer(const Elf_Sym *sym, const Obj_Entry *obj)
526 {
527         struct fptr **fptrs = obj->priv;
528         int index = sym - obj->symtab;
529
530         if (!fptrs) {
531                 /*
532                  * This should only happen for something like
533                  * dlsym("dlopen"). Actually, I'm not sure it can ever 
534                  * happen.
535                  */
536                 fptrs = alloc_fptrs((Obj_Entry *) obj, false);
537         }
538         if (!fptrs[index]) {
539                 Elf_Addr target, gp;
540                 target = (Elf_Addr) (obj->relocbase + sym->st_value);
541                 gp = (Elf_Addr) obj->pltgot;
542                 fptrs[index] = alloc_fptr(target, gp);
543         }
544         return fptrs[index];
545 }
546
547 void
548 call_initfini_pointer(const Obj_Entry *obj, Elf_Addr target)
549 {
550         struct fptr fptr;
551
552         fptr.gp = (Elf_Addr) obj->pltgot;
553         fptr.target = target;
554         dbg(" initfini: target=%p, gp=%p",
555             (void *) fptr.target, (void *) fptr.gp);
556         ((InitFunc) &fptr)();
557 }
558
559 /* Initialize the special PLT entries. */
560 void
561 init_pltgot(Obj_Entry *obj)
562 {
563         const Elf_Dyn *dynp;
564         Elf_Addr *pltres = 0;
565
566         /*
567          * When there are no PLT relocations, the DT_IA_64_PLT_RESERVE entry
568          * is bogus. Do not setup the BOR pointers in that case. An example
569          * of where this happens is /usr/lib/libxpg4.so.3.
570          */
571         if (obj->pltrelasize == 0 && obj->pltrelsize == 0)
572                 return;
573
574         /*
575          * Find the PLT RESERVE section.
576          */
577         for (dynp = obj->dynamic;  dynp->d_tag != DT_NULL;  dynp++) {
578                 if (dynp->d_tag == DT_IA_64_PLT_RESERVE)
579                         pltres = (u_int64_t *)
580                                 (obj->relocbase + dynp->d_un.d_ptr);
581         }
582         if (!pltres)
583                 errx(1, "Can't find DT_IA_64_PLT_RESERVE entry");
584
585         /*
586          * The PLT RESERVE section is used to get values to pass to
587          * _rtld_bind when lazy binding.
588          */
589         pltres[0] = (Elf_Addr) obj;
590         pltres[1] = FPTR_TARGET(_rtld_bind_start);
591         pltres[2] = FPTR_GP(_rtld_bind_start);
592 }
593
594 void
595 allocate_initial_tls(Obj_Entry *list)
596 {
597     void *tpval;
598
599     /*
600      * Fix the size of the static TLS block by using the maximum
601      * offset allocated so far and adding a bit for dynamic modules to
602      * use.
603      */
604     tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA;
605
606     tpval = allocate_tls(list, NULL, TLS_TCB_SIZE, 16);
607     __asm __volatile("mov r13 = %0" :: "r"(tpval));
608 }
609
610 void *__tls_get_addr(unsigned long module, unsigned long offset)
611 {
612     register Elf_Addr** tp __asm__("r13");
613
614     return tls_get_addr_common(tp, module, offset);
615 }