]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - libexec/rtld-elf/mips/reloc.c
Copy stable/8 to releng/8.2 in preparation for FreeBSD-8.2 release.
[FreeBSD/releng/8.2.git] / libexec / rtld-elf / mips / reloc.c
1 /*      $NetBSD: mips_reloc.c,v 1.58 2010/01/14 11:57:06 skrll Exp $    */
2
3 /*
4  * Copyright 1997 Michael L. Hitch <mhitch@montana.edu>
5  * Portions copyright 2002 Charles M. Hannum <root@ihack.net>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/endian.h>
37
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include "debug.h"
42 #include "rtld.h"
43
44 #ifdef __mips_n64
45 #define GOT1_MASK       0x8000000000000000UL
46 #else
47 #define GOT1_MASK       0x80000000UL
48 #endif
49
50 void
51 init_pltgot(Obj_Entry *obj)
52 {
53         if (obj->pltgot != NULL) {
54                 obj->pltgot[0] = (Elf_Addr) &_rtld_bind_start;
55                 if (obj->pltgot[1] & 0x80000000)
56                         obj->pltgot[1] = (Elf_Addr) obj | GOT1_MASK;
57         }
58 }
59
60 int
61 do_copy_relocations(Obj_Entry *dstobj)
62 {
63         /* Do nothing */
64         return 0;
65 }
66
67 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
68
69 /*
70  * It is possible for the compiler to emit relocations for unaligned data.
71  * We handle this situation with these inlines.
72  */
73 #ifdef __mips_n64
74 /*
75  * ELF64 MIPS encodes the relocs uniquely.  The first 32-bits of info contain
76  * the symbol index.  The top 32-bits contain three relocation types encoded
77  * in big-endian integer with first relocation in LSB.  This means for little
78  * endian we have to byte swap that integer (r_type).
79  */
80 #define Elf_Sxword                      Elf64_Sxword
81 #define ELF_R_NXTTYPE_64_P(r_type)      ((((r_type) >> 8) & 0xff) == R_TYPE(64))
82 #if BYTE_ORDER == LITTLE_ENDIAN
83 #undef ELF_R_SYM
84 #undef ELF_R_TYPE
85 #define ELF_R_SYM(r_info)               ((r_info) & 0xffffffff)
86 #define ELF_R_TYPE(r_info)              bswap32(((r_info) >> 32))
87 #endif
88 #else
89 #define ELF_R_NXTTYPE_64_P(r_type)      (0)
90 #define Elf_Sxword                      Elf32_Sword
91 #endif
92
93 static __inline Elf_Sxword
94 load_ptr(void *where, size_t len)
95 {
96         Elf_Sxword val;
97
98         if (__predict_true(((uintptr_t)where & (len - 1)) == 0)) {
99 #ifdef __mips_n64
100                 if (len == sizeof(Elf_Sxword))
101                         return *(Elf_Sxword *)where;
102 #endif
103                 return *(Elf_Sword *)where;
104         }
105
106         val = 0;
107 #if BYTE_ORDER == LITTLE_ENDIAN
108         (void)memcpy(&val, where, len);
109 #endif
110 #if BYTE_ORDER == BIG_ENDIAN
111         (void)memcpy((uint8_t *)((&val)+1) - len, where, len);
112 #endif
113         return (len == sizeof(Elf_Sxword)) ? val : (Elf_Sword)val;
114 }
115
116 static __inline void
117 store_ptr(void *where, Elf_Sxword val, size_t len)
118 {
119         if (__predict_true(((uintptr_t)where & (len - 1)) == 0)) {
120 #ifdef __mips_n64
121                 if (len == sizeof(Elf_Sxword)) {
122                         *(Elf_Sxword *)where = val;
123                         return;
124                 }
125 #endif
126                 *(Elf_Sword *)where = val;
127                 return;
128         }
129 #if BYTE_ORDER == LITTLE_ENDIAN
130         (void)memcpy(where, &val, len);
131 #endif
132 #if BYTE_ORDER == BIG_ENDIAN
133         (void)memcpy(where, (const uint8_t *)((&val)+1) - len, len);
134 #endif
135 }
136
137 void
138 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
139 {
140         const Elf_Rel *rel = 0, *rellim;
141         Elf_Addr relsz = 0;
142         const Elf_Sym *symtab = NULL, *sym;
143         Elf_Addr *where;
144         Elf_Addr *got = NULL;
145         Elf_Word local_gotno = 0, symtabno = 0, gotsym = 0;
146         size_t i;
147
148         for (; dynp->d_tag != DT_NULL; dynp++) {
149                 switch (dynp->d_tag) {
150                 case DT_REL:
151                         rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
152                         break;
153                 case DT_RELSZ:
154                         relsz = dynp->d_un.d_val;
155                         break;
156                 case DT_SYMTAB:
157                         symtab = (const Elf_Sym *)(relocbase + dynp->d_un.d_ptr);
158                         break;
159                 case DT_PLTGOT:
160                         got = (Elf_Addr *)(relocbase + dynp->d_un.d_ptr);
161                         break;
162                 case DT_MIPS_LOCAL_GOTNO:
163                         local_gotno = dynp->d_un.d_val;
164                         break;
165                 case DT_MIPS_SYMTABNO:
166                         symtabno = dynp->d_un.d_val;
167                         break;
168                 case DT_MIPS_GOTSYM:
169                         gotsym = dynp->d_un.d_val;
170                         break;
171                 }
172         }
173
174         i = (got[1] & GOT1_MASK) ? 2 : 1;
175         /* Relocate the local GOT entries */
176         got += i;
177         for (; i < local_gotno; i++) {
178                 *got++ += relocbase;
179         }
180
181         sym = symtab + gotsym;
182         /* Now do the global GOT entries */
183         for (i = gotsym; i < symtabno; i++) {
184                 *got = sym->st_value + relocbase;
185                 ++sym;
186                 ++got;
187         }
188
189         rellim = (const Elf_Rel *)((caddr_t)rel + relsz);
190         for (; rel < rellim; rel++) {
191                 Elf_Word r_symndx, r_type;
192
193                 where = (void *)(relocbase + rel->r_offset);
194
195                 r_symndx = ELF_R_SYM(rel->r_info);
196                 r_type = ELF_R_TYPE(rel->r_info);
197
198                 switch (r_type & 0xff) {
199                 case R_TYPE(REL32): {
200                         const size_t rlen =
201                             ELF_R_NXTTYPE_64_P(r_type)
202                                 ? sizeof(Elf_Sxword)
203                                 : sizeof(Elf_Sword);
204                         Elf_Sxword old = load_ptr(where, rlen);
205                         Elf_Sxword val = old;
206 #ifdef __mips_n64
207                         assert(r_type == R_TYPE(REL32)
208                             || r_type == (R_TYPE(REL32)|(R_TYPE(64) << 8)));
209 #endif
210                         assert(r_symndx < gotsym);
211                         sym = symtab + r_symndx;
212                         assert(ELF_ST_BIND(sym->st_info) == STB_LOCAL);
213                         val += relocbase;
214                         store_ptr(where, val, sizeof(Elf_Sword));
215                         dbg("REL32/L(%p) %p -> %p in <self>",
216                             where, (void *)old, (void *)val);
217                         store_ptr(where, val, rlen);
218                         break;
219                 }
220
221                 case R_TYPE(GPREL32):
222                 case R_TYPE(NONE):
223                         break;
224
225
226                 default:
227                         abort();
228                         break;
229                 }
230         }
231 }
232
233 Elf_Addr
234 _mips_rtld_bind(Obj_Entry *obj, Elf_Size reloff)
235 {
236         Elf_Addr *got = obj->pltgot;
237         const Elf_Sym *def;
238         const Obj_Entry *defobj;
239         Elf_Addr target;
240
241         def = find_symdef(reloff, obj, &defobj, SYMLOOK_IN_PLT, NULL);
242         if (def == NULL)
243                 _rtld_error("bind failed no symbol");
244
245         target = (Elf_Addr)(defobj->relocbase + def->st_value);
246         dbg("bind now/fixup at %s sym # %d in %s --> was=%p new=%p",
247             obj->path,
248             reloff, defobj->strtab + def->st_name, 
249             (void *)got[obj->local_gotno + reloff - obj->gotsym],
250             (void *)target);
251         got[obj->local_gotno + reloff - obj->gotsym] = target;
252         return (Elf_Addr)target;
253 }
254
255 int
256 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
257 {
258         const Elf_Rel *rel;
259         const Elf_Rel *rellim;
260         Elf_Addr *got = obj->pltgot;
261         const Elf_Sym *sym, *def;
262         const Obj_Entry *defobj;
263         Elf_Word i;
264 #ifdef SUPPORT_OLD_BROKEN_LD
265         int broken;
266 #endif
267
268         /* The relocation for the dynamic loader has already been done. */
269         if (obj == obj_rtld)
270                 return (0);
271
272 #ifdef SUPPORT_OLD_BROKEN_LD
273         broken = 0;
274         sym = obj->symtab;
275         for (i = 1; i < 12; i++)
276                 if (sym[i].st_info == ELF_ST_INFO(STB_LOCAL, STT_NOTYPE))
277                         broken = 1;
278         dbg("%s: broken=%d", obj->path, broken);
279 #endif
280
281         i = (got[1] & GOT1_MASK) ? 2 : 1;
282
283         /* Relocate the local GOT entries */
284         got += i;
285         dbg("got:%p for %d entries adding %x",
286             got, obj->local_gotno, (uint32_t)obj->relocbase);
287         for (; i < obj->local_gotno; i++) {
288                 *got += (Elf_Addr)obj->relocbase;
289                 got++;
290         }
291         sym = obj->symtab + obj->gotsym;
292
293         dbg("got:%p for %d entries",
294             got, obj->symtabno);
295         /* Now do the global GOT entries */
296         for (i = obj->gotsym; i < obj->symtabno; i++) {
297                 dbg(" doing got %d sym %p (%s, %lx)", i - obj->gotsym, sym,
298                     sym->st_name + obj->strtab, (u_long) *got);
299
300 #ifdef SUPPORT_OLD_BROKEN_LD
301                 if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
302                     broken && sym->st_shndx == SHN_UNDEF) {
303                         /*
304                          * XXX DANGER WILL ROBINSON!
305                          * You might think this is stupid, as it intentionally
306                          * defeats lazy binding -- and you'd be right.
307                          * Unfortunately, for lazy binding to work right, we
308                          * need to a way to force the GOT slots used for
309                          * function pointers to be resolved immediately.  This
310                          * is supposed to be done automatically by the linker,
311                          * by not outputting a PLT slot and setting st_value
312                          * to 0 if there are non-PLT references, but older
313                          * versions of GNU ld do not do this.
314                          */
315                         def = find_symdef(i, obj, &defobj, false, NULL);
316                         if (def == NULL)
317                                 return -1;
318                         *got = def->st_value + (Elf_Addr)defobj->relocbase;
319                 } else
320 #endif
321                 if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
322                     sym->st_value != 0 && sym->st_shndx == SHN_UNDEF) {
323                         /*
324                          * If there are non-PLT references to the function,
325                          * st_value should be 0, forcing us to resolve the
326                          * address immediately.
327                          *
328                          * XXX DANGER WILL ROBINSON!
329                          * The linker is not outputting PLT slots for calls to
330                          * functions that are defined in the same shared
331                          * library.  This is a bug, because it can screw up
332                          * link ordering rules if the symbol is defined in
333                          * more than one module.  For now, if there is a
334                          * definition, we fail the test above and force a full
335                          * symbol lookup.  This means that all intra-module
336                          * calls are bound immediately.  - mycroft, 2003/09/24
337                          */
338                         *got = sym->st_value + (Elf_Addr)obj->relocbase;
339                         if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) {
340                                 dbg("Warning2, i:%d maps to relocbase address:%x",
341                                     i, (uint32_t)obj->relocbase);
342                         }
343
344                 } else if (sym->st_info == ELF_ST_INFO(STB_GLOBAL, STT_SECTION)) {
345                         /* Symbols with index SHN_ABS are not relocated. */
346                         if (sym->st_shndx != SHN_ABS) {
347                                 *got = sym->st_value +
348                                     (Elf_Addr)obj->relocbase;
349                                 if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) {
350                                         dbg("Warning3, i:%d maps to relocbase address:%x",
351                                             i, (uint32_t)obj->relocbase);
352                                 }
353                         }
354                 } else {
355                         /* TODO: add cache here */
356                         def = find_symdef(i, obj, &defobj, false, NULL);
357                         if (def == NULL) {
358                                 dbg("Warning4, cant find symbole %d", i);
359                                 return -1;
360                         }
361                         *got = def->st_value + (Elf_Addr)defobj->relocbase;
362                         if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) {
363                                 dbg("Warning4, i:%d maps to relocbase address:%x",
364                                     i, (uint32_t)obj->relocbase);
365                                 dbg("via first obj symbol %s",
366                                     obj->strtab + obj->symtab[i].st_name);
367                                 dbg("found in obj %p:%s",
368                                     defobj, defobj->path);
369                         }
370                 }
371
372                 dbg("  --> now %lx", (u_long) *got);
373                 ++sym;
374                 ++got;
375         }
376
377         got = obj->pltgot;
378         rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
379         for (rel = obj->rel; rel < rellim; rel++) {
380                 Elf_Word        r_symndx, r_type;
381                 void            *where;
382
383                 where = obj->relocbase + rel->r_offset;
384                 r_symndx = ELF_R_SYM(rel->r_info);
385                 r_type = ELF_R_TYPE(rel->r_info);
386
387                 switch (r_type & 0xff) {
388                 case R_TYPE(NONE):
389                         break;
390
391                 case R_TYPE(REL32): {
392                         /* 32-bit PC-relative reference */
393                         const size_t rlen =
394                             ELF_R_NXTTYPE_64_P(r_type)
395                                 ? sizeof(Elf_Sxword)
396                                 : sizeof(Elf_Sword);
397                         Elf_Sxword old = load_ptr(where, rlen);
398                         Elf_Sxword val = old;
399
400                         def = obj->symtab + r_symndx;
401
402                         if (r_symndx >= obj->gotsym) {
403                                 val += got[obj->local_gotno + r_symndx - obj->gotsym];
404                                 dbg("REL32/G(%p) %p --> %p (%s) in %s",
405                                     where, (void *)old, (void *)val,
406                                     obj->strtab + def->st_name,
407                                     obj->path);
408                         } else {
409                                 /*
410                                  * XXX: ABI DIFFERENCE!
411                                  *
412                                  * Old NetBSD binutils would generate shared
413                                  * libs with section-relative relocations being
414                                  * already adjusted for the start address of
415                                  * the section.
416                                  *
417                                  * New binutils, OTOH, generate shared libs
418                                  * with the same relocations being based at
419                                  * zero, so we need to add in the start address
420                                  * of the section.
421                                  *
422                                  * --rkb, Oct 6, 2001
423                                  */
424
425                                 if (def->st_info ==
426                                     ELF_ST_INFO(STB_LOCAL, STT_SECTION)
427 #ifdef SUPPORT_OLD_BROKEN_LD
428                                     && !broken
429 #endif
430                                     )
431                                         val += (Elf_Addr)def->st_value;
432
433                                 val += (Elf_Addr)obj->relocbase;
434
435                                 dbg("REL32/L(%p) %p -> %p (%s) in %s",
436                                     where, (void *)old, (void *)val,
437                                     obj->strtab + def->st_name, obj->path);
438                         }
439                         store_ptr(where, val, rlen);
440                         break;
441                 }
442
443                 default:
444                         dbg("sym = %lu, type = %lu, offset = %p, "
445                             "contents = %p, symbol = %s",
446                             (u_long)r_symndx, (u_long)ELF_R_TYPE(rel->r_info),
447                             (void *)rel->r_offset,
448                             (void *)load_ptr(where, sizeof(Elf_Sword)),
449                             obj->strtab + obj->symtab[r_symndx].st_name);
450                         _rtld_error("%s: Unsupported relocation type %ld "
451                             "in non-PLT relocations",
452                             obj->path, (u_long) ELF_R_TYPE(rel->r_info));
453                         return -1;
454                 }
455         }
456
457         return 0;
458 }
459
460 /*
461  *  Process the PLT relocations.
462  */
463 int
464 reloc_plt(Obj_Entry *obj)
465 {
466 #if 0
467         const Elf_Rel *rellim;
468         const Elf_Rel *rel;
469                 
470         dbg("reloc_plt obj:%p pltrel:%p sz:%d", obj, obj->pltrel, (int)obj->pltrelsize);
471         dbg("gottable %p num syms:%d", obj->pltgot, obj->symtabno );
472         dbg("*****************************************************");
473         rellim = (const Elf_Rel *)((char *)obj->pltrel +
474             obj->pltrelsize);
475         for (rel = obj->pltrel;  rel < rellim;  rel++) {
476                 Elf_Addr *where;
477                 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
478                 *where += (Elf_Addr )obj->relocbase;
479         }
480
481 #endif
482         /* PLT fixups were done above in the GOT relocation. */
483         return (0);
484 }
485
486 /*
487  * LD_BIND_NOW was set - force relocation for all jump slots
488  */
489 int
490 reloc_jmpslots(Obj_Entry *obj)
491 {
492         /* Do nothing */
493         obj->jmpslots_done = true;
494         
495         return (0);
496 }
497
498 Elf_Addr
499 reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj,
500                 const Obj_Entry *obj, const Elf_Rel *rel)
501 {
502
503         /* Do nothing */
504
505         return target;
506 }
507
508 void
509 allocate_initial_tls(Obj_Entry *objs)
510 {
511         
512 }
513
514 void *
515 __tls_get_addr(tls_index* ti)
516 {
517         return (NULL);
518 }