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/i386/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/segments.h>
37#include <machine/sysarch.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_386_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_Rel *rellim;
64    const Elf_Rel *rel;
65
66    assert(dstobj->mainprog);	/* COPY relocations are invalid elsewhere */
67
68    rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize);
69    for (rel = dstobj->rel;  rel < rellim;  rel++) {
70	if (ELF_R_TYPE(rel->r_info) == R_386_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 + rel->r_offset);
82	    dstsym = dstobj->symtab + ELF_R_SYM(rel->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(rel->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_Rel *rellim;
129	const Elf_Rel *rel;
130	SymCache *cache;
131	const Elf_Sym *def;
132	const Obj_Entry *defobj;
133	Elf_Addr *where, symval, add;
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	rellim = (const Elf_Rel *)((caddr_t) obj->rel + obj->relsize);
148	for (rel = obj->rel;  rel < rellim;  rel++) {
149		switch (ELF_R_TYPE(rel->r_info)) {
150		case R_386_32:
151		case R_386_PC32:
152		case R_386_GLOB_DAT:
153		case R_386_TLS_TPOFF:
154		case R_386_TLS_TPOFF32:
155		case R_386_TLS_DTPMOD32:
156		case R_386_TLS_DTPOFF32:
157			def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
158			    flags, cache, lockstate);
159			if (def == NULL)
160				goto done;
161			if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
162				switch (ELF_R_TYPE(rel->r_info)) {
163				case R_386_32:
164				case R_386_PC32:
165				case R_386_GLOB_DAT:
166					if ((flags & SYMLOOK_IFUNC) == 0) {
167						obj->non_plt_gnu_ifunc = true;
168						continue;
169					}
170					symval = (Elf_Addr)rtld_resolve_ifunc(
171					    defobj, def);
172					break;
173				case R_386_TLS_TPOFF:
174				case R_386_TLS_TPOFF32:
175				case R_386_TLS_DTPMOD32:
176				case R_386_TLS_DTPOFF32:
177					_rtld_error("%s: IFUNC for TLS reloc",
178					    obj->path);
179					goto done;
180				}
181			} else {
182				if ((flags & SYMLOOK_IFUNC) != 0)
183					continue;
184				symval = (Elf_Addr)defobj->relocbase +
185				    def->st_value;
186			}
187			break;
188		default:
189			if ((flags & SYMLOOK_IFUNC) != 0)
190				continue;
191			break;
192		}
193		where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
194
195		switch (ELF_R_TYPE(rel->r_info)) {
196		case R_386_NONE:
197			break;
198		case R_386_32:
199			*where += symval;
200			break;
201		case R_386_PC32:
202		    /*
203		     * I don't think the dynamic linker should ever
204		     * see this type of relocation.  But the
205		     * binutils-2.6 tools sometimes generate it.
206		     */
207		    *where += symval - (Elf_Addr)where;
208		    break;
209		case R_386_COPY:
210			/*
211			 * These are deferred until all other
212			 * relocations have been done.  All we do here
213			 * is make sure that the COPY relocation is
214			 * not in a shared library.  They are allowed
215			 * only in executable files.
216			 */
217			if (!obj->mainprog) {
218				_rtld_error("%s: Unexpected R_386_COPY "
219				    "relocation in shared library", obj->path);
220				goto done;
221			}
222			break;
223		case R_386_GLOB_DAT:
224			*where = symval;
225			break;
226		case R_386_RELATIVE:
227			*where += (Elf_Addr)obj->relocbase;
228			break;
229		case R_386_TLS_TPOFF:
230		case R_386_TLS_TPOFF32:
231			/*
232			 * We lazily allocate offsets for static TLS
233			 * as we see the first relocation that
234			 * references the TLS block. This allows us to
235			 * support (small amounts of) static TLS in
236			 * dynamically loaded modules. If we run out
237			 * of space, we generate an error.
238			 */
239			if (!defobj->tls_done) {
240				if (!allocate_tls_offset((Obj_Entry*) defobj)) {
241					_rtld_error("%s: No space available "
242					    "for static Thread Local Storage",
243					    obj->path);
244					goto done;
245				}
246			}
247			add = (Elf_Addr)(def->st_value - defobj->tlsoffset);
248			if (ELF_R_TYPE(rel->r_info) == R_386_TLS_TPOFF)
249				*where += add;
250			else
251				*where -= add;
252			break;
253		case R_386_TLS_DTPMOD32:
254			*where += (Elf_Addr)defobj->tlsindex;
255			break;
256		case R_386_TLS_DTPOFF32:
257			*where += (Elf_Addr) def->st_value;
258			break;
259		default:
260			_rtld_error("%s: Unsupported relocation type %d"
261			    " in non-PLT relocations\n", obj->path,
262			    ELF_R_TYPE(rel->r_info));
263			goto done;
264		}
265	}
266	r = 0;
267done:
268	free(cache);
269	return (r);
270}
271
272/* Process the PLT relocations. */
273int
274reloc_plt(Obj_Entry *obj)
275{
276    const Elf_Rel *rellim;
277    const Elf_Rel *rel;
278
279    rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
280    for (rel = obj->pltrel;  rel < rellim;  rel++) {
281	Elf_Addr *where/*, val*/;
282
283	switch (ELF_R_TYPE(rel->r_info)) {
284	case R_386_JMP_SLOT:
285	  /* Relocate the GOT slot pointing into the PLT. */
286	  where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
287	  *where += (Elf_Addr)obj->relocbase;
288	  break;
289
290	case R_386_IRELATIVE:
291	  obj->irelative = true;
292	  break;
293
294	default:
295	  _rtld_error("Unknown relocation type %x in PLT",
296	    ELF_R_TYPE(rel->r_info));
297	  return (-1);
298	}
299    }
300    return 0;
301}
302
303/* Relocate the jump slots in an object. */
304int
305reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
306{
307    const Elf_Rel *rellim;
308    const Elf_Rel *rel;
309
310    if (obj->jmpslots_done)
311	return 0;
312    rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
313    for (rel = obj->pltrel;  rel < rellim;  rel++) {
314	Elf_Addr *where, target;
315	const Elf_Sym *def;
316	const Obj_Entry *defobj;
317
318	switch (ELF_R_TYPE(rel->r_info)) {
319	case R_386_JMP_SLOT:
320	  where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
321	  def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
322		SYMLOOK_IN_PLT | flags, NULL, lockstate);
323	  if (def == NULL)
324	      return (-1);
325	  if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
326	      obj->gnu_ifunc = true;
327	      continue;
328	  }
329	  target = (Elf_Addr)(defobj->relocbase + def->st_value);
330	  reloc_jmpslot(where, target, defobj, obj, rel);
331	  break;
332
333	case R_386_IRELATIVE:
334	  break;
335
336	default:
337	  _rtld_error("Unknown relocation type %x in PLT",
338	    ELF_R_TYPE(rel->r_info));
339	  return (-1);
340	}
341    }
342
343    obj->jmpslots_done = true;
344    return 0;
345}
346
347int
348reloc_iresolve(Obj_Entry *obj, RtldLockState *lockstate)
349{
350    const Elf_Rel *rellim;
351    const Elf_Rel *rel;
352    Elf_Addr *where, target;
353
354    if (!obj->irelative)
355	return (0);
356    rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
357    for (rel = obj->pltrel;  rel < rellim;  rel++) {
358	switch (ELF_R_TYPE(rel->r_info)) {
359	case R_386_IRELATIVE:
360	  where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
361	  lock_release(rtld_bind_lock, lockstate);
362	  target = ((Elf_Addr (*)(void))(obj->relocbase + *where))();
363	  wlock_acquire(rtld_bind_lock, lockstate);
364	  *where = target;
365	  break;
366	}
367    }
368    obj->irelative = false;
369    return (0);
370}
371
372int
373reloc_gnu_ifunc(Obj_Entry *obj, int flags, RtldLockState *lockstate)
374{
375    const Elf_Rel *rellim;
376    const Elf_Rel *rel;
377
378    if (!obj->gnu_ifunc)
379	return (0);
380    rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
381    for (rel = obj->pltrel;  rel < rellim;  rel++) {
382	Elf_Addr *where, target;
383	const Elf_Sym *def;
384	const Obj_Entry *defobj;
385
386	switch (ELF_R_TYPE(rel->r_info)) {
387	case R_386_JMP_SLOT:
388	  where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
389	  def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
390		SYMLOOK_IN_PLT | flags, NULL, lockstate);
391	  if (def == NULL)
392	      return (-1);
393	  if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC)
394	      continue;
395	  lock_release(rtld_bind_lock, lockstate);
396	  target = (Elf_Addr)rtld_resolve_ifunc(defobj, def);
397	  wlock_acquire(rtld_bind_lock, lockstate);
398	  reloc_jmpslot(where, target, defobj, obj, rel);
399	  break;
400	}
401    }
402
403    obj->gnu_ifunc = false;
404    return (0);
405}
406
407void
408allocate_initial_tls(Obj_Entry *objs)
409{
410    void* tls;
411
412    /*
413     * Fix the size of the static TLS block by using the maximum
414     * offset allocated so far and adding a bit for dynamic modules to
415     * use.
416     */
417    tls_static_space = tls_last_offset + RTLD_STATIC_TLS_EXTRA;
418    tls = allocate_tls(objs, NULL, 3*sizeof(Elf_Addr), sizeof(Elf_Addr));
419    i386_set_gsbase(tls);
420}
421
422/* GNU ABI */
423__attribute__((__regparm__(1)))
424void *___tls_get_addr(tls_index *ti)
425{
426    Elf_Addr** segbase;
427
428    __asm __volatile("movl %%gs:0, %0" : "=r" (segbase));
429
430    return tls_get_addr_common(&segbase[1], ti->ti_module, ti->ti_offset);
431}
432
433/* Sun ABI */
434void *__tls_get_addr(tls_index *ti)
435{
436    Elf_Addr** segbase;
437
438    __asm __volatile("movl %%gs:0, %0" : "=r" (segbase));
439
440    return tls_get_addr_common(&segbase[1], ti->ti_module, ti->ti_offset);
441}
442