1 /* $NetBSD: mips_reloc.c,v 1.60 2010/09/24 15:20:52 matt 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.60 2010/09/24 15:20:52 matt Exp $");
36 #include <sys/types.h>
37 #include <sys/endian.h>
46 #define SUPPORT_OLD_BROKEN_LD
49 void _rtld_bind_start(void);
50 void _rtld_relocate_nonplt_self(Elf_Dyn
*, Elf_Addr
);
51 caddr_t
_rtld_bind(Elf_Word
, Elf_Addr
, Elf_Addr
, Elf_Addr
);
54 * It is possible for the compiler to emit relocations for unaligned data.
55 * We handle this situation with these inlines.
60 * ELF64 MIPS encodes the relocs uniquely. The first 32-bits of info contain
61 * the symbol index. The top 32-bits contain three relocation types encoded
62 * in big-endian integer with first relocation in LSB. This means for little
63 * endian we have to byte swap that interger (r_type).
65 #define Elf_Sxword Elf64_Sxword
66 #define ELF_R_NXTTYPE_64_P(r_type) ((((r_type) >> 8) & 0xff) == R_TYPE(64))
67 #if BYTE_ORDER == LITTLE_ENDIAN
70 #define ELF_R_SYM(r_info) ((r_info) & 0xffffffff)
71 #define ELF_R_TYPE(r_info) bswap32((r_info) >> 32)
74 #define ELF_R_NXTTYPE_64_P(r_type) (0)
75 #define Elf_Sxword Elf32_Sword
77 #define GOT1_MASK (~(Elf_Addr)0 >> 1)
79 static inline Elf_Sxword
80 load_ptr(void *where
, size_t len
)
84 if (__predict_true(((uintptr_t)where
& (len
- 1)) == 0)) {
86 if (len
== sizeof(Elf_Sxword
))
87 return *(Elf_Sxword
*)where
;
89 return *(Elf_Sword
*)where
;
93 #if BYTE_ORDER == LITTLE_ENDIAN
94 (void)memcpy(&val
, where
, len
);
96 #if BYTE_ORDER == BIG_ENDIAN
97 (void)memcpy((uint8_t *)((&val
)+1) - len
, where
, len
);
99 return (len
== sizeof(Elf_Sxword
)) ? val
: (Elf_Sword
)val
;
103 store_ptr(void *where
, Elf_Sxword val
, size_t len
)
105 if (__predict_true(((uintptr_t)where
& (len
- 1)) == 0)) {
107 if (len
== sizeof(Elf_Sxword
)) {
108 *(Elf_Sxword
*)where
= val
;
112 *(Elf_Sword
*)where
= val
;
115 #if BYTE_ORDER == LITTLE_ENDIAN
116 (void)memcpy(where
, &val
, len
);
118 #if BYTE_ORDER == BIG_ENDIAN
119 (void)memcpy(where
, (const uint8_t *)((&val
)+1) - len
, len
);
125 _rtld_setup_pltgot(const Obj_Entry
*obj
)
127 obj
->pltgot
[0] = (Elf_Addr
) &_rtld_bind_start
;
128 /* XXX only if obj->pltgot[1] & 0x80000000 ?? */
129 obj
->pltgot
[1] |= (Elf_Addr
) obj
;
133 _rtld_relocate_nonplt_self(Elf_Dyn
*dynp
, Elf_Addr relocbase
)
135 const Elf_Rel
*rel
= 0, *rellim
;
138 const Elf_Sym
*symtab
= NULL
, *sym
;
139 Elf_Addr
*got
= NULL
;
140 Elf_Word local_gotno
= 0, symtabno
= 0, gotsym
= 0;
143 for (; dynp
->d_tag
!= DT_NULL
; dynp
++) {
144 switch (dynp
->d_tag
) {
146 rel
= (const Elf_Rel
*)(relocbase
+ dynp
->d_un
.d_ptr
);
149 relsz
= dynp
->d_un
.d_val
;
152 symtab
= (const Elf_Sym
*)(relocbase
+ dynp
->d_un
.d_ptr
);
155 got
= (Elf_Addr
*)(relocbase
+ dynp
->d_un
.d_ptr
);
157 case DT_MIPS_LOCAL_GOTNO
:
158 local_gotno
= dynp
->d_un
.d_val
;
160 case DT_MIPS_SYMTABNO
:
161 symtabno
= dynp
->d_un
.d_val
;
164 gotsym
= dynp
->d_un
.d_val
;
169 i
= (got
[1] & 0x80000000) ? 2 : 1;
170 /* Relocate the local GOT entries */
172 for (; i
< local_gotno
; i
++)
174 sym
= symtab
+ gotsym
;
175 /* Now do the global GOT entries */
176 for (i
= gotsym
; i
< symtabno
; i
++) {
177 *got
= sym
->st_value
+ relocbase
;
182 rellim
= (const Elf_Rel
*)((uintptr_t)rel
+ relsz
);
183 for (; rel
< rellim
; rel
++) {
184 Elf_Word r_symndx
, r_type
;
186 where
= (void *)(relocbase
+ rel
->r_offset
);
188 r_symndx
= ELF_R_SYM(rel
->r_info
);
189 r_type
= ELF_R_TYPE(rel
->r_info
);
191 switch (r_type
& 0xff) {
192 case R_TYPE(REL32
): {
194 ELF_R_NXTTYPE_64_P(r_type
)
197 Elf_Sxword old
= load_ptr(where
, rlen
);
198 Elf_Sxword val
= old
;
200 assert(r_type
== R_TYPE(REL32
)
201 || r_type
== (R_TYPE(REL32
)|(R_TYPE(64) << 8)));
203 assert(r_symndx
< gotsym
);
204 sym
= symtab
+ r_symndx
;
205 assert(ELF_ST_BIND(sym
->st_info
) == STB_LOCAL
);
207 store_ptr(where
, val
, sizeof(Elf_Sword
));
208 rdbg(("REL32/L(%p) %p -> %p in <self>",
209 where
, (void *)old
, (void *)val
));
210 store_ptr(where
, val
, rlen
);
214 case R_TYPE(GPREL32
):
226 _rtld_relocate_nonplt_objects(Obj_Entry
*obj
)
229 Elf_Addr
*got
= obj
->pltgot
;
230 const Elf_Sym
*sym
, *def
;
231 const Obj_Entry
*defobj
;
233 #ifdef SUPPORT_OLD_BROKEN_LD
237 #ifdef SUPPORT_OLD_BROKEN_LD
240 for (i
= 1; i
< 12; i
++)
241 if (sym
[i
].st_info
== ELF_ST_INFO(STB_LOCAL
, STT_NOTYPE
))
243 dbg(("%s: broken=%d", obj
->path
, broken
));
246 i
= (got
[1] & 0x80000000) ? 2 : 1;
247 /* Relocate the local GOT entries */
249 for (; i
< obj
->local_gotno
; i
++)
250 *got
++ += (Elf_Addr
)obj
->relocbase
;
251 sym
= obj
->symtab
+ obj
->gotsym
;
252 /* Now do the global GOT entries */
253 for (i
= obj
->gotsym
; i
< obj
->symtabno
; i
++) {
254 rdbg((" doing got %d sym %p (%s, %lx)", i
- obj
->gotsym
, sym
,
255 sym
->st_name
+ obj
->strtab
, (u_long
) *got
));
257 #ifdef SUPPORT_OLD_BROKEN_LD
258 if (ELF_ST_TYPE(sym
->st_info
) == STT_FUNC
&&
259 broken
&& sym
->st_shndx
== SHN_UNDEF
) {
261 * XXX DANGER WILL ROBINSON!
262 * You might think this is stupid, as it intentionally
263 * defeats lazy binding -- and you'd be right.
264 * Unfortunately, for lazy binding to work right, we
265 * need to a way to force the GOT slots used for
266 * function pointers to be resolved immediately. This
267 * is supposed to be done automatically by the linker,
268 * by not outputting a PLT slot and setting st_value
269 * to 0 if there are non-PLT references, but older
270 * versions of GNU ld do not do this.
272 def
= _rtld_find_symdef(i
, obj
, &defobj
, false);
275 *got
= def
->st_value
+ (Elf_Addr
)defobj
->relocbase
;
278 if (ELF_ST_TYPE(sym
->st_info
) == STT_FUNC
&&
279 sym
->st_value
!= 0 && sym
->st_shndx
== SHN_UNDEF
) {
281 * If there are non-PLT references to the function,
282 * st_value should be 0, forcing us to resolve the
283 * address immediately.
285 * XXX DANGER WILL ROBINSON!
286 * The linker is not outputting PLT slots for calls to
287 * functions that are defined in the same shared
288 * library. This is a bug, because it can screw up
289 * link ordering rules if the symbol is defined in
290 * more than one module. For now, if there is a
291 * definition, we fail the test above and force a full
292 * symbol lookup. This means that all intra-module
293 * calls are bound immediately. - mycroft, 2003/09/24
295 *got
= sym
->st_value
+ (Elf_Addr
)obj
->relocbase
;
296 } else if (sym
->st_info
== ELF_ST_INFO(STB_GLOBAL
, STT_SECTION
)) {
297 /* Symbols with index SHN_ABS are not relocated. */
298 if (sym
->st_shndx
!= SHN_ABS
)
299 *got
= sym
->st_value
+
300 (Elf_Addr
)obj
->relocbase
;
302 def
= _rtld_find_symdef(i
, obj
, &defobj
, false);
305 *got
= def
->st_value
+ (Elf_Addr
)defobj
->relocbase
;
308 rdbg((" --> now %lx", (u_long
) *got
));
314 for (rel
= obj
->rel
; rel
< obj
->rellim
; rel
++) {
315 Elf_Word r_symndx
, r_type
;
318 where
= obj
->relocbase
+ rel
->r_offset
;
319 r_symndx
= ELF_R_SYM(rel
->r_info
);
320 r_type
= ELF_R_TYPE(rel
->r_info
);
322 switch (r_type
& 0xff) {
326 case R_TYPE(REL32
): {
327 /* 32-bit PC-relative reference */
329 ELF_R_NXTTYPE_64_P(r_type
)
332 Elf_Sxword old
= load_ptr(where
, rlen
);
333 Elf_Sxword val
= old
;
335 def
= obj
->symtab
+ r_symndx
;
337 if (r_symndx
>= obj
->gotsym
) {
338 val
+= got
[obj
->local_gotno
+ r_symndx
- obj
->gotsym
];
339 rdbg(("REL32/G(%p) %p --> %p (%s) in %s",
340 where
, (void *)old
, (void *)val
,
341 obj
->strtab
+ def
->st_name
,
345 * XXX: ABI DIFFERENCE!
347 * Old NetBSD binutils would generate shared
348 * libs with section-relative relocations being
349 * already adjusted for the start address of
352 * New binutils, OTOH, generate shared libs
353 * with the same relocations being based at
354 * zero, so we need to add in the start address
361 ELF_ST_INFO(STB_LOCAL
, STT_SECTION
)
362 #ifdef SUPPORT_OLD_BROKEN_LD
366 val
+= (Elf_Addr
)def
->st_value
;
368 val
+= (Elf_Addr
)obj
->relocbase
;
370 rdbg(("REL32/L(%p) %p -> %p (%s) in %s",
371 where
, (void *)old
, (void *)val
,
372 obj
->strtab
+ def
->st_name
, obj
->path
));
374 store_ptr(where
, val
, rlen
);
379 rdbg(("sym = %lu, type = %lu, offset = %p, "
380 "contents = %p, symbol = %s",
381 (u_long
)r_symndx
, (u_long
)ELF_R_TYPE(rel
->r_info
),
382 (void *)rel
->r_offset
,
383 (void *)load_ptr(where
, sizeof(Elf_Sword
)),
384 obj
->strtab
+ obj
->symtab
[r_symndx
].st_name
));
385 _rtld_error("%s: Unsupported relocation type %ld "
386 "in non-PLT relocations",
387 obj
->path
, (u_long
) ELF_R_TYPE(rel
->r_info
));
396 _rtld_relocate_plt_lazy(const Obj_Entry
*obj
)
398 /* PLT fixups were done above in the GOT relocation. */
403 _rtld_relocate_plt_object(const Obj_Entry
*obj
, Elf_Word sym
, Elf_Addr
*tp
)
405 Elf_Addr
*got
= obj
->pltgot
;
407 const Obj_Entry
*defobj
;
410 def
= _rtld_find_plt_symdef(sym
, obj
, &defobj
, tp
!= NULL
);
411 if (__predict_false(def
== NULL
))
413 if (__predict_false(def
== &_rtld_sym_zero
))
416 new_value
= (Elf_Addr
)(defobj
->relocbase
+ def
->st_value
);
417 rdbg(("bind now/fixup in %s --> new=%p",
418 defobj
->strtab
+ def
->st_name
, (void *)new_value
));
419 got
[obj
->local_gotno
+ sym
- obj
->gotsym
] = new_value
;
427 _rtld_bind(Elf_Word a0
, Elf_Addr a1
, Elf_Addr a2
, Elf_Addr a3
)
429 Elf_Addr
*got
= (Elf_Addr
*)(a2
- 0x7ff0);
430 const Obj_Entry
*obj
= (Obj_Entry
*)(got
[1] & GOT1_MASK
);
431 Elf_Addr new_value
= 0; /* XXX gcc */
434 err
= _rtld_relocate_plt_object(obj
, a0
, &new_value
);
438 return (caddr_t
)new_value
;
442 _rtld_relocate_plt_objects(const Obj_Entry
*obj
)
444 const Elf_Sym
*sym
= obj
->symtab
+ obj
->gotsym
;
447 for (i
= obj
->gotsym
; i
< obj
->symtabno
; i
++, sym
++) {
448 if (ELF_ST_TYPE(sym
->st_info
) == STT_FUNC
)
449 if (_rtld_relocate_plt_object(obj
, i
, NULL
) < 0)