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