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