rtld: Implement ELF filters (DT_FILTER and DT_AUXILIARY)
[dragonfly.git] / libexec / rtld-elf / i386 / reloc.c
CommitLineData
984263bc
MD
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 *
f4f4bfd5 25 * $FreeBSD$
984263bc
MD
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>
55b88cae 36#include <sys/tls.h>
984263bc 37
9e2ee207
JS
38#include <machine/tls.h>
39
984263bc
MD
40#include <dlfcn.h>
41#include <err.h>
42#include <errno.h>
43#include <fcntl.h>
44#include <stdarg.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <unistd.h>
49
50#include "debug.h"
51#include "rtld.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
35b2b265 68 rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize);
984263bc
MD
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;
984263bc
MD
74 size_t size;
75 const void *srcaddr;
76 const Elf_Sym *srcsym;
35b2b265
JM
77 const Obj_Entry *srcobj, *defobj;
78 SymLook req;
79 int res;
984263bc
MD
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;
984263bc 84 size = dstsym->st_size;
35b2b265
JM
85 symlook_init(&req, name);
86 req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info));
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;
984263bc 93 break;
35b2b265
JM
94 }
95 }
984263bc
MD
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
35b2b265 103 srcaddr = (const void *) (defobj->relocbase + srcsym->st_value);
984263bc
MD
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
35b2b265 123reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate)
984263bc
MD
124{
125 const Elf_Rel *rellim;
126 const Elf_Rel *rel;
127 SymCache *cache;
984263bc
MD
128 int r = -1;
129
130 /*
131 * The dynamic loader may be called from a thread, we have
132 * limited amounts of stack available so we cannot use alloca().
133 */
fcf53d9b
JM
134 if (obj != obj_rtld) {
135 cache = calloc(obj->nchains, sizeof(SymCache));
136 /* No need to check for NULL here */
137 } else
984263bc 138 cache = NULL;
984263bc 139
35b2b265 140 rellim = (const Elf_Rel *) ((caddr_t) obj->rel + obj->relsize);
984263bc
MD
141 for (rel = obj->rel; rel < rellim; rel++) {
142 Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rel->r_offset);
143
144 switch (ELF_R_TYPE(rel->r_info)) {
145
146 case R_386_NONE:
147 break;
148
149 case R_386_32:
150 {
151 const Elf_Sym *def;
152 const Obj_Entry *defobj;
153
154 def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
35b2b265 155 false, cache, lockstate);
984263bc
MD
156 if (def == NULL)
157 goto done;
158
159 *where += (Elf_Addr) (defobj->relocbase + def->st_value);
160 }
161 break;
162
163 case R_386_PC32:
164 /*
165 * I don't think the dynamic linker should ever see this
166 * type of relocation. But the binutils-2.6 tools sometimes
167 * generate it.
168 */
169 {
170 const Elf_Sym *def;
171 const Obj_Entry *defobj;
172
173 def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
35b2b265 174 false, cache, lockstate);
984263bc
MD
175 if (def == NULL)
176 goto done;
177
178 *where +=
179 (Elf_Addr) (defobj->relocbase + def->st_value) -
180 (Elf_Addr) where;
181 }
182 break;
183
184 case R_386_COPY:
185 /*
186 * These are deferred until all other relocations have
187 * been done. All we do here is make sure that the COPY
188 * relocation is not in a shared library. They are allowed
189 * only in executable files.
190 */
191 if (!obj->mainprog) {
192 _rtld_error("%s: Unexpected R_386_COPY relocation"
193 " in shared library", obj->path);
194 goto done;
195 }
196 break;
197
198 case R_386_GLOB_DAT:
199 {
200 const Elf_Sym *def;
201 const Obj_Entry *defobj;
202
203 def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
35b2b265 204 false, cache, lockstate);
984263bc
MD
205 if (def == NULL)
206 goto done;
207
208 *where = (Elf_Addr) (defobj->relocbase + def->st_value);
209 }
210 break;
211
212 case R_386_RELATIVE:
213 *where += (Elf_Addr) obj->relocbase;
214 break;
215
55b88cae
DX
216 case R_386_TLS_TPOFF:
217 {
218 const Elf_Sym *def;
219 const Obj_Entry *defobj;
220
221 def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
35b2b265 222 false, cache, lockstate);
55b88cae
DX
223 if (def == NULL)
224 goto done;
225
226 /*
227 * We lazily allocate offsets for static TLS as we
228 * see the first relocation that references the
229 * TLS block. This allows us to support (small
230 * amounts of) static TLS in dynamically loaded
231 * modules. If we run out of space, we generate an
232 * error.
233 */
234 if (!defobj->tls_done) {
235 if (!allocate_tls_offset((Obj_Entry*) defobj)) {
236 _rtld_error("%s: No space available for static "
237 "Thread Local Storage", obj->path);
238 goto done;
239 }
240 }
241
242 *where += (Elf_Addr) (def->st_value - defobj->tlsoffset);
243 }
244 break;
245
923439ca
JS
246 case R_386_TLS_TPOFF32:
247 {
248 const Elf_Sym *def;
249 const Obj_Entry *defobj;
250
251 def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
252 false, cache);
253 if (def == NULL)
254 goto done;
255
256 /*
257 * We lazily allocate offsets for static TLS as we
258 * see the first relocation that references the
259 * TLS block. This allows us to support (small
260 * amounts of) static TLS in dynamically loaded
261 * modules. If we run out of space, we generate an
262 * error.
263 */
264 if (!defobj->tls_done) {
265 if (!allocate_tls_offset((Obj_Entry*) defobj)) {
266 _rtld_error("%s: No space available for static "
267 "Thread Local Storage", obj->path);
268 goto done;
269 }
270 }
271
272 *where += (Elf_Addr) (defobj->tlsoffset - def->st_value);
273 }
274 break;
275
55b88cae
DX
276 case R_386_TLS_DTPMOD32:
277 {
278 const Elf_Sym *def;
279 const Obj_Entry *defobj;
280
281 def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
35b2b265 282 false, cache, lockstate);
55b88cae
DX
283 if (def == NULL)
284 goto done;
285
286 *where += (Elf_Addr) defobj->tlsindex;
287 }
288 break;
289
290 case R_386_TLS_DTPOFF32:
291 {
292 const Elf_Sym *def;
293 const Obj_Entry *defobj;
294
295 def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
35b2b265 296 false, cache, lockstate);
55b88cae
DX
297 if (def == NULL)
298 goto done;
299
300 *where += (Elf_Addr) def->st_value;
301 }
302 break;
303
984263bc
MD
304 default:
305 _rtld_error("%s: Unsupported relocation type %d"
306 " in non-PLT relocations\n", obj->path,
307 ELF_R_TYPE(rel->r_info));
308 goto done;
309 }
310 }
311 r = 0;
312done:
fcf53d9b
JM
313 if (cache != NULL)
314 free(cache);
984263bc
MD
315 return(r);
316}
317
318/* Process the PLT relocations. */
319int
320reloc_plt(Obj_Entry *obj)
321{
322 const Elf_Rel *rellim;
323 const Elf_Rel *rel;
324
f609f035 325 rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
984263bc
MD
326 for (rel = obj->pltrel; rel < rellim; rel++) {
327 Elf_Addr *where;
328
f609f035
JM
329 switch (ELF_R_TYPE(rel->r_info)) {
330 case R_386_JMP_SLOT:
331 /* Relocate the GOT slot pointing into the PLT. */
332 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
333 *where += (Elf_Addr)obj->relocbase;
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 }
984263bc
MD
341 }
342 return 0;
343}
344
345/* Relocate the jump slots in an object. */
346int
35b2b265 347reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate)
984263bc
MD
348{
349 const Elf_Rel *rellim;
350 const Elf_Rel *rel;
351
352 if (obj->jmpslots_done)
353 return 0;
35b2b265 354 rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
984263bc 355 for (rel = obj->pltrel; rel < rellim; rel++) {
fcf53d9b 356 Elf_Addr *where, target;
984263bc
MD
357 const Elf_Sym *def;
358 const Obj_Entry *defobj;
359
f609f035
JM
360 switch (ELF_R_TYPE(rel->r_info)) {
361 case R_386_JMP_SLOT:
362 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
35b2b265
JM
363 def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, NULL,
364 lockstate);
f609f035
JM
365 if (def == NULL)
366 return (-1);
367 target = (Elf_Addr)(defobj->relocbase + def->st_value);
368 reloc_jmpslot(where, target, defobj, obj, rel);
369 break;
370
371 default:
372 _rtld_error("Unknown relocation type %x in PLT",
373 ELF_R_TYPE(rel->r_info));
374 return (-1);
375 }
984263bc 376 }
f609f035 377
984263bc
MD
378 obj->jmpslots_done = true;
379 return 0;
380}
55b88cae 381
55b88cae
DX
382/* GNU ABI */
383__attribute__((__regparm__(1)))
bc633d63
MD
384void *
385___tls_get_addr(tls_index *ti)
55b88cae 386{
bc633d63 387 struct tls_tcb *tcb;
55b88cae 388
9e2ee207 389 tcb = tls_get_tcb();
18d39a4f 390 return tls_get_addr_common((Elf_Addr **)&tcb->tcb_dtv, ti->ti_module, ti->ti_offset);
55b88cae
DX
391}
392
393/* Sun ABI */
bc633d63
MD
394void *
395__tls_get_addr(tls_index *ti)
55b88cae 396{
bc633d63 397 struct tls_tcb *tcb;
55b88cae 398
9e2ee207 399 tcb = tls_get_tcb();
18d39a4f 400 return tls_get_addr_common((Elf_Addr **)&tcb->tcb_dtv, ti->ti_module, ti->ti_offset);
55b88cae 401}
bc633d63 402
a1eee96a
MD
403/* Sun ABI */
404void *
405__tls_get_addr_tcb(struct tls_tcb *tcb, tls_index *ti)
406{
18d39a4f 407 return tls_get_addr_common((Elf_Addr **)&tcb->tcb_dtv, ti->ti_module, ti->ti_offset);
a1eee96a 408}