1 /* $NetBSD: mdreloc.c,v 1.23 2003/07/26 15:04:38 mrg Exp $ */
17 init_pltgot(Obj_Entry *obj)
19 if (obj->pltgot != NULL) {
20 obj->pltgot[1] = (Elf_Addr) obj;
21 obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
26 do_copy_relocations(Obj_Entry *dstobj)
28 const Elf_Rel *rellim;
31 assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */
33 rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize);
34 for (rel = dstobj->rel; rel < rellim; rel++) {
35 if (ELF_R_TYPE(rel->r_info) == R_ARM_COPY) {
37 const Elf_Sym *dstsym;
42 const Elf_Sym *srcsym;
46 dstaddr = (void *) (dstobj->relocbase + rel->r_offset);
47 dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
48 name = dstobj->strtab + dstsym->st_name;
49 hash = elf_hash(name);
50 size = dstsym->st_size;
51 ve = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info));
53 for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next)
54 if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0)) != NULL)
58 _rtld_error("Undefined symbol \"%s\" referenced from COPY"
59 " relocation in %s", name, dstobj->path);
63 srcaddr = (const void *) (srcobj->relocbase + srcsym->st_value);
64 memcpy(dstaddr, srcaddr, size);
70 void _rtld_bind_start(void);
71 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
76 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
78 const Elf_Rel *rel = 0, *rellim;
83 for (; dynp->d_tag != DT_NULL; dynp++) {
84 switch (dynp->d_tag) {
86 rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
89 relsz = dynp->d_un.d_val;
93 rellim = (const Elf_Rel *)((caddr_t)rel + relsz);
94 size = (rellim - 1)->r_offset - rel->r_offset;
95 for (; rel < rellim; rel++) {
96 where = (Elf_Addr *)(relocbase + rel->r_offset);
98 *where += (Elf_Addr)relocbase;
102 * It is possible for the compiler to emit relocations for unaligned data.
103 * We handle this situation with these inlines.
105 #define RELOC_ALIGNED_P(x) \
106 (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
108 static __inline Elf_Addr
109 load_ptr(void *where)
113 memcpy(&res, where, sizeof(res));
119 store_ptr(void *where, Elf_Addr val)
122 memcpy(where, &val, sizeof(val));
126 reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache)
130 const Obj_Entry *defobj;
132 unsigned long symnum;
134 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
135 symnum = ELF_R_SYM(rel->r_info);
137 switch (ELF_R_TYPE(rel->r_info)) {
141 #if 1 /* XXX should not occur */
142 case R_ARM_PC24: { /* word32 S - P + A */
146 * Extract addend and sign-extend if needed.
149 if (addend & 0x00800000)
150 addend |= 0xff000000;
152 def = find_symdef(symnum, obj, &defobj, false, cache);
155 tmp = (Elf_Addr)obj->relocbase + def->st_value
156 - (Elf_Addr)where + (addend << 2);
157 if ((tmp & 0xfe000000) != 0xfe000000 &&
158 (tmp & 0xfe000000) != 0) {
160 "%s: R_ARM_PC24 relocation @ %p to %s failed "
161 "(displacement %ld (%#lx) out of range)",
163 obj->strtab + obj->symtab[symnum].st_name,
164 (long) tmp, (long) tmp);
168 *where = (*where & 0xff000000) | (tmp & 0x00ffffff);
169 dbg("PC24 %s in %s --> %p @ %p in %s",
170 obj->strtab + obj->symtab[symnum].st_name,
171 obj->path, (void *)*where, where, defobj->path);
176 case R_ARM_ABS32: /* word32 B + S + A */
177 case R_ARM_GLOB_DAT: /* word32 B + S */
178 def = find_symdef(symnum, obj, &defobj, false, cache);
181 if (__predict_true(RELOC_ALIGNED_P(where))) {
182 tmp = *where + (Elf_Addr)defobj->relocbase +
186 tmp = load_ptr(where) +
187 (Elf_Addr)defobj->relocbase +
189 store_ptr(where, tmp);
191 dbg("ABS32/GLOB_DAT %s in %s --> %p @ %p in %s",
192 obj->strtab + obj->symtab[symnum].st_name,
193 obj->path, (void *)tmp, where, defobj->path);
196 case R_ARM_RELATIVE: /* word32 B + A */
197 if (__predict_true(RELOC_ALIGNED_P(where))) {
198 tmp = *where + (Elf_Addr)obj->relocbase;
201 tmp = load_ptr(where) +
202 (Elf_Addr)obj->relocbase;
203 store_ptr(where, tmp);
205 dbg("RELATIVE in %s --> %p", obj->path,
211 * These are deferred until all other relocations have
212 * been done. All we do here is make sure that the
213 * COPY relocation is not in a shared library. They
214 * are allowed only in executable files.
216 if (!obj->mainprog) {
218 "%s: Unexpected R_COPY relocation in shared library",
222 dbg("COPY (avoid in main)");
226 dbg("sym = %lu, type = %lu, offset = %p, "
227 "contents = %p, symbol = %s",
228 symnum, (u_long)ELF_R_TYPE(rel->r_info),
229 (void *)rel->r_offset, (void *)load_ptr(where),
230 obj->strtab + obj->symtab[symnum].st_name);
231 _rtld_error("%s: Unsupported relocation type %ld "
232 "in non-PLT relocations\n",
233 obj->path, (u_long) ELF_R_TYPE(rel->r_info));
240 * * Process non-PLT relocations
243 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
245 const Elf_Rel *rellim;
248 int bytes = obj->nchains * sizeof(SymCache);
251 /* The relocation for the dynamic loader has already been done. */
255 * The dynamic loader may be called from a thread, we have
256 * limited amounts of stack available so we cannot use alloca().
258 cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
259 if (cache == MAP_FAILED)
262 rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
263 for (rel = obj->rel; rel < rellim; rel++) {
264 if (reloc_nonplt_object(obj, rel, cache) < 0)
270 munmap(cache, bytes);
276 * * Process the PLT relocations.
279 reloc_plt(Obj_Entry *obj)
281 const Elf_Rel *rellim;
284 rellim = (const Elf_Rel *)((char *)obj->pltrel +
286 for (rel = obj->pltrel; rel < rellim; rel++) {
289 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
291 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
292 *where += (Elf_Addr )obj->relocbase;
299 * * LD_BIND_NOW was set - force relocation for all jump slots
302 reloc_jmpslots(Obj_Entry *obj)
304 const Obj_Entry *defobj;
305 const Elf_Rel *rellim;
311 rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
312 for (rel = obj->pltrel; rel < rellim; rel++) {
313 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
314 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
315 def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
318 dbg("reloc_jmpslots: sym not found");
322 target = (Elf_Addr)(defobj->relocbase + def->st_value);
323 reloc_jmpslot(where, target, defobj, obj,
324 (const Elf_Rel *) rel);
327 obj->jmpslots_done = true;
333 reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj,
334 const Obj_Entry *obj, const Elf_Rel *rel)
337 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
339 if (*where != target)
346 allocate_initial_tls(Obj_Entry *objs)
352 __tls_get_addr(tls_index* ti)