]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - libexec/rtld-elf/mips/reloc.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / libexec / rtld-elf / mips / reloc.c
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 $     */
3
4 /*
5  * Copyright 1997 Michael L. Hitch <mhitch@montana.edu>
6  * Portions copyright 2002 Charles M. Hannum <root@ihack.net>
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
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.
19  *
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.
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
35 #include <sys/mman.h>
36
37 #include <errno.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include "debug.h"
43 #include "rtld.h"
44
45 void
46 init_pltgot(Obj_Entry *obj)
47 {       
48         if (obj->pltgot != NULL) {
49                 obj->pltgot[0] = (Elf_Addr) &_rtld_bind_start;
50                 obj->pltgot[1] |= (Elf_Addr) obj;
51         }
52 }
53
54 int             
55 do_copy_relocations(Obj_Entry *dstobj)
56 {
57         /* Do nothing */
58         return 0;                            
59 }
60
61 void _rtld_bind_start(void);
62 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
63
64 int open();
65 int _open();
66
67 /*
68  * It is possible for the compiler to emit relocations for unaligned data.
69  * We handle this situation with these inlines.
70  */
71 #define RELOC_ALIGNED_P(x) \
72         (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
73
74 static __inline Elf_Addr
75 load_ptr(void *where)
76 {
77         if (__predict_true(RELOC_ALIGNED_P(where)))
78                 return *(Elf_Addr *)where;
79         else {
80                 Elf_Addr res;
81
82                 (void)memcpy(&res, where, sizeof(res));
83                 return res;
84         }
85 }
86
87 static __inline void
88 store_ptr(void *where, Elf_Addr val)
89 {
90         if (__predict_true(RELOC_ALIGNED_P(where)))
91                 *(Elf_Addr *)where = val;
92         else
93                 (void)memcpy(where, &val, sizeof(val));
94 }
95
96 void
97 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
98 {
99         const Elf_Rel *rel = 0, *rellim;
100         Elf_Addr relsz = 0;
101         const Elf_Sym *symtab = NULL, *sym;
102         Elf_Addr *where;
103         Elf_Addr *got = NULL;
104         Elf_Word local_gotno = 0, symtabno = 0, gotsym = 0;
105         int i;
106
107         for (; dynp->d_tag != DT_NULL; dynp++) {
108                 switch (dynp->d_tag) {
109                 case DT_REL:
110                         rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
111                         break;
112                 case DT_RELSZ:
113                         relsz = dynp->d_un.d_val;
114                         break;
115                 case DT_SYMTAB:
116                         symtab = (const Elf_Sym *)(relocbase + dynp->d_un.d_ptr);
117                         break;
118                 case DT_PLTGOT:
119                         got = (Elf_Addr *)(relocbase + dynp->d_un.d_ptr);
120                         break;
121                 case DT_MIPS_LOCAL_GOTNO:
122                         local_gotno = dynp->d_un.d_val;
123                         break;
124                 case DT_MIPS_SYMTABNO:
125                         symtabno = dynp->d_un.d_val;
126                         break;
127                 case DT_MIPS_GOTSYM:
128                         gotsym = dynp->d_un.d_val;
129                         break;
130                 }
131         }
132
133         i = (got[1] & 0x80000000) ? 2 : 1;
134         /* Relocate the local GOT entries */
135         got += i;
136         for (; i < local_gotno; i++) {
137                *got++ += relocbase;
138         }
139
140         sym = symtab + gotsym;
141         /* Now do the global GOT entries */
142         for (i = gotsym; i < symtabno; i++) {
143                 *got = sym->st_value + relocbase;
144                 ++sym;
145                 ++got;
146         }
147
148         rellim = (const Elf_Rel *)((caddr_t)rel + relsz);
149         for (; rel < rellim; rel++) {
150                 where = (void *)(relocbase + rel->r_offset);
151
152                 switch (ELF_R_TYPE(rel->r_info)) {
153                 case R_TYPE(NONE):
154                         break;
155
156                 case R_TYPE(REL32):
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);
161                         break;
162
163                 default:
164                         abort();
165                         break;
166                 }
167         }
168 }
169
170 Elf_Addr
171 _mips_rtld_bind(Obj_Entry *obj, Elf_Size reloff)
172 {
173         Elf_Addr *got = obj->pltgot;
174         const Elf_Sym *def;
175         const Obj_Entry *defobj;
176         Elf_Addr target;
177
178         def = find_symdef(reloff, obj, &defobj, SYMLOOK_IN_PLT, NULL);
179         if (def == NULL)
180                 _rtld_error("bind failed no symbol");
181
182         target = (Elf_Addr)(defobj->relocbase + def->st_value);
183         dbg("bind now/fixup at %s sym # %d in %s --> was=%p new=%p",
184             obj->path,
185             reloff, defobj->strtab + def->st_name, 
186             (void *)got[obj->local_gotno + reloff - obj->gotsym],
187             (void *)target);
188         got[obj->local_gotno + reloff - obj->gotsym] = target;
189         return (Elf_Addr)target;
190 }
191
192 /*
193  * Process non-PLT relocations
194  */
195 int
196 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
197 {
198         const Elf_Rel *rel;
199         const Elf_Rel *rellim;
200         Elf_Addr *got = obj->pltgot;
201         const Elf_Sym *sym, *def;
202         const Obj_Entry *defobj;
203         int i;
204
205         /* The relocation for the dynamic loader has already been done. */
206         if (obj == obj_rtld)
207                 return (0);
208
209         i = (got[1] & 0x80000000) ? 2 : 1;
210
211         /* Relocate the local GOT entries */
212         got += i;
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;
217                     got++;
218         }
219         sym = obj->symtab + obj->gotsym;
220
221
222         dbg("got:%p for %d entries",
223             got, obj->symtabno);
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) {
228                         /*
229                          * If there are non-PLT references to the function,
230                          * st_value should be 0, forcing us to resolve the
231                          * address immediately.
232                          *
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
242                          */
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);
247                         }
248
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);
257                                 }
258                         }
259                 } else {
260                         /* TODO: add cache here */
261                         def = find_symdef(i, obj, &defobj, false, NULL);
262                         if (def == NULL) {
263                           dbg("Warning4, cant find symbole %d", i);
264                                 return -1;
265                         }
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);
274                         } 
275                 }
276                 ++sym;
277                 ++got;
278         }
279         got = obj->pltgot;
280         rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
281         for (rel = obj->rel; rel < rellim; rel++) {
282                 void            *where;
283                 Elf_Addr         tmp;
284                 unsigned long    symnum;
285
286                 where = obj->relocbase + rel->r_offset;
287                 symnum = ELF_R_SYM(rel->r_info);
288                 switch (ELF_R_TYPE(rel->r_info)) {
289                 case R_TYPE(NONE):
290                         break;
291
292                 case R_TYPE(REL32):
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);
299                                 break;
300                         } else {
301                                 tmp = load_ptr(where);
302
303                                 if (def->st_info ==
304                                     ELF_ST_INFO(STB_LOCAL, STT_SECTION)
305                                     )
306                                         tmp += (Elf_Addr)def->st_value;
307
308                                 tmp += (Elf_Addr)obj->relocbase;
309                                 store_ptr(where, tmp);
310                         }
311                         break;
312                 default:
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));
321                         return -1;
322                 }
323         }
324
325         return 0;
326 }
327
328 /*
329  *  Process the PLT relocations.
330  */
331 int
332 reloc_plt(Obj_Entry *obj)
333 {
334         const Elf_Rel *rellim;
335         const Elf_Rel *rel;
336                 
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 +
341             obj->pltrelsize);
342         for (rel = obj->pltrel;  rel < rellim;  rel++) {
343                 Elf_Addr *where;
344                 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
345                 *where += (Elf_Addr )obj->relocbase;
346         }
347
348         return (0);
349 }
350
351 /*
352  * LD_BIND_NOW was set - force relocation for all jump slots
353  */
354 int
355 reloc_jmpslots(Obj_Entry *obj)
356 {
357         /* Do nothing */
358         obj->jmpslots_done = true;
359         
360         return (0);
361 }
362
363 Elf_Addr
364 reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj,
365                 const Obj_Entry *obj, const Elf_Rel *rel)
366 {
367
368         /* Do nothing */
369
370         return target;
371 }
372
373 void
374 allocate_initial_tls(Obj_Entry *objs)
375 {
376         
377 }
378
379 void *
380 __tls_get_addr(tls_index* ti)
381 {
382         return (NULL);
383 }