1 /* $NetBSD: mdreloc.c,v 1.23 2003/07/26 15:04:38 mrg Exp $ */
2 /* $NetBSD: mips_reloc.c,v 1.53 2008/07/24 04:39:25 matt Exp $ */
5 * Copyright 1997 Michael L. Hitch <mhitch@montana.edu>
6 * Portions copyright 2002 Charles M. Hannum <root@ihack.net>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
46 init_pltgot(Obj_Entry *obj)
48 if (obj->pltgot != NULL) {
49 obj->pltgot[0] = (Elf_Addr) &_rtld_bind_start;
50 obj->pltgot[1] |= (Elf_Addr) obj;
55 do_copy_relocations(Obj_Entry *dstobj)
61 void _rtld_bind_start(void);
62 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
68 * It is possible for the compiler to emit relocations for unaligned data.
69 * We handle this situation with these inlines.
71 #define RELOC_ALIGNED_P(x) \
72 (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
74 static __inline Elf_Addr
77 if (__predict_true(RELOC_ALIGNED_P(where)))
78 return *(Elf_Addr *)where;
82 (void)memcpy(&res, where, sizeof(res));
88 store_ptr(void *where, Elf_Addr val)
90 if (__predict_true(RELOC_ALIGNED_P(where)))
91 *(Elf_Addr *)where = val;
93 (void)memcpy(where, &val, sizeof(val));
97 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
99 const Elf_Rel *rel = 0, *rellim;
101 const Elf_Sym *symtab = NULL, *sym;
103 Elf_Addr *got = NULL;
104 Elf_Word local_gotno = 0, symtabno = 0, gotsym = 0;
107 for (; dynp->d_tag != DT_NULL; dynp++) {
108 switch (dynp->d_tag) {
110 rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
113 relsz = dynp->d_un.d_val;
116 symtab = (const Elf_Sym *)(relocbase + dynp->d_un.d_ptr);
119 got = (Elf_Addr *)(relocbase + dynp->d_un.d_ptr);
121 case DT_MIPS_LOCAL_GOTNO:
122 local_gotno = dynp->d_un.d_val;
124 case DT_MIPS_SYMTABNO:
125 symtabno = dynp->d_un.d_val;
128 gotsym = dynp->d_un.d_val;
133 i = (got[1] & 0x80000000) ? 2 : 1;
134 /* Relocate the local GOT entries */
136 for (; i < local_gotno; i++) {
140 sym = symtab + gotsym;
141 /* Now do the global GOT entries */
142 for (i = gotsym; i < symtabno; i++) {
143 *got = sym->st_value + relocbase;
148 rellim = (const Elf_Rel *)((caddr_t)rel + relsz);
149 for (; rel < rellim; rel++) {
150 where = (void *)(relocbase + rel->r_offset);
152 switch (ELF_R_TYPE(rel->r_info)) {
157 assert(ELF_R_SYM(rel->r_info) < gotsym);
158 sym = symtab + ELF_R_SYM(rel->r_info);
159 assert(ELF_ST_BIND(sym->st_info) == STB_LOCAL);
160 store_ptr(where, load_ptr(where) + relocbase);
171 _mips_rtld_bind(Obj_Entry *obj, Elf_Size reloff)
173 Elf_Addr *got = obj->pltgot;
175 const Obj_Entry *defobj;
178 def = find_symdef(reloff, obj, &defobj, SYMLOOK_IN_PLT, NULL);
180 _rtld_error("bind failed no symbol");
182 target = (Elf_Addr)(defobj->relocbase + def->st_value);
183 dbg("bind now/fixup at %s sym # %d in %s --> was=%p new=%p",
185 reloff, defobj->strtab + def->st_name,
186 (void *)got[obj->local_gotno + reloff - obj->gotsym],
188 got[obj->local_gotno + reloff - obj->gotsym] = target;
189 return (Elf_Addr)target;
193 * Process non-PLT relocations
196 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
199 const Elf_Rel *rellim;
200 Elf_Addr *got = obj->pltgot;
201 const Elf_Sym *sym, *def;
202 const Obj_Entry *defobj;
205 /* The relocation for the dynamic loader has already been done. */
209 i = (got[1] & 0x80000000) ? 2 : 1;
211 /* Relocate the local GOT entries */
213 dbg("got:%p for %d entries adding %x",
214 got, obj->local_gotno, (uint32_t)obj->relocbase);
215 for (; i < obj->local_gotno; i++) {
216 *got += (Elf_Addr)obj->relocbase;
219 sym = obj->symtab + obj->gotsym;
222 dbg("got:%p for %d entries",
224 /* Now do the global GOT entries */
225 for (i = obj->gotsym; i < obj->symtabno; i++) {
226 if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
227 sym->st_value != 0 && sym->st_shndx == SHN_UNDEF) {
229 * If there are non-PLT references to the function,
230 * st_value should be 0, forcing us to resolve the
231 * address immediately.
233 * XXX DANGER WILL ROBINSON!
234 * The linker is not outputting PLT slots for calls to
235 * functions that are defined in the same shared
236 * library. This is a bug, because it can screw up
237 * link ordering rules if the symbol is defined in
238 * more than one module. For now, if there is a
239 * definition, we fail the test above and force a full
240 * symbol lookup. This means that all intra-module
241 * calls are bound immediately. - mycroft, 2003/09/24
243 *got = sym->st_value + (Elf_Addr)obj->relocbase;
244 if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) {
245 dbg("Warning2, i:%d maps to relocbase address:%x",
246 i, (uint32_t)obj->relocbase);
249 } else if (sym->st_info == ELF_ST_INFO(STB_GLOBAL, STT_SECTION)) {
250 /* Symbols with index SHN_ABS are not relocated. */
251 if (sym->st_shndx != SHN_ABS) {
252 *got = sym->st_value +
253 (Elf_Addr)obj->relocbase;
254 if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) {
255 dbg("Warning3, i:%d maps to relocbase address:%x",
256 i, (uint32_t)obj->relocbase);
260 /* TODO: add cache here */
261 def = find_symdef(i, obj, &defobj, false, NULL);
263 dbg("Warning4, cant find symbole %d", i);
266 *got = def->st_value + (Elf_Addr)defobj->relocbase;
267 if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) {
268 dbg("Warning4, i:%d maps to relocbase address:%x",
269 i, (uint32_t)obj->relocbase);
270 dbg("via first obj symbol %s",
271 obj->strtab + obj->symtab[i].st_name);
272 dbg("found in obj %p:%s",
273 defobj, defobj->path);
280 rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
281 for (rel = obj->rel; rel < rellim; rel++) {
284 unsigned long symnum;
286 where = obj->relocbase + rel->r_offset;
287 symnum = ELF_R_SYM(rel->r_info);
288 switch (ELF_R_TYPE(rel->r_info)) {
293 /* 32-bit PC-relative reference */
294 def = obj->symtab + symnum;
295 if (symnum >= obj->gotsym) {
296 tmp = load_ptr(where);
297 tmp += got[obj->local_gotno + symnum - obj->gotsym];
298 store_ptr(where, tmp);
301 tmp = load_ptr(where);
304 ELF_ST_INFO(STB_LOCAL, STT_SECTION)
306 tmp += (Elf_Addr)def->st_value;
308 tmp += (Elf_Addr)obj->relocbase;
309 store_ptr(where, tmp);
313 dbg("sym = %lu, type = %lu, offset = %p, "
314 "contents = %p, symbol = %s",
315 symnum, (u_long)ELF_R_TYPE(rel->r_info),
316 (void *)rel->r_offset, (void *)load_ptr(where),
317 obj->strtab + obj->symtab[symnum].st_name);
318 _rtld_error("%s: Unsupported relocation type %ld "
319 "in non-PLT relocations\n",
320 obj->path, (u_long) ELF_R_TYPE(rel->r_info));
329 * Process the PLT relocations.
332 reloc_plt(Obj_Entry *obj)
334 const Elf_Rel *rellim;
337 dbg("reloc_plt obj:%p pltrel:%p sz:%d", obj, obj->pltrel, (int)obj->pltrelsize);
338 dbg("gottable %p num syms:%d", obj->pltgot, obj->symtabno );
339 dbg("*****************************************************");
340 rellim = (const Elf_Rel *)((char *)obj->pltrel +
342 for (rel = obj->pltrel; rel < rellim; rel++) {
344 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
345 *where += (Elf_Addr )obj->relocbase;
352 * LD_BIND_NOW was set - force relocation for all jump slots
355 reloc_jmpslots(Obj_Entry *obj)
358 obj->jmpslots_done = true;
364 reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj,
365 const Obj_Entry *obj, const Elf_Rel *rel)
374 allocate_initial_tls(Obj_Entry *objs)
380 __tls_get_addr(tls_index* ti)