1 /*-
2 * Copyright (c) 2014-2015 The FreeBSD Foundation
3 *
4 * Portions of this software were developed by Andrew Turner
5 * under sponsorship from the FreeBSD Foundation.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 #include <sys/types.h>
31
32 #include <stdlib.h>
33
34 #include "debug.h"
35 #include "rtld.h"
36 #include "rtld_printf.h"
37
38 /*
39 * It is possible for the compiler to emit relocations for unaligned data.
40 * We handle this situation with these inlines.
41 */
42 #define RELOC_ALIGNED_P(x) \
43 (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
44
45 /*
46 * This is not the correct prototype, but we only need it for
47 * a function pointer to a simple asm function.
48 */
49 void *_rtld_tlsdesc_static(void *);
50 void *_rtld_tlsdesc_undef(void *);
51 void *_rtld_tlsdesc_dynamic(void *);
52
53 void _exit(int);
54
55 void
init_pltgot(Obj_Entry * obj)56 init_pltgot(Obj_Entry *obj)
57 {
58
59 if (obj->pltgot != NULL) {
60 obj->pltgot[1] = (Elf_Addr) obj;
61 obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
62 }
63 }
64
65 int
do_copy_relocations(Obj_Entry * dstobj)66 do_copy_relocations(Obj_Entry *dstobj)
67 {
68 const Obj_Entry *srcobj, *defobj;
69 const Elf_Rela *relalim;
70 const Elf_Rela *rela;
71 const Elf_Sym *srcsym;
72 const Elf_Sym *dstsym;
73 const void *srcaddr;
74 const char *name;
75 void *dstaddr;
76 SymLook req;
77 size_t size;
78 int res;
79
80 /*
81 * COPY relocs are invalid outside of the main program
82 */
83 assert(dstobj->mainprog);
84
85 relalim = (const Elf_Rela *)((const char *)dstobj->rela +
86 dstobj->relasize);
87 for (rela = dstobj->rela; rela < relalim; rela++) {
88 if (ELF_R_TYPE(rela->r_info) != R_AARCH64_COPY)
89 continue;
90
91 dstaddr = (void *)(dstobj->relocbase + rela->r_offset);
92 dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
93 name = dstobj->strtab + dstsym->st_name;
94 size = dstsym->st_size;
95
96 symlook_init(&req, name);
97 req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
98 req.flags = SYMLOOK_EARLY;
99
100 for (srcobj = globallist_next(dstobj); srcobj != NULL;
101 srcobj = globallist_next(srcobj)) {
102 res = symlook_obj(&req, srcobj);
103 if (res == 0) {
104 srcsym = req.sym_out;
105 defobj = req.defobj_out;
106 break;
107 }
108 }
109 if (srcobj == NULL) {
110 _rtld_error("Undefined symbol \"%s\" referenced from "
111 "COPY relocation in %s", name, dstobj->path);
112 return (-1);
113 }
114
115 srcaddr = (const void *)(defobj->relocbase + srcsym->st_value);
116 memcpy(dstaddr, srcaddr, size);
117 }
118
119 return (0);
120 }
121
122 struct tls_data {
123 Elf_Addr dtv_gen;
124 int tls_index;
125 Elf_Addr tls_offs;
126 };
127
128 static Elf_Addr
reloc_tlsdesc_alloc(int tlsindex,Elf_Addr tlsoffs)129 reloc_tlsdesc_alloc(int tlsindex, Elf_Addr tlsoffs)
130 {
131 struct tls_data *tlsdesc;
132
133 tlsdesc = xmalloc(sizeof(struct tls_data));
134 tlsdesc->dtv_gen = tls_dtv_generation;
135 tlsdesc->tls_index = tlsindex;
136 tlsdesc->tls_offs = tlsoffs;
137
138 return ((Elf_Addr)tlsdesc);
139 }
140
141 static void
reloc_tlsdesc(const Obj_Entry * obj,const Elf_Rela * rela,Elf_Addr * where,int flags,RtldLockState * lockstate)142 reloc_tlsdesc(const Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *where,
143 int flags, RtldLockState *lockstate)
144 {
145 const Elf_Sym *def;
146 const Obj_Entry *defobj;
147 Elf_Addr offs;
148
149
150 offs = 0;
151 if (ELF_R_SYM(rela->r_info) != 0) {
152 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, flags,
153 NULL, lockstate);
154 if (def == NULL)
155 rtld_die();
156 offs = def->st_value;
157 obj = defobj;
158 if (def->st_shndx == SHN_UNDEF) {
159 /* Weak undefined thread variable */
160 where[0] = (Elf_Addr)_rtld_tlsdesc_undef;
161 where[1] = rela->r_addend;
162 return;
163 }
164 }
165 offs += rela->r_addend;
166
167 if (obj->tlsoffset != 0) {
168 /* Variable is in initialy allocated TLS segment */
169 where[0] = (Elf_Addr)_rtld_tlsdesc_static;
170 where[1] = obj->tlsoffset + offs;
171 } else {
172 /* TLS offest is unknown at load time, use dynamic resolving */
173 where[0] = (Elf_Addr)_rtld_tlsdesc_dynamic;
174 where[1] = reloc_tlsdesc_alloc(obj->tlsindex, offs);
175 }
176 }
177
178 /*
179 * Process the PLT relocations.
180 */
181 int
reloc_plt(Obj_Entry * obj,int flags,RtldLockState * lockstate)182 reloc_plt(Obj_Entry *obj, int flags, RtldLockState *lockstate)
183 {
184 const Elf_Rela *relalim;
185 const Elf_Rela *rela;
186
187 relalim = (const Elf_Rela *)((const char *)obj->pltrela +
188 obj->pltrelasize);
189 for (rela = obj->pltrela; rela < relalim; rela++) {
190 Elf_Addr *where;
191
192 where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
193
194 switch(ELF_R_TYPE(rela->r_info)) {
195 case R_AARCH64_JUMP_SLOT:
196 *where += (Elf_Addr)obj->relocbase;
197 break;
198 case R_AARCH64_TLSDESC:
199 reloc_tlsdesc(obj, rela, where, SYMLOOK_IN_PLT | flags,
200 lockstate);
201 break;
202 case R_AARCH64_IRELATIVE:
203 obj->irelative = true;
204 break;
205 case R_AARCH64_NONE:
206 break;
207 default:
208 _rtld_error("Unknown relocation type %u in PLT",
209 (unsigned int)ELF_R_TYPE(rela->r_info));
210 return (-1);
211 }
212 }
213
214 return (0);
215 }
216
217 /*
218 * LD_BIND_NOW was set - force relocation for all jump slots
219 */
220 int
reloc_jmpslots(Obj_Entry * obj,int flags,RtldLockState * lockstate)221 reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
222 {
223 const Obj_Entry *defobj;
224 const Elf_Rela *relalim;
225 const Elf_Rela *rela;
226 const Elf_Sym *def;
227
228 if (obj->jmpslots_done)
229 return (0);
230
231 relalim = (const Elf_Rela *)((const char *)obj->pltrela +
232 obj->pltrelasize);
233 for (rela = obj->pltrela; rela < relalim; rela++) {
234 Elf_Addr *where, target;
235
236 where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
237 switch(ELF_R_TYPE(rela->r_info)) {
238 case R_AARCH64_JUMP_SLOT:
239 def = find_symdef(ELF_R_SYM(rela->r_info), obj,
240 &defobj, SYMLOOK_IN_PLT | flags, NULL, lockstate);
241 if (def == NULL)
242 return (-1);
243 if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
244 obj->gnu_ifunc = true;
245 continue;
246 }
247 target = (Elf_Addr)(defobj->relocbase + def->st_value);
248 reloc_jmpslot(where, target, defobj, obj,
249 (const Elf_Rel *)rela);
250 break;
251 }
252 }
253 obj->jmpslots_done = true;
254
255 return (0);
256 }
257
258 static void
reloc_iresolve_one(Obj_Entry * obj,const Elf_Rela * rela,RtldLockState * lockstate)259 reloc_iresolve_one(Obj_Entry *obj, const Elf_Rela *rela,
260 RtldLockState *lockstate)
261 {
262 Elf_Addr *where, target, *ptr;
263
264 ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend);
265 where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
266 lock_release(rtld_bind_lock, lockstate);
267 target = call_ifunc_resolver(ptr);
268 wlock_acquire(rtld_bind_lock, lockstate);
269 *where = target;
270 }
271
272 int
reloc_iresolve(Obj_Entry * obj,struct Struct_RtldLockState * lockstate)273 reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
274 {
275 const Elf_Rela *relalim;
276 const Elf_Rela *rela;
277
278 if (!obj->irelative)
279 return (0);
280 obj->irelative = false;
281 relalim = (const Elf_Rela *)((const char *)obj->pltrela +
282 obj->pltrelasize);
283 for (rela = obj->pltrela; rela < relalim; rela++) {
284 if (ELF_R_TYPE(rela->r_info) == R_AARCH64_IRELATIVE)
285 reloc_iresolve_one(obj, rela, lockstate);
286 }
287 return (0);
288 }
289
290 int
reloc_iresolve_nonplt(Obj_Entry * obj,struct Struct_RtldLockState * lockstate)291 reloc_iresolve_nonplt(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
292 {
293 const Elf_Rela *relalim;
294 const Elf_Rela *rela;
295
296 if (!obj->irelative_nonplt)
297 return (0);
298 obj->irelative_nonplt = false;
299 relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize);
300 for (rela = obj->rela; rela < relalim; rela++) {
301 if (ELF_R_TYPE(rela->r_info) == R_AARCH64_IRELATIVE)
302 reloc_iresolve_one(obj, rela, lockstate);
303 }
304 return (0);
305 }
306
307 int
reloc_gnu_ifunc(Obj_Entry * obj,int flags,struct Struct_RtldLockState * lockstate)308 reloc_gnu_ifunc(Obj_Entry *obj, int flags,
309 struct Struct_RtldLockState *lockstate)
310 {
311 const Elf_Rela *relalim;
312 const Elf_Rela *rela;
313 Elf_Addr *where, target;
314 const Elf_Sym *def;
315 const Obj_Entry *defobj;
316
317 if (!obj->gnu_ifunc)
318 return (0);
319 relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize);
320 for (rela = obj->pltrela; rela < relalim; rela++) {
321 if (ELF_R_TYPE(rela->r_info) == R_AARCH64_JUMP_SLOT) {
322 where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
323 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
324 SYMLOOK_IN_PLT | flags, NULL, lockstate);
325 if (def == NULL)
326 return (-1);
327 if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC)
328 continue;
329 lock_release(rtld_bind_lock, lockstate);
330 target = (Elf_Addr)rtld_resolve_ifunc(defobj, def);
331 wlock_acquire(rtld_bind_lock, lockstate);
332 reloc_jmpslot(where, target, defobj, obj,
333 (const Elf_Rel *)rela);
334 }
335 }
336 obj->gnu_ifunc = false;
337 return (0);
338 }
339
340 Elf_Addr
reloc_jmpslot(Elf_Addr * where,Elf_Addr target,const Obj_Entry * defobj __unused,const Obj_Entry * obj __unused,const Elf_Rel * rel)341 reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
342 const Obj_Entry *defobj __unused, const Obj_Entry *obj __unused,
343 const Elf_Rel *rel)
344 {
345
346 assert(ELF_R_TYPE(rel->r_info) == R_AARCH64_JUMP_SLOT ||
347 ELF_R_TYPE(rel->r_info) == R_AARCH64_IRELATIVE);
348
349 if (*where != target && !ld_bind_not)
350 *where = target;
351 return (target);
352 }
353
354 void
ifunc_init(Elf_Auxinfo aux_info[__min_size (AT_COUNT)]__unused)355 ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused)
356 {
357
358 }
359
360 /*
361 * Process non-PLT relocations
362 */
363 int
reloc_non_plt(Obj_Entry * obj,Obj_Entry * obj_rtld,int flags,RtldLockState * lockstate)364 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
365 RtldLockState *lockstate)
366 {
367 const Obj_Entry *defobj;
368 const Elf_Rela *relalim;
369 const Elf_Rela *rela;
370 const Elf_Sym *def;
371 SymCache *cache;
372 Elf_Addr *where, symval;
373
374 /*
375 * The dynamic loader may be called from a thread, we have
376 * limited amounts of stack available so we cannot use alloca().
377 */
378 if (obj == obj_rtld)
379 cache = NULL;
380 else
381 cache = calloc(obj->dynsymcount, sizeof(SymCache));
382 /* No need to check for NULL here */
383
384 relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize);
385 for (rela = obj->rela; rela < relalim; rela++) {
386 /*
387 * First, resolve symbol for relocations which
388 * reference symbols.
389 */
390 switch (ELF_R_TYPE(rela->r_info)) {
391 case R_AARCH64_ABS64:
392 case R_AARCH64_GLOB_DAT:
393 case R_AARCH64_TLS_TPREL64:
394 case R_AARCH64_TLS_DTPREL64:
395 case R_AARCH64_TLS_DTPMOD64:
396 def = find_symdef(ELF_R_SYM(rela->r_info), obj,
397 &defobj, flags, cache, lockstate);
398 if (def == NULL)
399 return (-1);
400 /*
401 * If symbol is IFUNC, only perform relocation
402 * when caller allowed it by passing
403 * SYMLOOK_IFUNC flag. Skip the relocations
404 * otherwise.
405 *
406 * Also error out in case IFUNC relocations
407 * are specified for TLS, which cannot be
408 * usefully interpreted.
409 */
410 if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
411 switch (ELF_R_TYPE(rela->r_info)) {
412 case R_AARCH64_ABS64:
413 case R_AARCH64_GLOB_DAT:
414 if ((flags & SYMLOOK_IFUNC) == 0) {
415 obj->non_plt_gnu_ifunc = true;
416 continue;
417 }
418 symval = (Elf_Addr)rtld_resolve_ifunc(
419 defobj, def);
420 break;
421 default:
422 _rtld_error("%s: IFUNC for TLS reloc",
423 obj->path);
424 return (-1);
425 }
426 } else {
427 if ((flags & SYMLOOK_IFUNC) != 0)
428 continue;
429 symval = (Elf_Addr)defobj->relocbase +
430 def->st_value;
431 }
432 break;
433 default:
434 if ((flags & SYMLOOK_IFUNC) != 0)
435 continue;
436 }
437
438 where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
439
440 switch (ELF_R_TYPE(rela->r_info)) {
441 case R_AARCH64_ABS64:
442 case R_AARCH64_GLOB_DAT:
443 *where = symval + rela->r_addend;
444 break;
445 case R_AARCH64_COPY:
446 /*
447 * These are deferred until all other relocations have
448 * been done. All we do here is make sure that the
449 * COPY relocation is not in a shared library. They
450 * are allowed only in executable files.
451 */
452 if (!obj->mainprog) {
453 _rtld_error("%s: Unexpected R_AARCH64_COPY "
454 "relocation in shared library", obj->path);
455 return (-1);
456 }
457 break;
458 case R_AARCH64_TLSDESC:
459 reloc_tlsdesc(obj, rela, where, flags, lockstate);
460 break;
461 case R_AARCH64_TLS_TPREL64:
462 /*
463 * We lazily allocate offsets for static TLS as we
464 * see the first relocation that references the
465 * TLS block. This allows us to support (small
466 * amounts of) static TLS in dynamically loaded
467 * modules. If we run out of space, we generate an
468 * error.
469 */
470 if (!defobj->tls_static) {
471 if (!allocate_tls_offset(
472 __DECONST(Obj_Entry *, defobj))) {
473 _rtld_error(
474 "%s: No space available for static "
475 "Thread Local Storage", obj->path);
476 return (-1);
477 }
478 }
479 *where = def->st_value + rela->r_addend +
480 defobj->tlsoffset;
481 break;
482
483 /*
484 * !!! BEWARE !!!
485 * ARM ELF ABI defines TLS_DTPMOD64 as 1029, and TLS_DTPREL64
486 * as 1028. But actual bfd linker and the glibc RTLD linker
487 * treats TLS_DTPMOD64 as 1028 and TLS_DTPREL64 1029.
488 */
489 case R_AARCH64_TLS_DTPREL64: /* efectively is TLS_DTPMOD64 */
490 *where += (Elf_Addr)defobj->tlsindex;
491 break;
492 case R_AARCH64_TLS_DTPMOD64: /* efectively is TLS_DTPREL64 */
493 *where += (Elf_Addr)(def->st_value + rela->r_addend);
494 break;
495 case R_AARCH64_RELATIVE:
496 *where = (Elf_Addr)(obj->relocbase + rela->r_addend);
497 break;
498 case R_AARCH64_NONE:
499 break;
500 case R_AARCH64_IRELATIVE:
501 obj->irelative_nonplt = true;
502 break;
503 default:
504 rtld_printf("%s: Unhandled relocation %lu\n",
505 obj->path, ELF_R_TYPE(rela->r_info));
506 return (-1);
507 }
508 }
509
510 return (0);
511 }
512
513 void
allocate_initial_tls(Obj_Entry * objs)514 allocate_initial_tls(Obj_Entry *objs)
515 {
516
517 /*
518 * Fix the size of the static TLS block by using the maximum
519 * offset allocated so far and adding a bit for dynamic modules to
520 * use.
521 */
522 tls_static_space = tls_last_offset + tls_last_size +
523 ld_static_tls_extra;
524
525 _tcb_set(allocate_tls(objs, NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN));
526 }
527
528 void *
__tls_get_addr(tls_index * ti)529 __tls_get_addr(tls_index* ti)
530 {
531 uintptr_t **dtvp;
532
533 dtvp = &_tcb_get()->tcb_dtv;
534 return (tls_get_addr_common(dtvp, ti->ti_module, ti->ti_offset));
535 }
536