1 /* $NetBSD: mips_reloc.c,v 1.63 2014/08/25 20:40:52 joerg Exp $ */
4 * Copyright 1997 Michael L. Hitch <mhitch@montana.edu>
5 * Portions copyright 2002 Charles M. Hannum <root@ihack.net>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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.
31 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: mips_reloc.c,v 1.63 2014/08/25 20:40:52 joerg Exp $");
36 #include <sys/types.h>
37 #include <sys/endian.h>
47 #define SUPPORT_OLD_BROKEN_LD
50 void _rtld_bind_start(void);
51 void _rtld_relocate_nonplt_self(Elf_Dyn
*, Elf_Addr
);
52 caddr_t
_rtld_bind(Elf_Word
, Elf_Addr
, Elf_Addr
, Elf_Addr
);
55 * It is possible for the compiler to emit relocations for unaligned data.
56 * We handle this situation with these inlines.
61 * ELF64 MIPS encodes the relocs uniquely. The first 32-bits of info contain
62 * the symbol index. The top 32-bits contain three relocation types encoded
63 * in big-endian integer with first relocation in LSB. This means for little
64 * endian we have to byte swap that interger (r_type).
66 #define Elf_Sxword Elf64_Sxword
67 #define ELF_R_NXTTYPE_64_P(r_type) ((((r_type) >> 8) & 0xff) == R_TYPE(64))
68 #if BYTE_ORDER == LITTLE_ENDIAN
71 #define ELF_R_SYM(r_info) ((r_info) & 0xffffffff)
72 #define ELF_R_TYPE(r_info) bswap32((r_info) >> 32)
75 #define ELF_R_NXTTYPE_64_P(r_type) (0)
76 #define Elf_Sxword Elf32_Sword
78 #define GOT1_MASK (~(Elf_Addr)0 >> 1)
80 static inline Elf_Sxword
81 load_ptr(void *where
, size_t len
)
85 if (__predict_true(((uintptr_t)where
& (len
- 1)) == 0)) {
87 if (len
== sizeof(Elf_Sxword
))
88 return *(Elf_Sxword
*)where
;
90 return *(Elf_Sword
*)where
;
94 #if BYTE_ORDER == LITTLE_ENDIAN
95 (void)memcpy(&val
, where
, len
);
97 #if BYTE_ORDER == BIG_ENDIAN
98 (void)memcpy((uint8_t *)((&val
)+1) - len
, where
, len
);
100 return (len
== sizeof(Elf_Sxword
)) ? val
: (Elf_Sword
)val
;
104 store_ptr(void *where
, Elf_Sxword val
, size_t len
)
106 if (__predict_true(((uintptr_t)where
& (len
- 1)) == 0)) {
108 if (len
== sizeof(Elf_Sxword
)) {
109 *(Elf_Sxword
*)where
= val
;
113 *(Elf_Sword
*)where
= val
;
116 #if BYTE_ORDER == LITTLE_ENDIAN
117 (void)memcpy(where
, &val
, len
);
119 #if BYTE_ORDER == BIG_ENDIAN
120 (void)memcpy(where
, (const uint8_t *)((&val
)+1) - len
, len
);
126 _rtld_setup_pltgot(const Obj_Entry
*obj
)
128 obj
->pltgot
[0] = (Elf_Addr
) &_rtld_bind_start
;
129 /* XXX only if obj->pltgot[1] & 0x80000000 ?? */
130 obj
->pltgot
[1] |= (Elf_Addr
) obj
;
134 _rtld_relocate_nonplt_self(Elf_Dyn
*dynp
, Elf_Addr relocbase
)
136 const Elf_Rel
*rel
= 0, *rellim
;
139 const Elf_Sym
*symtab
= NULL
, *sym
;
140 Elf_Addr
*got
= NULL
;
141 Elf_Word local_gotno
= 0, symtabno
= 0, gotsym
= 0;
144 for (; dynp
->d_tag
!= DT_NULL
; dynp
++) {
145 switch (dynp
->d_tag
) {
147 rel
= (const Elf_Rel
*)(relocbase
+ dynp
->d_un
.d_ptr
);
150 relsz
= dynp
->d_un
.d_val
;
153 symtab
= (const Elf_Sym
*)(relocbase
+ dynp
->d_un
.d_ptr
);
156 got
= (Elf_Addr
*)(relocbase
+ dynp
->d_un
.d_ptr
);
158 case DT_MIPS_LOCAL_GOTNO
:
159 local_gotno
= dynp
->d_un
.d_val
;
161 case DT_MIPS_SYMTABNO
:
162 symtabno
= dynp
->d_un
.d_val
;
165 gotsym
= dynp
->d_un
.d_val
;
170 i
= (got
[1] & 0x80000000) ? 2 : 1;
171 /* Relocate the local GOT entries */
173 for (; i
< local_gotno
; i
++)
175 sym
= symtab
+ gotsym
;
176 /* Now do the global GOT entries */
177 for (i
= gotsym
; i
< symtabno
; i
++) {
178 *got
= sym
->st_value
+ relocbase
;
183 rellim
= (const Elf_Rel
*)((uintptr_t)rel
+ relsz
);
184 for (; rel
< rellim
; rel
++) {
185 Elf_Word r_symndx
, r_type
;
187 where
= (void *)(relocbase
+ rel
->r_offset
);
189 r_symndx
= ELF_R_SYM(rel
->r_info
);
190 r_type
= ELF_R_TYPE(rel
->r_info
);
192 switch (r_type
& 0xff) {
193 case R_TYPE(REL32
): {
195 ELF_R_NXTTYPE_64_P(r_type
)
198 Elf_Sxword old
= load_ptr(where
, rlen
);
199 Elf_Sxword val
= old
;
201 assert(r_type
== R_TYPE(REL32
)
202 || r_type
== (R_TYPE(REL32
)|(R_TYPE(64) << 8)));
204 assert(r_symndx
< gotsym
);
205 sym
= symtab
+ r_symndx
;
206 assert(ELF_ST_BIND(sym
->st_info
) == STB_LOCAL
);
208 store_ptr(where
, val
, sizeof(Elf_Sword
));
209 rdbg(("REL32/L(%p) %p -> %p in <self>",
210 where
, (void *)old
, (void *)val
));
211 store_ptr(where
, val
, rlen
);
215 case R_TYPE(GPREL32
):
227 _rtld_relocate_nonplt_objects(Obj_Entry
*obj
)
230 Elf_Addr
*got
= obj
->pltgot
;
231 const Elf_Sym
*sym
, *def
;
232 const Obj_Entry
*defobj
;
234 #ifdef SUPPORT_OLD_BROKEN_LD
238 #ifdef SUPPORT_OLD_BROKEN_LD
241 for (i
= 1; i
< 12; i
++)
242 if (sym
[i
].st_info
== ELF_ST_INFO(STB_LOCAL
, STT_NOTYPE
))
244 dbg(("%s: broken=%d", obj
->path
, broken
));
247 i
= (got
[1] & 0x80000000) ? 2 : 1;
248 /* Relocate the local GOT entries */
250 for (; i
< obj
->local_gotno
; i
++)
251 *got
++ += (Elf_Addr
)obj
->relocbase
;
252 sym
= obj
->symtab
+ obj
->gotsym
;
253 /* Now do the global GOT entries */
254 for (i
= obj
->gotsym
; i
< obj
->symtabno
; i
++) {
255 rdbg((" doing got %d sym %p (%s, %lx)", i
- obj
->gotsym
, sym
,
256 sym
->st_name
+ obj
->strtab
, (u_long
) *got
));
258 #ifdef SUPPORT_OLD_BROKEN_LD
259 if (ELF_ST_TYPE(sym
->st_info
) == STT_FUNC
&&
260 broken
&& sym
->st_shndx
== SHN_UNDEF
) {
262 * XXX DANGER WILL ROBINSON!
263 * You might think this is stupid, as it intentionally
264 * defeats lazy binding -- and you'd be right.
265 * Unfortunately, for lazy binding to work right, we
266 * need to a way to force the GOT slots used for
267 * function pointers to be resolved immediately. This
268 * is supposed to be done automatically by the linker,
269 * by not outputting a PLT slot and setting st_value
270 * to 0 if there are non-PLT references, but older
271 * versions of GNU ld do not do this.
273 def
= _rtld_find_symdef(i
, obj
, &defobj
, false);
276 *got
= def
->st_value
+ (Elf_Addr
)defobj
->relocbase
;
279 if (ELF_ST_TYPE(sym
->st_info
) == STT_FUNC
&&
280 sym
->st_value
!= 0 && sym
->st_shndx
== SHN_UNDEF
) {
282 * If there are non-PLT references to the function,
283 * st_value should be 0, forcing us to resolve the
284 * address immediately.
286 * XXX DANGER WILL ROBINSON!
287 * The linker is not outputting PLT slots for calls to
288 * functions that are defined in the same shared
289 * library. This is a bug, because it can screw up
290 * link ordering rules if the symbol is defined in
291 * more than one module. For now, if there is a
292 * definition, we fail the test above and force a full
293 * symbol lookup. This means that all intra-module
294 * calls are bound immediately. - mycroft, 2003/09/24
296 *got
= sym
->st_value
+ (Elf_Addr
)obj
->relocbase
;
297 } else if (sym
->st_info
== ELF_ST_INFO(STB_GLOBAL
, STT_SECTION
)) {
298 /* Symbols with index SHN_ABS are not relocated. */
299 if (sym
->st_shndx
!= SHN_ABS
)
300 *got
= sym
->st_value
+
301 (Elf_Addr
)obj
->relocbase
;
303 def
= _rtld_find_symdef(i
, obj
, &defobj
, false);
306 *got
= def
->st_value
+ (Elf_Addr
)defobj
->relocbase
;
309 rdbg((" --> now %lx", (u_long
) *got
));
315 for (rel
= obj
->rel
; rel
< obj
->rellim
; rel
++) {
316 Elf_Word r_symndx
, r_type
;
319 where
= obj
->relocbase
+ rel
->r_offset
;
320 r_symndx
= ELF_R_SYM(rel
->r_info
);
321 r_type
= ELF_R_TYPE(rel
->r_info
);
323 switch (r_type
& 0xff) {
327 case R_TYPE(REL32
): {
328 /* 32-bit PC-relative reference */
330 ELF_R_NXTTYPE_64_P(r_type
)
333 Elf_Sxword old
= load_ptr(where
, rlen
);
334 Elf_Sxword val
= old
;
336 def
= obj
->symtab
+ r_symndx
;
338 if (r_symndx
>= obj
->gotsym
) {
339 val
+= got
[obj
->local_gotno
+ r_symndx
- obj
->gotsym
];
340 rdbg(("REL32/G(%p) %p --> %p (%s) in %s",
341 where
, (void *)old
, (void *)val
,
342 obj
->strtab
+ def
->st_name
,
346 * XXX: ABI DIFFERENCE!
348 * Old NetBSD binutils would generate shared
349 * libs with section-relative relocations being
350 * already adjusted for the start address of
353 * New binutils, OTOH, generate shared libs
354 * with the same relocations being based at
355 * zero, so we need to add in the start address
362 ELF_ST_INFO(STB_LOCAL
, STT_SECTION
)
363 #ifdef SUPPORT_OLD_BROKEN_LD
367 val
+= (Elf_Addr
)def
->st_value
;
369 val
+= (Elf_Addr
)obj
->relocbase
;
371 rdbg(("REL32/L(%p) %p -> %p (%s) in %s",
372 where
, (void *)old
, (void *)val
,
373 obj
->strtab
+ def
->st_name
, obj
->path
));
375 store_ptr(where
, val
, rlen
);
380 case R_TYPE(TLS_DTPMOD64
):
382 case R_TYPE(TLS_DTPMOD32
):
385 Elf_Addr old
= load_ptr(where
, ELFSIZE
/ 8);
388 def
= _rtld_find_symdef(r_symndx
, obj
, &defobj
, false);
392 val
+= (Elf_Addr
)defobj
->tlsindex
;
394 store_ptr(where
, val
, ELFSIZE
/ 8);
395 rdbg(("DTPMOD %s in %s --> %p in %s",
396 obj
->strtab
+ obj
->symtab
[r_symndx
].st_name
,
397 obj
->path
, (void *)old
, defobj
->path
));
402 case R_TYPE(TLS_DTPREL64
):
404 case R_TYPE(TLS_DTPREL32
):
407 Elf_Addr old
= load_ptr(where
, ELFSIZE
/ 8);
410 def
= _rtld_find_symdef(r_symndx
, obj
, &defobj
, false);
414 if (!defobj
->tls_done
&& _rtld_tls_offset_allocate(obj
))
417 val
+= (Elf_Addr
)def
->st_value
- TLS_DTV_OFFSET
;
418 store_ptr(where
, val
, ELFSIZE
/ 8);
420 rdbg(("DTPREL %s in %s --> %p in %s",
421 obj
->strtab
+ obj
->symtab
[r_symndx
].st_name
,
422 obj
->path
, (void *)old
, defobj
->path
));
427 case R_TYPE(TLS_TPREL64
):
429 case R_TYPE(TLS_TPREL32
):
432 Elf_Addr old
= load_ptr(where
, ELFSIZE
/ 8);
435 def
= _rtld_find_symdef(r_symndx
, obj
, &defobj
, false);
439 if (!defobj
->tls_done
&& _rtld_tls_offset_allocate(obj
))
442 val
+= (Elf_Addr
)(def
->st_value
+ defobj
->tlsoffset
444 store_ptr(where
, val
, ELFSIZE
/ 8);
446 rdbg(("TPREL %s in %s --> %p in %s",
447 obj
->strtab
+ obj
->symtab
[r_symndx
].st_name
,
448 obj
->path
, (void *)*where
, defobj
->path
));
453 rdbg(("sym = %lu, type = %lu, offset = %p, "
454 "contents = %p, symbol = %s",
455 (u_long
)r_symndx
, (u_long
)ELF_R_TYPE(rel
->r_info
),
456 (void *)rel
->r_offset
,
457 (void *)load_ptr(where
, sizeof(Elf_Sword
)),
458 obj
->strtab
+ obj
->symtab
[r_symndx
].st_name
));
459 _rtld_error("%s: Unsupported relocation type %ld "
460 "in non-PLT relocations",
461 obj
->path
, (u_long
) ELF_R_TYPE(rel
->r_info
));
470 _rtld_relocate_plt_lazy(const Obj_Entry
*obj
)
472 /* PLT fixups were done above in the GOT relocation. */
477 _rtld_relocate_plt_object(const Obj_Entry
*obj
, Elf_Word sym
, Elf_Addr
*tp
)
479 Elf_Addr
*got
= obj
->pltgot
;
481 const Obj_Entry
*defobj
;
484 def
= _rtld_find_plt_symdef(sym
, obj
, &defobj
, tp
!= NULL
);
485 if (__predict_false(def
== NULL
))
487 if (__predict_false(def
== &_rtld_sym_zero
))
490 if (ELF_ST_TYPE(def
->st_info
) == STT_GNU_IFUNC
) {
493 new_value
= _rtld_resolve_ifunc(defobj
, def
);
495 new_value
= (Elf_Addr
)(defobj
->relocbase
+ def
->st_value
);
497 rdbg(("bind now/fixup in %s --> new=%p",
498 defobj
->strtab
+ def
->st_name
, (void *)new_value
));
499 got
[obj
->local_gotno
+ sym
- obj
->gotsym
] = new_value
;
507 _rtld_bind(Elf_Word a0
, Elf_Addr a1
, Elf_Addr a2
, Elf_Addr a3
)
509 Elf_Addr
*got
= (Elf_Addr
*)(a2
- 0x7ff0);
510 const Obj_Entry
*obj
= (Obj_Entry
*)(got
[1] & GOT1_MASK
);
511 Elf_Addr new_value
= 0; /* XXX gcc */
514 _rtld_shared_enter();
515 err
= _rtld_relocate_plt_object(obj
, a0
, &new_value
);
520 return (caddr_t
)new_value
;
524 _rtld_relocate_plt_objects(const Obj_Entry
*obj
)
526 const Elf_Sym
*sym
= obj
->symtab
+ obj
->gotsym
;
529 for (i
= obj
->gotsym
; i
< obj
->symtabno
; i
++, sym
++) {
530 if (ELF_ST_TYPE(sym
->st_info
) == STT_FUNC
)
531 if (_rtld_relocate_plt_object(obj
, i
, NULL
) < 0)