1 /* $NetBSD: mdreloc.c,v 1.23 2003/07/26 15:04:38 mrg Exp $ */
14 #include "machine/sysarch.h"
21 init_pltgot(Obj_Entry *obj)
23 if (obj->pltgot != NULL) {
24 obj->pltgot[1] = (Elf_Addr) obj;
25 obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
30 do_copy_relocations(Obj_Entry *dstobj)
32 const Elf_Rel *rellim;
35 assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */
37 rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize);
38 for (rel = dstobj->rel; rel < rellim; rel++) {
39 if (ELF_R_TYPE(rel->r_info) == R_ARM_COPY) {
41 const Elf_Sym *dstsym;
45 const Elf_Sym *srcsym;
46 const Obj_Entry *srcobj, *defobj;
50 dstaddr = (void *) (dstobj->relocbase + rel->r_offset);
51 dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
52 name = dstobj->strtab + dstsym->st_name;
53 size = dstsym->st_size;
55 symlook_init(&req, name);
56 req.ventry = fetch_ventry(dstobj,
57 ELF_R_SYM(rel->r_info));
58 req.flags = SYMLOOK_EARLY;
60 for (srcobj = dstobj->next; srcobj != NULL;
61 srcobj = srcobj->next) {
62 res = symlook_obj(&req, srcobj);
65 defobj = req.defobj_out;
71 "Undefined symbol \"%s\" referenced from COPY relocation in %s",
76 srcaddr = (const void *)(defobj->relocbase +
78 memcpy(dstaddr, srcaddr, size);
84 void _rtld_bind_start(void);
85 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
90 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
92 const Elf_Rel *rel = 0, *rellim;
97 for (; dynp->d_tag != DT_NULL; dynp++) {
98 switch (dynp->d_tag) {
100 rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
103 relsz = dynp->d_un.d_val;
107 rellim = (const Elf_Rel *)((caddr_t)rel + relsz);
108 size = (rellim - 1)->r_offset - rel->r_offset;
109 for (; rel < rellim; rel++) {
110 where = (Elf_Addr *)(relocbase + rel->r_offset);
112 *where += (Elf_Addr)relocbase;
116 * It is possible for the compiler to emit relocations for unaligned data.
117 * We handle this situation with these inlines.
119 #define RELOC_ALIGNED_P(x) \
120 (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
122 static __inline Elf_Addr
123 load_ptr(void *where)
127 memcpy(&res, where, sizeof(res));
133 store_ptr(void *where, Elf_Addr val)
136 memcpy(where, &val, sizeof(val));
140 reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache,
141 int flags, RtldLockState *lockstate)
145 const Obj_Entry *defobj;
147 unsigned long symnum;
149 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
150 symnum = ELF_R_SYM(rel->r_info);
152 switch (ELF_R_TYPE(rel->r_info)) {
156 #if 1 /* XXX should not occur */
157 case R_ARM_PC24: { /* word32 S - P + A */
161 * Extract addend and sign-extend if needed.
164 if (addend & 0x00800000)
165 addend |= 0xff000000;
167 def = find_symdef(symnum, obj, &defobj, flags, cache,
171 tmp = (Elf_Addr)obj->relocbase + def->st_value
172 - (Elf_Addr)where + (addend << 2);
173 if ((tmp & 0xfe000000) != 0xfe000000 &&
174 (tmp & 0xfe000000) != 0) {
176 "%s: R_ARM_PC24 relocation @ %p to %s failed "
177 "(displacement %ld (%#lx) out of range)",
179 obj->strtab + obj->symtab[symnum].st_name,
180 (long) tmp, (long) tmp);
184 *where = (*where & 0xff000000) | (tmp & 0x00ffffff);
185 dbg("PC24 %s in %s --> %p @ %p in %s",
186 obj->strtab + obj->symtab[symnum].st_name,
187 obj->path, (void *)*where, where, defobj->path);
192 case R_ARM_ABS32: /* word32 B + S + A */
193 case R_ARM_GLOB_DAT: /* word32 B + S */
194 def = find_symdef(symnum, obj, &defobj, flags, cache,
198 if (__predict_true(RELOC_ALIGNED_P(where))) {
199 tmp = *where + (Elf_Addr)defobj->relocbase +
203 tmp = load_ptr(where) +
204 (Elf_Addr)defobj->relocbase +
206 store_ptr(where, tmp);
208 dbg("ABS32/GLOB_DAT %s in %s --> %p @ %p in %s",
209 obj->strtab + obj->symtab[symnum].st_name,
210 obj->path, (void *)tmp, where, defobj->path);
213 case R_ARM_RELATIVE: /* word32 B + A */
214 if (__predict_true(RELOC_ALIGNED_P(where))) {
215 tmp = *where + (Elf_Addr)obj->relocbase;
218 tmp = load_ptr(where) +
219 (Elf_Addr)obj->relocbase;
220 store_ptr(where, tmp);
222 dbg("RELATIVE in %s --> %p", obj->path,
228 * These are deferred until all other relocations have
229 * been done. All we do here is make sure that the
230 * COPY relocation is not in a shared library. They
231 * are allowed only in executable files.
233 if (!obj->mainprog) {
235 "%s: Unexpected R_COPY relocation in shared library",
239 dbg("COPY (avoid in main)");
242 case R_ARM_TLS_DTPOFF32:
243 def = find_symdef(symnum, obj, &defobj, flags, cache,
248 tmp = (Elf_Addr)(def->st_value);
249 if (__predict_true(RELOC_ALIGNED_P(where)))
252 store_ptr(where, tmp);
254 dbg("TLS_DTPOFF32 %s in %s --> %p",
255 obj->strtab + obj->symtab[symnum].st_name,
256 obj->path, (void *)tmp);
259 case R_ARM_TLS_DTPMOD32:
260 def = find_symdef(symnum, obj, &defobj, flags, cache,
265 tmp = (Elf_Addr)(defobj->tlsindex);
266 if (__predict_true(RELOC_ALIGNED_P(where)))
269 store_ptr(where, tmp);
271 dbg("TLS_DTPMOD32 %s in %s --> %p",
272 obj->strtab + obj->symtab[symnum].st_name,
273 obj->path, (void *)tmp);
277 case R_ARM_TLS_TPOFF32:
278 def = find_symdef(symnum, obj, &defobj, flags, cache,
283 if (!defobj->tls_done && allocate_tls_offset(obj))
287 tmp = (Elf_Addr)def->st_value + defobj->tlsoffset +
289 if (__predict_true(RELOC_ALIGNED_P(where)))
292 store_ptr(where, tmp);
293 dbg("TLS_TPOFF32 %s in %s --> %p",
294 obj->strtab + obj->symtab[symnum].st_name,
295 obj->path, (void *)tmp);
300 dbg("sym = %lu, type = %lu, offset = %p, "
301 "contents = %p, symbol = %s",
302 symnum, (u_long)ELF_R_TYPE(rel->r_info),
303 (void *)rel->r_offset, (void *)load_ptr(where),
304 obj->strtab + obj->symtab[symnum].st_name);
305 _rtld_error("%s: Unsupported relocation type %ld "
306 "in non-PLT relocations\n",
307 obj->path, (u_long) ELF_R_TYPE(rel->r_info));
314 * * Process non-PLT relocations
317 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
318 RtldLockState *lockstate)
320 const Elf_Rel *rellim;
325 /* The relocation for the dynamic loader has already been done. */
328 if ((flags & SYMLOOK_IFUNC) != 0)
329 /* XXX not implemented */
333 * The dynamic loader may be called from a thread, we have
334 * limited amounts of stack available so we cannot use alloca().
336 cache = calloc(obj->dynsymcount, sizeof(SymCache));
337 /* No need to check for NULL here */
339 rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
340 for (rel = obj->rel; rel < rellim; rel++) {
341 if (reloc_nonplt_object(obj, rel, cache, flags, lockstate) < 0)
352 * * Process the PLT relocations.
355 reloc_plt(Obj_Entry *obj)
357 const Elf_Rel *rellim;
360 rellim = (const Elf_Rel *)((char *)obj->pltrel +
362 for (rel = obj->pltrel; rel < rellim; rel++) {
365 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
367 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
368 *where += (Elf_Addr )obj->relocbase;
375 * * LD_BIND_NOW was set - force relocation for all jump slots
378 reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
380 const Obj_Entry *defobj;
381 const Elf_Rel *rellim;
387 rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
388 for (rel = obj->pltrel; rel < rellim; rel++) {
389 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
390 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
391 def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
392 SYMLOOK_IN_PLT | flags, NULL, lockstate);
394 dbg("reloc_jmpslots: sym not found");
398 target = (Elf_Addr)(defobj->relocbase + def->st_value);
399 reloc_jmpslot(where, target, defobj, obj,
400 (const Elf_Rel *) rel);
403 obj->jmpslots_done = true;
409 reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
412 /* XXX not implemented */
417 reloc_gnu_ifunc(Obj_Entry *obj, int flags,
418 struct Struct_RtldLockState *lockstate)
421 /* XXX not implemented */
426 reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj,
427 const Obj_Entry *obj, const Elf_Rel *rel)
430 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
432 if (*where != target)
439 allocate_initial_tls(Obj_Entry *objs)
441 #ifdef ARM_TP_ADDRESS
442 void **_tp = (void **)ARM_TP_ADDRESS;
446 * Fix the size of the static TLS block by using the maximum
447 * offset allocated so far and adding a bit for dynamic modules to
451 tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA;
453 #ifdef ARM_TP_ADDRESS
454 (*_tp) = (void *) allocate_tls(objs, NULL, TLS_TCB_SIZE, 8);
456 sysarch(ARM_SET_TP, allocate_tls(objs, NULL, TLS_TCB_SIZE, 8));
461 __tls_get_addr(tls_index* ti)
464 #ifdef ARM_TP_ADDRESS
465 void **_tp = (void **)ARM_TP_ADDRESS;
467 p = tls_get_addr_common((Elf_Addr **)(*_tp), ti->ti_module, ti->ti_offset);
470 __asm __volatile("mrc p15, 0, %0, c13, c0, 3" \
472 p = tls_get_addr_common((Elf_Addr **)(_tp), ti->ti_module, ti->ti_offset);