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