1 /* $NetBSD: mdreloc.c,v 1.23 2003/07/26 15:04:38 mrg Exp $ */
14 #include "machine/sysarch.h"
20 init_pltgot(Obj_Entry *obj)
22 if (obj->pltgot != NULL) {
23 obj->pltgot[1] = (Elf_Addr) obj;
24 obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
29 do_copy_relocations(Obj_Entry *dstobj)
31 const Elf_Rel *rellim;
34 assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */
36 rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize);
37 for (rel = dstobj->rel; rel < rellim; rel++) {
38 if (ELF_R_TYPE(rel->r_info) == R_ARM_COPY) {
40 const Elf_Sym *dstsym;
44 const Elf_Sym *srcsym;
45 const Obj_Entry *srcobj, *defobj;
49 dstaddr = (void *) (dstobj->relocbase + rel->r_offset);
50 dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
51 name = dstobj->strtab + dstsym->st_name;
52 size = dstsym->st_size;
54 symlook_init(&req, name);
55 req.ventry = fetch_ventry(dstobj,
56 ELF_R_SYM(rel->r_info));
57 req.flags = SYMLOOK_EARLY;
59 for (srcobj = dstobj->next; srcobj != NULL;
60 srcobj = srcobj->next) {
61 res = symlook_obj(&req, srcobj);
64 defobj = req.defobj_out;
70 "Undefined symbol \"%s\" referenced from COPY relocation in %s",
75 srcaddr = (const void *)(defobj->relocbase +
77 memcpy(dstaddr, srcaddr, size);
83 void _rtld_bind_start(void);
84 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
89 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
91 const Elf_Rel *rel = 0, *rellim;
96 for (; dynp->d_tag != DT_NULL; dynp++) {
97 switch (dynp->d_tag) {
99 rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
102 relsz = dynp->d_un.d_val;
106 rellim = (const Elf_Rel *)((caddr_t)rel + relsz);
107 size = (rellim - 1)->r_offset - rel->r_offset;
108 for (; rel < rellim; rel++) {
109 where = (Elf_Addr *)(relocbase + rel->r_offset);
111 *where += (Elf_Addr)relocbase;
115 * It is possible for the compiler to emit relocations for unaligned data.
116 * We handle this situation with these inlines.
118 #define RELOC_ALIGNED_P(x) \
119 (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
121 static __inline Elf_Addr
122 load_ptr(void *where)
126 memcpy(&res, where, sizeof(res));
132 store_ptr(void *where, Elf_Addr val)
135 memcpy(where, &val, sizeof(val));
139 reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache,
140 int flags, RtldLockState *lockstate)
144 const Obj_Entry *defobj;
146 unsigned long symnum;
148 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
149 symnum = ELF_R_SYM(rel->r_info);
151 switch (ELF_R_TYPE(rel->r_info)) {
155 #if 1 /* XXX should not occur */
156 case R_ARM_PC24: { /* word32 S - P + A */
160 * Extract addend and sign-extend if needed.
163 if (addend & 0x00800000)
164 addend |= 0xff000000;
166 def = find_symdef(symnum, obj, &defobj, flags, cache,
170 tmp = (Elf_Addr)obj->relocbase + def->st_value
171 - (Elf_Addr)where + (addend << 2);
172 if ((tmp & 0xfe000000) != 0xfe000000 &&
173 (tmp & 0xfe000000) != 0) {
175 "%s: R_ARM_PC24 relocation @ %p to %s failed "
176 "(displacement %ld (%#lx) out of range)",
178 obj->strtab + obj->symtab[symnum].st_name,
179 (long) tmp, (long) tmp);
183 *where = (*where & 0xff000000) | (tmp & 0x00ffffff);
184 dbg("PC24 %s in %s --> %p @ %p in %s",
185 obj->strtab + obj->symtab[symnum].st_name,
186 obj->path, (void *)*where, where, defobj->path);
191 case R_ARM_ABS32: /* word32 B + S + A */
192 case R_ARM_GLOB_DAT: /* word32 B + S */
193 def = find_symdef(symnum, obj, &defobj, flags, cache,
197 if (__predict_true(RELOC_ALIGNED_P(where))) {
198 tmp = *where + (Elf_Addr)defobj->relocbase +
202 tmp = load_ptr(where) +
203 (Elf_Addr)defobj->relocbase +
205 store_ptr(where, tmp);
207 dbg("ABS32/GLOB_DAT %s in %s --> %p @ %p in %s",
208 obj->strtab + obj->symtab[symnum].st_name,
209 obj->path, (void *)tmp, where, defobj->path);
212 case R_ARM_RELATIVE: /* word32 B + A */
213 if (__predict_true(RELOC_ALIGNED_P(where))) {
214 tmp = *where + (Elf_Addr)obj->relocbase;
217 tmp = load_ptr(where) +
218 (Elf_Addr)obj->relocbase;
219 store_ptr(where, tmp);
221 dbg("RELATIVE in %s --> %p", obj->path,
227 * These are deferred until all other relocations have
228 * been done. All we do here is make sure that the
229 * COPY relocation is not in a shared library. They
230 * are allowed only in executable files.
232 if (!obj->mainprog) {
234 "%s: Unexpected R_COPY relocation in shared library",
238 dbg("COPY (avoid in main)");
241 case R_ARM_TLS_DTPOFF32:
242 def = find_symdef(symnum, obj, &defobj, flags, cache,
247 tmp = (Elf_Addr)(def->st_value);
248 if (__predict_true(RELOC_ALIGNED_P(where)))
251 store_ptr(where, tmp);
253 dbg("TLS_DTPOFF32 %s in %s --> %p",
254 obj->strtab + obj->symtab[symnum].st_name,
255 obj->path, (void *)tmp);
258 case R_ARM_TLS_DTPMOD32:
259 def = find_symdef(symnum, obj, &defobj, flags, cache,
264 tmp = (Elf_Addr)(defobj->tlsindex);
265 if (__predict_true(RELOC_ALIGNED_P(where)))
268 store_ptr(where, tmp);
270 dbg("TLS_DTPMOD32 %s in %s --> %p",
271 obj->strtab + obj->symtab[symnum].st_name,
272 obj->path, (void *)tmp);
276 case R_ARM_TLS_TPOFF32:
277 def = find_symdef(symnum, obj, &defobj, flags, cache,
282 if (!defobj->tls_done && allocate_tls_offset(obj))
286 tmp = (Elf_Addr)def->st_value + defobj->tlsoffset +
288 if (__predict_true(RELOC_ALIGNED_P(where)))
291 store_ptr(where, tmp);
292 dbg("TLS_TPOFF32 %s in %s --> %p",
293 obj->strtab + obj->symtab[symnum].st_name,
294 obj->path, (void *)tmp);
299 dbg("sym = %lu, type = %lu, offset = %p, "
300 "contents = %p, symbol = %s",
301 symnum, (u_long)ELF_R_TYPE(rel->r_info),
302 (void *)rel->r_offset, (void *)load_ptr(where),
303 obj->strtab + obj->symtab[symnum].st_name);
304 _rtld_error("%s: Unsupported relocation type %ld "
305 "in non-PLT relocations\n",
306 obj->path, (u_long) ELF_R_TYPE(rel->r_info));
313 * * Process non-PLT relocations
316 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
317 RtldLockState *lockstate)
319 const Elf_Rel *rellim;
324 /* The relocation for the dynamic loader has already been done. */
328 * The dynamic loader may be called from a thread, we have
329 * limited amounts of stack available so we cannot use alloca().
331 cache = calloc(obj->dynsymcount, sizeof(SymCache));
332 /* No need to check for NULL here */
334 rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
335 for (rel = obj->rel; rel < rellim; rel++) {
336 if (reloc_nonplt_object(obj, rel, cache, flags, lockstate) < 0)
347 * * Process the PLT relocations.
350 reloc_plt(Obj_Entry *obj)
352 const Elf_Rel *rellim;
355 rellim = (const Elf_Rel *)((char *)obj->pltrel +
357 for (rel = obj->pltrel; rel < rellim; rel++) {
360 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
362 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
363 *where += (Elf_Addr )obj->relocbase;
370 * * LD_BIND_NOW was set - force relocation for all jump slots
373 reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
375 const Obj_Entry *defobj;
376 const Elf_Rel *rellim;
382 rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
383 for (rel = obj->pltrel; rel < rellim; rel++) {
384 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
385 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
386 def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
387 SYMLOOK_IN_PLT | flags, NULL, lockstate);
389 dbg("reloc_jmpslots: sym not found");
393 target = (Elf_Addr)(defobj->relocbase + def->st_value);
394 reloc_jmpslot(where, target, defobj, obj,
395 (const Elf_Rel *) rel);
398 obj->jmpslots_done = true;
404 reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
407 /* XXX not implemented */
412 reloc_gnu_ifunc(Obj_Entry *obj, int flags,
413 struct Struct_RtldLockState *lockstate)
416 /* XXX not implemented */
421 reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj,
422 const Obj_Entry *obj, const Elf_Rel *rel)
425 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
427 if (*where != target)
434 allocate_initial_tls(Obj_Entry *objs)
436 void **_tp = (void **)ARM_TP_ADDRESS;
439 * Fix the size of the static TLS block by using the maximum
440 * offset allocated so far and adding a bit for dynamic modules to
444 tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA;
446 (*_tp) = (void *) allocate_tls(objs, NULL, TLS_TCB_SIZE, 8);
450 __tls_get_addr(tls_index* ti)
452 void **_tp = (void **)ARM_TP_ADDRESS;
455 p = tls_get_addr_common((Elf_Addr **)(*_tp), ti->ti_module, ti->ti_offset);