1 /* vi: set sw=4 ts=4: */
2 /* microblaze ELF shared library loader suppport
4 * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
5 * David Engel, Hongjiu Lu and Mitch D'Souza
6 * Copyright (C) 2001-2004 Erik Andersen
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. The name of the above contributors may not be
16 * used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 /* Program to load an ELF binary on a linux system, and run it.
35 References to symbols in sharable libraries can be resolved by either
36 an ELF sharable library or a linux style of shared library. */
38 /* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
39 I ever taken any courses on internals. This program was developed using
40 information available through the book "UNIX SYSTEM V RELEASE 4,
41 Programmers guide: Ansi C and Programming Support Tools", which did
42 a more than adequate job of explaining everything required to get this
45 extern int _dl_linux_resolve(void);
48 _dl_linux_resolver(struct elf_resolve
*tpnt
, int reloc_entry
)
50 ELF_RELOC
*this_reloc
;
57 ElfW(Addr
) instr_addr
;
60 rel_addr
= (char *)tpnt
->dynamic_info
[DT_JMPREL
];
61 this_reloc
= (ELF_RELOC
*)(rel_addr
+ reloc_entry
);
62 symtab_index
= ELF_R_SYM(this_reloc
->r_info
);
64 symtab
= (ElfW(Sym
) *)tpnt
->dynamic_info
[DT_SYMTAB
];
65 strtab
= (char *)tpnt
->dynamic_info
[DT_STRTAB
];
66 symname
= strtab
+ symtab
[symtab_index
].st_name
;
68 /* Address of the jump instruction to fix up. */
69 instr_addr
= (this_reloc
->r_offset
+ tpnt
->loadaddr
);
70 got_addr
= (char **)instr_addr
;
72 /* Get the address of the GOT entry. */
73 new_addr
= _dl_find_hash(symname
, &_dl_loaded_modules
->symbol_scope
, tpnt
, ELF_RTYPE_CLASS_PLT
, NULL
);
74 if (unlikely(!new_addr
)) {
75 _dl_dprintf(2, "%s: Can't resolve symbol '%s'\n", _dl_progname
, symname
);
79 #if defined (__SUPPORT_LD_DEBUG__)
80 if ((unsigned long)got_addr
< 0x40000000) {
81 if (_dl_debug_bindings
) {
82 _dl_dprintf(_dl_debug_file
, "\nresolve function: %s", symname
);
84 _dl_dprintf(_dl_debug_file
,
85 "\tpatched: %x ==> %x @ %x\n",
86 *got_addr
, new_addr
, got_addr
);
89 if (!_dl_debug_nofixups
)
93 return (unsigned long)new_addr
;
97 _dl_parse(struct elf_resolve
*tpnt
, struct r_scope_elem
*scope
,
98 unsigned long rel_addr
, unsigned long rel_size
,
99 int (*reloc_fnc
)(struct elf_resolve
*tpnt
, struct r_scope_elem
*scope
,
100 ELF_RELOC
*rpnt
, ElfW(Sym
) *symtab
, char *strtab
))
108 /* Parse the relocation information. */
109 rpnt
= (ELF_RELOC
*)rel_addr
;
110 rel_size
/= sizeof(ELF_RELOC
);
112 symtab
= (ElfW(Sym
) *)tpnt
->dynamic_info
[DT_SYMTAB
];
113 strtab
= (char *)tpnt
->dynamic_info
[DT_STRTAB
];
115 for (i
= 0; i
< rel_size
; i
++, rpnt
++) {
118 symtab_index
= ELF_R_SYM(rpnt
->r_info
);
120 debug_sym(symtab
, strtab
, symtab_index
);
121 debug_reloc(symtab
, strtab
, rpnt
);
123 res
= reloc_fnc(tpnt
, scope
, rpnt
, symtab
, strtab
);
128 _dl_dprintf(2, "\n%s: ", _dl_progname
);
131 _dl_dprintf(2, "symbol '%s': ",
132 strtab
+ symtab
[symtab_index
].st_name
);
134 if (unlikely(res
< 0)) {
135 int reloc_type
= ELF_R_TYPE(rpnt
->r_info
);
137 _dl_dprintf(2, "can't handle reloc type "
138 #if defined (__SUPPORT_LD_DEBUG__)
139 "%s\n", _dl_reltypes(reloc_type
));
144 } else if (unlikely(res
> 0)) {
145 _dl_dprintf(2, "can't resolve symbol\n");
154 _dl_do_reloc(struct elf_resolve
*tpnt
, struct r_scope_elem
*scope
,
155 ELF_RELOC
*rpnt
, ElfW(Sym
) *symtab
, char *strtab
)
160 #if defined USE_TLS && USE_TLS
161 struct elf_resolve
*tls_tpnt
;
163 struct symbol_ref sym_ref
;
164 ElfW(Addr
) *reloc_addr
;
165 ElfW(Addr
) symbol_addr
;
166 #if defined (__SUPPORT_LD_DEBUG__)
170 reloc_addr
= (ElfW(Addr
)*)(tpnt
->loadaddr
+ (unsigned long)rpnt
->r_offset
);
171 reloc_type
= ELF_R_TYPE(rpnt
->r_info
);
172 symtab_index
= ELF_R_SYM(rpnt
->r_info
);
173 sym_ref
.sym
= &symtab
[symtab_index
];
176 symname
= strtab
+ sym_ref
.sym
->st_name
;
179 symbol_addr
= (ElfW(Addr
))_dl_find_hash(symname
, scope
, tpnt
,
180 elf_machine_type_class(reloc_type
), &sym_ref
);
182 * We want to allow undefined references to weak symbols - this
183 * might have been intentional. We should not be linking local
184 * symbols here, so all bases should be covered.
186 if (unlikely(!symbol_addr
&& (ELF_ST_TYPE(sym_ref
.sym
->st_info
) != STT_TLS
)
187 && (ELF_ST_BIND(sym_ref
.sym
->st_info
) != STB_WEAK
))) {
188 /* This may be non-fatal if called from dlopen. */
191 #if defined USE_TLS && USE_TLS
192 tls_tpnt
= sym_ref
.tpnt
;
195 /* Relocs against STN_UNDEF are usually treated as using a
196 * symbol value of zero, and using the module containing the
198 symbol_addr
= sym_ref
.sym
->st_value
;
199 #if defined USE_TLS && USE_TLS
205 #if defined (__SUPPORT_LD_DEBUG__)
207 old_val
= *reloc_addr
;
213 switch (reloc_type
) {
214 case R_MICROBLAZE_NONE
:
215 case R_MICROBLAZE_64_NONE
:
217 case R_MICROBLAZE_64
:
218 *reloc_addr
= symbol_addr
+ rpnt
->r_addend
;
220 case R_MICROBLAZE_32
:
221 case R_MICROBLAZE_32_LO
:
222 *reloc_addr
= symbol_addr
+ rpnt
->r_addend
;
224 case R_MICROBLAZE_32_PCREL
:
225 case R_MICROBLAZE_32_PCREL_LO
:
226 case R_MICROBLAZE_64_PCREL
:
227 case R_MICROBLAZE_SRO32
:
228 case R_MICROBLAZE_SRW32
:
229 *reloc_addr
= symbol_addr
+ rpnt
->r_addend
;
231 case R_MICROBLAZE_GLOB_DAT
:
232 case R_MICROBLAZE_JUMP_SLOT
:
233 *reloc_addr
= symbol_addr
+ rpnt
->r_addend
;
235 case R_MICROBLAZE_REL
:
236 *reloc_addr
= (unsigned long)tpnt
->loadaddr
+ rpnt
->r_addend
;
238 #if defined USE_TLS && USE_TLS
239 case R_MICROBLAZE_TLSDTPMOD32
:
240 *reloc_addr
= tls_tpnt
->l_tls_modid
;
242 case R_MICROBLAZE_TLSDTPREL32
:
243 *reloc_addr
= symbol_addr
;
245 case R_MICROBLAZE_TLSTPREL32
:
246 CHECK_STATIC_TLS ((struct link_map
*) tls_tpnt
);
247 *reloc_addr
= tls_tpnt
->l_tls_offset
+ symbol_addr
+ rpnt
->r_addend
;
250 case R_MICROBLAZE_COPY
:
252 #if defined (__SUPPORT_LD_DEBUG__)
254 _dl_dprintf(_dl_debug_file
,
255 "\t%s move %d bytes from %x to %x\n",
256 symname
, sym_ref
.sym
->st_size
,
257 symbol_addr
, reloc_addr
);
259 _dl_memcpy((char *)reloc_addr
,
261 sym_ref
.sym
->st_size
);
263 #if defined (__SUPPORT_LD_DEBUG__)
265 _dl_dprintf(_dl_debug_file
, "no symbol_addr to copy !?\n");
269 return -1; /* Calls _dl_exit(1). */
272 #if defined (__SUPPORT_LD_DEBUG__)
273 if (_dl_debug_reloc
&& _dl_debug_detail
)
274 _dl_dprintf(_dl_debug_file
, "\tpatched: %x ==> %x @ %x\n",
275 old_val
, *reloc_addr
, reloc_addr
);
282 _dl_do_lazy_reloc(struct elf_resolve
*tpnt
, struct r_scope_elem
*scope
,
283 ELF_RELOC
*rpnt
, ElfW(Sym
) *symtab
, char *strtab
)
286 ElfW(Addr
) *reloc_addr
;
287 #if defined (__SUPPORT_LD_DEBUG__)
294 reloc_addr
= (ElfW(Addr
)*)(tpnt
->loadaddr
+ rpnt
->r_offset
);
295 reloc_type
= ELF_R_TYPE(rpnt
->r_info
);
297 #if defined (__SUPPORT_LD_DEBUG__)
298 old_val
= *reloc_addr
;
301 switch (reloc_type
) {
302 case R_MICROBLAZE_NONE
:
304 case R_MICROBLAZE_JUMP_SLOT
:
305 *reloc_addr
+= (unsigned long)tpnt
->loadaddr
;
311 #if defined (__SUPPORT_LD_DEBUG__)
312 if (_dl_debug_reloc
&& _dl_debug_detail
)
313 _dl_dprintf(_dl_debug_file
, "\tpatched_lazy: %x ==> %x @ %x\n",
314 old_val
, *reloc_addr
, reloc_addr
);
321 _dl_parse_lazy_relocation_information(struct dyn_elf
*rpnt
,
322 unsigned long rel_addr
, unsigned long rel_size
)
324 (void)_dl_parse(rpnt
->dyn
, NULL
, rel_addr
, rel_size
, _dl_do_lazy_reloc
);
328 _dl_parse_relocation_information(struct dyn_elf
*rpnt
,
329 struct r_scope_elem
*scope
, unsigned long rel_addr
, unsigned long rel_size
)
331 return _dl_parse(rpnt
->dyn
, scope
, rel_addr
, rel_size
, _dl_do_reloc
);