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