]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - libexec/rtld-elf/mips/reloc.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.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             NULL);
243         if (def == NULL)
244                 _rtld_error("bind failed no symbol");
245
246         target = (Elf_Addr)(defobj->relocbase + def->st_value);
247         dbg("bind now/fixup at %s sym # %d in %s --> was=%p new=%p",
248             obj->path,
249             reloff, defobj->strtab + def->st_name, 
250             (void *)got[obj->local_gotno + reloff - obj->gotsym],
251             (void *)target);
252         got[obj->local_gotno + reloff - obj->gotsym] = target;
253         return (Elf_Addr)target;
254 }
255
256 int
257 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
258     RtldLockState *lockstate)
259 {
260         const Elf_Rel *rel;
261         const Elf_Rel *rellim;
262         Elf_Addr *got = obj->pltgot;
263         const Elf_Sym *sym, *def;
264         const Obj_Entry *defobj;
265         Elf_Word i;
266 #ifdef SUPPORT_OLD_BROKEN_LD
267         int broken;
268 #endif
269
270         /* The relocation for the dynamic loader has already been done. */
271         if (obj == obj_rtld)
272                 return (0);
273
274 #ifdef SUPPORT_OLD_BROKEN_LD
275         broken = 0;
276         sym = obj->symtab;
277         for (i = 1; i < 12; i++)
278                 if (sym[i].st_info == ELF_ST_INFO(STB_LOCAL, STT_NOTYPE))
279                         broken = 1;
280         dbg("%s: broken=%d", obj->path, broken);
281 #endif
282
283         i = (got[1] & GOT1_MASK) ? 2 : 1;
284
285         /* Relocate the local GOT entries */
286         got += i;
287         dbg("got:%p for %d entries adding %x",
288             got, obj->local_gotno, (uint32_t)obj->relocbase);
289         for (; i < obj->local_gotno; i++) {
290                 *got += (Elf_Addr)obj->relocbase;
291                 got++;
292         }
293         sym = obj->symtab + obj->gotsym;
294
295         dbg("got:%p for %d entries",
296             got, obj->symtabno);
297         /* Now do the global GOT entries */
298         for (i = obj->gotsym; i < obj->symtabno; i++) {
299                 dbg(" doing got %d sym %p (%s, %lx)", i - obj->gotsym, sym,
300                     sym->st_name + obj->strtab, (u_long) *got);
301
302 #ifdef SUPPORT_OLD_BROKEN_LD
303                 if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
304                     broken && sym->st_shndx == SHN_UNDEF) {
305                         /*
306                          * XXX DANGER WILL ROBINSON!
307                          * You might think this is stupid, as it intentionally
308                          * defeats lazy binding -- and you'd be right.
309                          * Unfortunately, for lazy binding to work right, we
310                          * need to a way to force the GOT slots used for
311                          * function pointers to be resolved immediately.  This
312                          * is supposed to be done automatically by the linker,
313                          * by not outputting a PLT slot and setting st_value
314                          * to 0 if there are non-PLT references, but older
315                          * versions of GNU ld do not do this.
316                          */
317                         def = find_symdef(i, obj, &defobj, flags, NULL,
318                             lockstate);
319                         if (def == NULL)
320                                 return -1;
321                         *got = def->st_value + (Elf_Addr)defobj->relocbase;
322                 } else
323 #endif
324                 if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
325                     sym->st_value != 0 && sym->st_shndx == SHN_UNDEF) {
326                         /*
327                          * If there are non-PLT references to the function,
328                          * st_value should be 0, forcing us to resolve the
329                          * address immediately.
330                          *
331                          * XXX DANGER WILL ROBINSON!
332                          * The linker is not outputting PLT slots for calls to
333                          * functions that are defined in the same shared
334                          * library.  This is a bug, because it can screw up
335                          * link ordering rules if the symbol is defined in
336                          * more than one module.  For now, if there is a
337                          * definition, we fail the test above and force a full
338                          * symbol lookup.  This means that all intra-module
339                          * calls are bound immediately.  - mycroft, 2003/09/24
340                          */
341                         *got = sym->st_value + (Elf_Addr)obj->relocbase;
342                         if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) {
343                                 dbg("Warning2, i:%d maps to relocbase address:%x",
344                                     i, (uint32_t)obj->relocbase);
345                         }
346
347                 } else if (sym->st_info == ELF_ST_INFO(STB_GLOBAL, STT_SECTION)) {
348                         /* Symbols with index SHN_ABS are not relocated. */
349                         if (sym->st_shndx != SHN_ABS) {
350                                 *got = sym->st_value +
351                                     (Elf_Addr)obj->relocbase;
352                                 if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) {
353                                         dbg("Warning3, i:%d maps to relocbase address:%x",
354                                             i, (uint32_t)obj->relocbase);
355                                 }
356                         }
357                 } else {
358                         /* TODO: add cache here */
359                         def = find_symdef(i, obj, &defobj, flags, NULL,
360                             lockstate);
361                         if (def == NULL) {
362                                 dbg("Warning4, cant find symbole %d", i);
363                                 return -1;
364                         }
365                         *got = def->st_value + (Elf_Addr)defobj->relocbase;
366                         if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) {
367                                 dbg("Warning4, i:%d maps to relocbase address:%x",
368                                     i, (uint32_t)obj->relocbase);
369                                 dbg("via first obj symbol %s",
370                                     obj->strtab + obj->symtab[i].st_name);
371                                 dbg("found in obj %p:%s",
372                                     defobj, defobj->path);
373                         }
374                 }
375
376                 dbg("  --> now %lx", (u_long) *got);
377                 ++sym;
378                 ++got;
379         }
380
381         got = obj->pltgot;
382         rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
383         for (rel = obj->rel; rel < rellim; rel++) {
384                 Elf_Word        r_symndx, r_type;
385                 void            *where;
386
387                 where = obj->relocbase + rel->r_offset;
388                 r_symndx = ELF_R_SYM(rel->r_info);
389                 r_type = ELF_R_TYPE(rel->r_info);
390
391                 switch (r_type & 0xff) {
392                 case R_TYPE(NONE):
393                         break;
394
395                 case R_TYPE(REL32): {
396                         /* 32-bit PC-relative reference */
397                         const size_t rlen =
398                             ELF_R_NXTTYPE_64_P(r_type)
399                                 ? sizeof(Elf_Sxword)
400                                 : sizeof(Elf_Sword);
401                         Elf_Sxword old = load_ptr(where, rlen);
402                         Elf_Sxword val = old;
403
404                         def = obj->symtab + r_symndx;
405
406                         if (r_symndx >= obj->gotsym) {
407                                 val += got[obj->local_gotno + r_symndx - obj->gotsym];
408                                 dbg("REL32/G(%p) %p --> %p (%s) in %s",
409                                     where, (void *)old, (void *)val,
410                                     obj->strtab + def->st_name,
411                                     obj->path);
412                         } else {
413                                 /*
414                                  * XXX: ABI DIFFERENCE!
415                                  *
416                                  * Old NetBSD binutils would generate shared
417                                  * libs with section-relative relocations being
418                                  * already adjusted for the start address of
419                                  * the section.
420                                  *
421                                  * New binutils, OTOH, generate shared libs
422                                  * with the same relocations being based at
423                                  * zero, so we need to add in the start address
424                                  * of the section.
425                                  *
426                                  * --rkb, Oct 6, 2001
427                                  */
428
429                                 if (def->st_info ==
430                                     ELF_ST_INFO(STB_LOCAL, STT_SECTION)
431 #ifdef SUPPORT_OLD_BROKEN_LD
432                                     && !broken
433 #endif
434                                     )
435                                         val += (Elf_Addr)def->st_value;
436
437                                 val += (Elf_Addr)obj->relocbase;
438
439                                 dbg("REL32/L(%p) %p -> %p (%s) in %s",
440                                     where, (void *)old, (void *)val,
441                                     obj->strtab + def->st_name, obj->path);
442                         }
443                         store_ptr(where, val, rlen);
444                         break;
445                 }
446
447                 default:
448                         dbg("sym = %lu, type = %lu, offset = %p, "
449                             "contents = %p, symbol = %s",
450                             (u_long)r_symndx, (u_long)ELF_R_TYPE(rel->r_info),
451                             (void *)rel->r_offset,
452                             (void *)load_ptr(where, sizeof(Elf_Sword)),
453                             obj->strtab + obj->symtab[r_symndx].st_name);
454                         _rtld_error("%s: Unsupported relocation type %ld "
455                             "in non-PLT relocations",
456                             obj->path, (u_long) ELF_R_TYPE(rel->r_info));
457                         return -1;
458                 }
459         }
460
461         return 0;
462 }
463
464 /*
465  *  Process the PLT relocations.
466  */
467 int
468 reloc_plt(Obj_Entry *obj)
469 {
470 #if 0
471         const Elf_Rel *rellim;
472         const Elf_Rel *rel;
473                 
474         dbg("reloc_plt obj:%p pltrel:%p sz:%d", obj, obj->pltrel, (int)obj->pltrelsize);
475         dbg("gottable %p num syms:%d", obj->pltgot, obj->symtabno );
476         dbg("*****************************************************");
477         rellim = (const Elf_Rel *)((char *)obj->pltrel +
478             obj->pltrelsize);
479         for (rel = obj->pltrel;  rel < rellim;  rel++) {
480                 Elf_Addr *where;
481                 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
482                 *where += (Elf_Addr )obj->relocbase;
483         }
484
485 #endif
486         /* PLT fixups were done above in the GOT relocation. */
487         return (0);
488 }
489
490 /*
491  * LD_BIND_NOW was set - force relocation for all jump slots
492  */
493 int
494 reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
495 {
496         /* Do nothing */
497         obj->jmpslots_done = true;
498         
499         return (0);
500 }
501
502 int
503 reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
504 {
505
506         /* XXX not implemented */
507         return (0);
508 }
509
510 int
511 reloc_gnu_ifunc(Obj_Entry *obj, int flags,
512     struct Struct_RtldLockState *lockstate)
513 {
514
515         /* XXX not implemented */
516         return (0);
517 }
518
519 Elf_Addr
520 reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj,
521                 const Obj_Entry *obj, const Elf_Rel *rel)
522 {
523
524         /* Do nothing */
525
526         return target;
527 }
528
529 void
530 allocate_initial_tls(Obj_Entry *objs)
531 {
532         
533 }
534
535 void *
536 __tls_get_addr(tls_index* ti)
537 {
538         return (NULL);
539 }