]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - libexec/rtld-elf/amd64/reloc.c
MFC r280816:
[FreeBSD/stable/10.git] / libexec / rtld-elf / amd64 / 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/sysarch.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 #include "rtld_tls.h"
51
52 /*
53  * Process the special R_X86_64_COPY relocations in the main program.  These
54  * copy data from a shared object into a region in the main program's BSS
55  * segment.
56  *
57  * Returns 0 on success, -1 on failure.
58  */
59 int
60 do_copy_relocations(Obj_Entry *dstobj)
61 {
62     const Elf_Rela *relalim;
63     const Elf_Rela *rela;
64
65     assert(dstobj->mainprog);   /* COPY relocations are invalid elsewhere */
66
67     relalim = (const Elf_Rela *) ((caddr_t) dstobj->rela + dstobj->relasize);
68     for (rela = dstobj->rela;  rela < relalim;  rela++) {
69         if (ELF_R_TYPE(rela->r_info) == R_X86_64_COPY) {
70             void *dstaddr;
71             const Elf_Sym *dstsym;
72             const char *name;
73             size_t size;
74             const void *srcaddr;
75             const Elf_Sym *srcsym;
76             const Obj_Entry *srcobj, *defobj;
77             SymLook req;
78             int res;
79
80             dstaddr = (void *) (dstobj->relocbase + rela->r_offset);
81             dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
82             name = dstobj->strtab + dstsym->st_name;
83             size = dstsym->st_size;
84             symlook_init(&req, name);
85             req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
86             req.flags = SYMLOOK_EARLY;
87
88             for (srcobj = dstobj->next;  srcobj != NULL;  srcobj = srcobj->next) {
89                 res = symlook_obj(&req, srcobj);
90                 if (res == 0) {
91                     srcsym = req.sym_out;
92                     defobj = req.defobj_out;
93                     break;
94                 }
95             }
96
97             if (srcobj == NULL) {
98                 _rtld_error("Undefined symbol \"%s\" referenced from COPY"
99                   " relocation in %s", name, dstobj->path);
100                 return -1;
101             }
102
103             srcaddr = (const void *) (defobj->relocbase + srcsym->st_value);
104             memcpy(dstaddr, srcaddr, size);
105         }
106     }
107
108     return 0;
109 }
110
111 /* Initialize the special GOT entries. */
112 void
113 init_pltgot(Obj_Entry *obj)
114 {
115     if (obj->pltgot != NULL) {
116         obj->pltgot[1] = (Elf_Addr) obj;
117         obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
118     }
119 }
120
121 /* Process the non-PLT relocations. */
122 int
123 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
124     RtldLockState *lockstate)
125 {
126         const Elf_Rela *relalim;
127         const Elf_Rela *rela;
128         SymCache *cache;
129         const Elf_Sym *def;
130         const Obj_Entry *defobj;
131         Elf_Addr *where, symval;
132         Elf32_Addr *where32;
133         int r;
134
135         r = -1;
136         /*
137          * The dynamic loader may be called from a thread, we have
138          * limited amounts of stack available so we cannot use alloca().
139          */
140         if (obj != obj_rtld) {
141                 cache = calloc(obj->dynsymcount, sizeof(SymCache));
142                 /* No need to check for NULL here */
143         } else
144                 cache = NULL;
145
146         relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize);
147         for (rela = obj->rela;  rela < relalim;  rela++) {
148                 /*
149                  * First, resolve symbol for relocations which
150                  * reference symbols.
151                  */
152                 switch (ELF_R_TYPE(rela->r_info)) {
153                 case R_X86_64_64:
154                 case R_X86_64_PC32:
155                 case R_X86_64_GLOB_DAT:
156                 case R_X86_64_TPOFF64:
157                 case R_X86_64_TPOFF32:
158                 case R_X86_64_DTPMOD64:
159                 case R_X86_64_DTPOFF64:
160                 case R_X86_64_DTPOFF32:
161                         def = find_symdef(ELF_R_SYM(rela->r_info), obj,
162                             &defobj, flags, cache, lockstate);
163                         if (def == NULL)
164                                 goto done;
165                         /*
166                          * If symbol is IFUNC, only perform relocation
167                          * when caller allowed it by passing
168                          * SYMLOOK_IFUNC flag.  Skip the relocations
169                          * otherwise.
170                          *
171                          * Also error out in case IFUNC relocations
172                          * are specified for TLS, which cannot be
173                          * usefully interpreted.
174                          */
175                         if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
176                                 switch (ELF_R_TYPE(rela->r_info)) {
177                                 case R_X86_64_64:
178                                 case R_X86_64_PC32:
179                                 case R_X86_64_GLOB_DAT:
180                                         if ((flags & SYMLOOK_IFUNC) == 0) {
181                                                 obj->non_plt_gnu_ifunc = true;
182                                                 continue;
183                                         }
184                                         symval = (Elf_Addr)rtld_resolve_ifunc(
185                                             defobj, def);
186                                         break;
187                                 case R_X86_64_TPOFF64:
188                                 case R_X86_64_TPOFF32:
189                                 case R_X86_64_DTPMOD64:
190                                 case R_X86_64_DTPOFF64:
191                                 case R_X86_64_DTPOFF32:
192                                         _rtld_error("%s: IFUNC for TLS reloc",
193                                             obj->path);
194                                         goto done;
195                                 }
196                         } else {
197                                 if ((flags & SYMLOOK_IFUNC) != 0)
198                                         continue;
199                                 symval = (Elf_Addr)defobj->relocbase +
200                                     def->st_value;
201                         }
202                         break;
203                 default:
204                         if ((flags & SYMLOOK_IFUNC) != 0)
205                                 continue;
206                         break;
207                 }
208                 where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
209                 where32 = (Elf32_Addr *)where;
210
211                 switch (ELF_R_TYPE(rela->r_info)) {
212                 case R_X86_64_NONE:
213                         break;
214                 case R_X86_64_64:
215                         *where = symval + rela->r_addend;
216                         break;
217                 case R_X86_64_PC32:
218                         /*
219                          * I don't think the dynamic linker should
220                          * ever see this type of relocation.  But the
221                          * binutils-2.6 tools sometimes generate it.
222                          */
223                         *where32 = (Elf32_Addr)(unsigned long)(symval +
224                             rela->r_addend - (Elf_Addr)where);
225                         break;
226                 /* missing: R_X86_64_GOT32 R_X86_64_PLT32 */
227                 case R_X86_64_COPY:
228                         /*
229                          * These are deferred until all other relocations have
230                          * been done.  All we do here is make sure that the COPY
231                          * relocation is not in a shared library.  They are allowed
232                          * only in executable files.
233                          */
234                         if (!obj->mainprog) {
235                                 _rtld_error("%s: Unexpected R_X86_64_COPY "
236                                     "relocation in shared library", obj->path);
237                                 goto done;
238                         }
239                         break;
240                 case R_X86_64_GLOB_DAT:
241                         *where = symval;
242                         break;
243                 case R_X86_64_TPOFF64:
244                         /*
245                          * We lazily allocate offsets for static TLS
246                          * as we see the first relocation that
247                          * references the TLS block. This allows us to
248                          * support (small amounts of) static TLS in
249                          * dynamically loaded modules. If we run out
250                          * of space, we generate an error.
251                          */
252                         if (!defobj->tls_done) {
253                                 if (!allocate_tls_offset((Obj_Entry*) defobj)) {
254                                         _rtld_error("%s: No space available "
255                                             "for static Thread Local Storage",
256                                             obj->path);
257                                         goto done;
258                                 }
259                         }
260                         *where = (Elf_Addr)(def->st_value - defobj->tlsoffset +
261                             rela->r_addend);
262                         break;
263                 case R_X86_64_TPOFF32:
264                         /*
265                          * We lazily allocate offsets for static TLS
266                          * as we see the first relocation that
267                          * references the TLS block. This allows us to
268                          * support (small amounts of) static TLS in
269                          * dynamically loaded modules. If we run out
270                          * of space, we generate an error.
271                          */
272                         if (!defobj->tls_done) {
273                                 if (!allocate_tls_offset((Obj_Entry*) defobj)) {
274                                         _rtld_error("%s: No space available "
275                                             "for static Thread Local Storage",
276                                             obj->path);
277                                         goto done;
278                                 }
279                         }
280                         *where32 = (Elf32_Addr)(def->st_value -
281                             defobj->tlsoffset + rela->r_addend);
282                         break;
283                 case R_X86_64_DTPMOD64:
284                         *where += (Elf_Addr)defobj->tlsindex;
285                         break;
286                 case R_X86_64_DTPOFF64:
287                         *where += (Elf_Addr)(def->st_value + rela->r_addend);
288                         break;
289                 case R_X86_64_DTPOFF32:
290                         *where32 += (Elf32_Addr)(def->st_value +
291                             rela->r_addend);
292                         break;
293                 case R_X86_64_RELATIVE:
294                         *where = (Elf_Addr)(obj->relocbase + rela->r_addend);
295                         break;
296                 /*
297                  * missing:
298                  * R_X86_64_GOTPCREL, R_X86_64_32, R_X86_64_32S, R_X86_64_16,
299                  * R_X86_64_PC16, R_X86_64_8, R_X86_64_PC8
300                  */
301                 default:
302                         _rtld_error("%s: Unsupported relocation type %u"
303                             " in non-PLT relocations\n", obj->path,
304                             (unsigned int)ELF_R_TYPE(rela->r_info));
305                         goto done;
306                 }
307         }
308         r = 0;
309 done:
310         free(cache);
311         return (r);
312 }
313
314 /* Process the PLT relocations. */
315 int
316 reloc_plt(Obj_Entry *obj)
317 {
318     const Elf_Rela *relalim;
319     const Elf_Rela *rela;
320
321     relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
322     for (rela = obj->pltrela;  rela < relalim;  rela++) {
323         Elf_Addr *where;
324
325         switch(ELF_R_TYPE(rela->r_info)) {
326         case R_X86_64_JMP_SLOT:
327           /* Relocate the GOT slot pointing into the PLT. */
328           where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
329           *where += (Elf_Addr)obj->relocbase;
330           break;
331
332         case R_X86_64_IRELATIVE:
333           obj->irelative = true;
334           break;
335
336         default:
337           _rtld_error("Unknown relocation type %x in PLT",
338             (unsigned int)ELF_R_TYPE(rela->r_info));
339           return (-1);
340         }
341     }
342     return 0;
343 }
344
345 /* Relocate the jump slots in an object. */
346 int
347 reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
348 {
349     const Elf_Rela *relalim;
350     const Elf_Rela *rela;
351
352     if (obj->jmpslots_done)
353         return 0;
354     relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
355     for (rela = obj->pltrela;  rela < relalim;  rela++) {
356         Elf_Addr *where, target;
357         const Elf_Sym *def;
358         const Obj_Entry *defobj;
359
360         switch (ELF_R_TYPE(rela->r_info)) {
361         case R_X86_64_JMP_SLOT:
362           where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
363           def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
364                 SYMLOOK_IN_PLT | flags, NULL, lockstate);
365           if (def == NULL)
366               return (-1);
367           if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
368               obj->gnu_ifunc = true;
369               continue;
370           }
371           target = (Elf_Addr)(defobj->relocbase + def->st_value + rela->r_addend);
372           reloc_jmpslot(where, target, defobj, obj, (const Elf_Rel *)rela);
373           break;
374
375         case R_X86_64_IRELATIVE:
376           break;
377
378         default:
379           _rtld_error("Unknown relocation type %x in PLT",
380             (unsigned int)ELF_R_TYPE(rela->r_info));
381           return (-1);
382         }
383     }
384     obj->jmpslots_done = true;
385     return 0;
386 }
387
388 int
389 reloc_iresolve(Obj_Entry *obj, RtldLockState *lockstate)
390 {
391     const Elf_Rela *relalim;
392     const Elf_Rela *rela;
393
394     if (!obj->irelative)
395         return (0);
396     relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
397     for (rela = obj->pltrela;  rela < relalim;  rela++) {
398         Elf_Addr *where, target, *ptr;
399
400         switch (ELF_R_TYPE(rela->r_info)) {
401         case R_X86_64_JMP_SLOT:
402           break;
403
404         case R_X86_64_IRELATIVE:
405           ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend);
406           where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
407           lock_release(rtld_bind_lock, lockstate);
408           target = ((Elf_Addr (*)(void))ptr)();
409           wlock_acquire(rtld_bind_lock, lockstate);
410           *where = target;
411           break;
412         }
413     }
414     obj->irelative = false;
415     return (0);
416 }
417
418 int
419 reloc_gnu_ifunc(Obj_Entry *obj, int flags, RtldLockState *lockstate)
420 {
421     const Elf_Rela *relalim;
422     const Elf_Rela *rela;
423
424     if (!obj->gnu_ifunc)
425         return (0);
426     relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
427     for (rela = obj->pltrela;  rela < relalim;  rela++) {
428         Elf_Addr *where, target;
429         const Elf_Sym *def;
430         const Obj_Entry *defobj;
431
432         switch (ELF_R_TYPE(rela->r_info)) {
433         case R_X86_64_JMP_SLOT:
434           where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
435           def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
436                 SYMLOOK_IN_PLT | flags, NULL, lockstate);
437           if (def == NULL)
438               return (-1);
439           if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC)
440               continue;
441           lock_release(rtld_bind_lock, lockstate);
442           target = (Elf_Addr)rtld_resolve_ifunc(defobj, def);
443           wlock_acquire(rtld_bind_lock, lockstate);
444           reloc_jmpslot(where, target, defobj, obj, (const Elf_Rel *)rela);
445           break;
446         }
447     }
448     obj->gnu_ifunc = false;
449     return (0);
450 }
451
452 void
453 allocate_initial_tls(Obj_Entry *objs)
454 {
455     /*
456      * Fix the size of the static TLS block by using the maximum
457      * offset allocated so far and adding a bit for dynamic modules to
458      * use.
459      */
460     tls_static_space = tls_last_offset + RTLD_STATIC_TLS_EXTRA;
461     amd64_set_fsbase(allocate_tls(objs, 0,
462                                   3*sizeof(Elf_Addr), sizeof(Elf_Addr)));
463 }
464
465 void *__tls_get_addr(tls_index *ti)
466 {
467     Elf_Addr** segbase;
468
469     __asm __volatile("movq %%fs:0, %0" : "=r" (segbase));
470
471     return tls_get_addr_common(&segbase[1], ti->ti_module, ti->ti_offset);
472 }