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