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