1 /* microblaze ELF shared library loader suppport
3 * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
4 * David Engel, Hongjiu Lu and Mitch D'Souza
5 * Copyright (C) 2001-2004 Erik Andersen
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. The name of the above contributors may not be
15 * used to endorse or promote products derived from this software
16 * without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 /* Program to load an ELF binary on a linux system, and run it.
34 References to symbols in sharable libraries can be resolved by either
35 an ELF sharable library or a linux style of shared library. */
37 extern int _dl_linux_resolve(void);
40 _dl_linux_resolver(struct elf_resolve
*tpnt
, int reloc_entry
)
42 ELF_RELOC
*this_reloc
;
49 ElfW(Addr
) instr_addr
;
52 rel_addr
= (char *)tpnt
->dynamic_info
[DT_JMPREL
];
53 this_reloc
= (ELF_RELOC
*)(rel_addr
+ reloc_entry
);
54 symtab_index
= ELF_R_SYM(this_reloc
->r_info
);
56 symtab
= (ElfW(Sym
) *)tpnt
->dynamic_info
[DT_SYMTAB
];
57 strtab
= (char *)tpnt
->dynamic_info
[DT_STRTAB
];
58 symname
= strtab
+ symtab
[symtab_index
].st_name
;
60 /* Address of the jump instruction to fix up. */
61 instr_addr
= (this_reloc
->r_offset
+ tpnt
->loadaddr
);
62 got_addr
= (char **)instr_addr
;
64 /* Get the address of the GOT entry. */
65 new_addr
= _dl_find_hash(symname
, &_dl_loaded_modules
->symbol_scope
, tpnt
, ELF_RTYPE_CLASS_PLT
, NULL
);
66 if (unlikely(!new_addr
)) {
67 _dl_dprintf(2, "%s: Can't resolve symbol '%s'\n", _dl_progname
, symname
);
71 #if defined (__SUPPORT_LD_DEBUG__)
72 if ((unsigned long)got_addr
< 0x40000000) {
73 if (_dl_debug_bindings
) {
74 _dl_dprintf(_dl_debug_file
, "\nresolve function: %s", symname
);
76 _dl_dprintf(_dl_debug_file
,
77 "\tpatched: %x ==> %x @ %x\n",
78 *got_addr
, new_addr
, got_addr
);
81 if (!_dl_debug_nofixups
)
85 return (unsigned long)new_addr
;
89 _dl_parse(struct elf_resolve
*tpnt
, struct r_scope_elem
*scope
,
90 unsigned long rel_addr
, unsigned long rel_size
,
91 int (*reloc_fnc
)(struct elf_resolve
*tpnt
, struct r_scope_elem
*scope
,
92 ELF_RELOC
*rpnt
, ElfW(Sym
) *symtab
, char *strtab
))
100 /* Parse the relocation information. */
101 rpnt
= (ELF_RELOC
*)rel_addr
;
102 rel_size
/= sizeof(ELF_RELOC
);
104 symtab
= (ElfW(Sym
) *)tpnt
->dynamic_info
[DT_SYMTAB
];
105 strtab
= (char *)tpnt
->dynamic_info
[DT_STRTAB
];
107 for (i
= 0; i
< rel_size
; i
++, rpnt
++) {
110 symtab_index
= ELF_R_SYM(rpnt
->r_info
);
112 debug_sym(symtab
, strtab
, symtab_index
);
113 debug_reloc(symtab
, strtab
, rpnt
);
115 res
= reloc_fnc(tpnt
, scope
, rpnt
, symtab
, strtab
);
120 _dl_dprintf(2, "\n%s: ", _dl_progname
);
123 _dl_dprintf(2, "symbol '%s': ",
124 strtab
+ symtab
[symtab_index
].st_name
);
126 if (unlikely(res
< 0)) {
127 int reloc_type
= ELF_R_TYPE(rpnt
->r_info
);
128 _dl_dprintf(2, "can't handle reloc type "
131 } else if (unlikely(res
> 0)) {
132 _dl_dprintf(2, "can't resolve symbol\n");
141 _dl_do_reloc(struct elf_resolve
*tpnt
, struct r_scope_elem
*scope
,
142 ELF_RELOC
*rpnt
, ElfW(Sym
) *symtab
, char *strtab
)
147 #if defined USE_TLS && USE_TLS
148 struct elf_resolve
*tls_tpnt
;
150 struct symbol_ref sym_ref
;
151 ElfW(Addr
) *reloc_addr
;
152 ElfW(Addr
) symbol_addr
;
153 #if defined (__SUPPORT_LD_DEBUG__)
157 reloc_addr
= (ElfW(Addr
)*)(tpnt
->loadaddr
+ (unsigned long)rpnt
->r_offset
);
158 reloc_type
= ELF_R_TYPE(rpnt
->r_info
);
159 symtab_index
= ELF_R_SYM(rpnt
->r_info
);
160 sym_ref
.sym
= &symtab
[symtab_index
];
163 symname
= strtab
+ sym_ref
.sym
->st_name
;
166 symbol_addr
= (ElfW(Addr
))_dl_find_hash(symname
, scope
, tpnt
,
167 elf_machine_type_class(reloc_type
), &sym_ref
);
169 * We want to allow undefined references to weak symbols - this
170 * might have been intentional. We should not be linking local
171 * symbols here, so all bases should be covered.
173 if (unlikely(!symbol_addr
&& (ELF_ST_TYPE(sym_ref
.sym
->st_info
) != STT_TLS
)
174 && (ELF_ST_BIND(sym_ref
.sym
->st_info
) != STB_WEAK
))) {
175 /* This may be non-fatal if called from dlopen. */
178 #if defined USE_TLS && USE_TLS
179 tls_tpnt
= sym_ref
.tpnt
;
182 /* Relocs against STN_UNDEF are usually treated as using a
183 * symbol value of zero, and using the module containing the
185 symbol_addr
= sym_ref
.sym
->st_value
;
186 #if defined USE_TLS && USE_TLS
192 #if defined (__SUPPORT_LD_DEBUG__)
194 old_val
= *reloc_addr
;
200 switch (reloc_type
) {
201 case R_MICROBLAZE_NONE
:
202 case R_MICROBLAZE_64_NONE
:
204 case R_MICROBLAZE_64
:
205 *reloc_addr
= symbol_addr
+ rpnt
->r_addend
;
207 case R_MICROBLAZE_32
:
208 case R_MICROBLAZE_32_LO
:
209 *reloc_addr
= symbol_addr
+ rpnt
->r_addend
;
211 case R_MICROBLAZE_32_PCREL
:
212 case R_MICROBLAZE_32_PCREL_LO
:
213 case R_MICROBLAZE_64_PCREL
:
214 case R_MICROBLAZE_SRO32
:
215 case R_MICROBLAZE_SRW32
:
216 *reloc_addr
= symbol_addr
+ rpnt
->r_addend
;
218 case R_MICROBLAZE_GLOB_DAT
:
219 case R_MICROBLAZE_JUMP_SLOT
:
220 *reloc_addr
= symbol_addr
+ rpnt
->r_addend
;
222 case R_MICROBLAZE_REL
:
223 *reloc_addr
= (unsigned long)tpnt
->loadaddr
+ rpnt
->r_addend
;
225 #if defined USE_TLS && USE_TLS
226 case R_MICROBLAZE_TLSDTPMOD32
:
227 *reloc_addr
= tls_tpnt
->l_tls_modid
;
229 case R_MICROBLAZE_TLSDTPREL32
:
230 *reloc_addr
= symbol_addr
;
232 case R_MICROBLAZE_TLSTPREL32
:
233 CHECK_STATIC_TLS ((struct link_map
*) tls_tpnt
);
234 *reloc_addr
= tls_tpnt
->l_tls_offset
+ symbol_addr
+ rpnt
->r_addend
;
237 case R_MICROBLAZE_COPY
:
239 #if defined (__SUPPORT_LD_DEBUG__)
241 _dl_dprintf(_dl_debug_file
,
242 "\t%s move %d bytes from %x to %x\n",
243 symname
, sym_ref
.sym
->st_size
,
244 symbol_addr
, reloc_addr
);
246 _dl_memcpy((char *)reloc_addr
,
248 sym_ref
.sym
->st_size
);
250 #if defined (__SUPPORT_LD_DEBUG__)
252 _dl_dprintf(_dl_debug_file
, "no symbol_addr to copy !?\n");
256 return -1; /* Calls _dl_exit(1). */
259 #if defined (__SUPPORT_LD_DEBUG__)
260 if (_dl_debug_reloc
&& _dl_debug_detail
)
261 _dl_dprintf(_dl_debug_file
, "\tpatched: %x ==> %x @ %x\n",
262 old_val
, *reloc_addr
, reloc_addr
);
269 _dl_do_lazy_reloc(struct elf_resolve
*tpnt
, struct r_scope_elem
*scope
,
270 ELF_RELOC
*rpnt
, ElfW(Sym
) *symtab
, char *strtab
)
273 ElfW(Addr
) *reloc_addr
;
274 #if defined (__SUPPORT_LD_DEBUG__)
281 reloc_addr
= (ElfW(Addr
)*)(tpnt
->loadaddr
+ rpnt
->r_offset
);
282 reloc_type
= ELF_R_TYPE(rpnt
->r_info
);
284 #if defined (__SUPPORT_LD_DEBUG__)
285 old_val
= *reloc_addr
;
288 switch (reloc_type
) {
289 case R_MICROBLAZE_NONE
:
291 case R_MICROBLAZE_JUMP_SLOT
:
292 *reloc_addr
+= (unsigned long)tpnt
->loadaddr
;
298 #if defined (__SUPPORT_LD_DEBUG__)
299 if (_dl_debug_reloc
&& _dl_debug_detail
)
300 _dl_dprintf(_dl_debug_file
, "\tpatched_lazy: %x ==> %x @ %x\n",
301 old_val
, *reloc_addr
, reloc_addr
);
308 _dl_parse_lazy_relocation_information(struct dyn_elf
*rpnt
,
309 unsigned long rel_addr
, unsigned long rel_size
)
311 (void)_dl_parse(rpnt
->dyn
, NULL
, rel_addr
, rel_size
, _dl_do_lazy_reloc
);
315 _dl_parse_relocation_information(struct dyn_elf
*rpnt
,
316 struct r_scope_elem
*scope
, unsigned long rel_addr
, unsigned long rel_size
)
318 return _dl_parse(rpnt
->dyn
, scope
, rel_addr
, rel_size
, _dl_do_reloc
);