1 /* vi: set sw=4 ts=4: */
2 /* m68k ELF shared library loader suppport
4 * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
5 * David Engel, Hongjiu Lu and Mitch D'Souza
6 * Adapted to ELF/68k by Andreas Schwab.
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
32 /* Program to load an ELF binary on a linux system, and run it.
33 References to symbols in sharable libraries can be resolved by either
34 an ELF sharable library or a linux style of shared library. */
36 /* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
37 I ever taken any courses on internals. This program was developed using
38 information available through the book "UNIX SYSTEM V RELEASE 4,
39 Programmers guide: Ansi C and Programming Support Tools", which did
40 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
, tpnt
->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 int)new_addr
;
97 _dl_parse(struct elf_resolve
*tpnt
, struct dyn_elf
*scope
,
98 unsigned long rel_addr
, unsigned long rel_size
,
99 int (*reloc_fnc
)(struct elf_resolve
*tpnt
, struct dyn_elf
*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 dyn_elf
*scope
,
155 ELF_RELOC
*rpnt
, ElfW(Sym
) *symtab
, char *strtab
)
160 struct symbol_ref sym_ref
;
161 ElfW(Addr
) *reloc_addr
;
162 ElfW(Addr
) symbol_addr
;
163 #if defined (__SUPPORT_LD_DEBUG__)
167 reloc_addr
= (ElfW(Addr
)*)(tpnt
->loadaddr
+ (unsigned long)rpnt
->r_offset
);
168 reloc_type
= ELF_R_TYPE(rpnt
->r_info
);
169 symtab_index
= ELF_R_SYM(rpnt
->r_info
);
170 sym_ref
.sym
= &symtab
[symtab_index
];
173 symname
= strtab
+ sym_ref
.sym
->st_name
;
176 symbol_addr
= (ElfW(Addr
))_dl_find_hash(symname
, scope
, tpnt
,
177 elf_machine_type_class(reloc_type
), &sym_ref
);
179 * We want to allow undefined references to weak symbols - this
180 * might have been intentional. We should not be linking local
181 * symbols here, so all bases should be covered.
183 if (unlikely(!symbol_addr
&& ELF_ST_BIND(sym_ref
.sym
->st_info
) != STB_WEAK
)) {
184 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname
, symname
);
189 #if defined (__SUPPORT_LD_DEBUG__)
190 old_val
= *reloc_addr
;
193 switch (reloc_type
) {
197 *(char *) reloc_addr
= symbol_addr
+ rpnt
->r_addend
;
200 *(short *) reloc_addr
= symbol_addr
+ rpnt
->r_addend
;
203 *reloc_addr
= symbol_addr
+ rpnt
->r_addend
;
206 *(char *) reloc_addr
= (symbol_addr
+ rpnt
->r_addend
207 - (unsigned int) reloc_addr
);
210 *(short *) reloc_addr
= (symbol_addr
+ rpnt
->r_addend
211 - (unsigned int) reloc_addr
);
214 *reloc_addr
= (symbol_addr
+ rpnt
->r_addend
215 - (unsigned int) reloc_addr
);
219 *reloc_addr
= symbol_addr
+ rpnt
->r_addend
;
221 /* handled by elf_machine_relative()
223 *reloc_addr = ((unsigned int) tpnt->loadaddr
224 / * Compatibility kludge. * /
225 + (rpnt->r_addend ? : *reloc_addr));
230 #if defined (__SUPPORT_LD_DEBUG__)
232 _dl_dprintf(_dl_debug_file
,
233 "\t%s move %d bytes from %x to %x\n",
234 symname
, sym_ref
.sym
->st_size
,
235 symbol_addr
, reloc_addr
);
237 _dl_memcpy ((void *) reloc_addr
,
238 (void *) symbol_addr
,
239 sym_ref
.sym
->st_size
);
241 _dl_dprintf(_dl_debug_file
, "no symbol_addr to copy !?\n");
245 return -1; /* Calls _dl_exit(1). */
248 #if defined (__SUPPORT_LD_DEBUG__)
249 if (_dl_debug_reloc
&& _dl_debug_detail
)
250 _dl_dprintf(_dl_debug_file
, "\tpatched: %x ==> %x @ %x\n",
251 old_val
, *reloc_addr
, reloc_addr
);
257 #undef LAZY_RELOC_WORKS
258 #ifdef LAZY_RELOC_WORKS
260 _dl_do_lazy_reloc(struct elf_resolve
*tpnt
, struct dyn_elf
*scope
,
261 ELF_RELOC
*rpnt
, ElfW(Sym
) *symtab
, char *strtab
)
265 ElfW(Addr
) *reloc_addr
;
266 #if defined (__SUPPORT_LD_DEBUG__)
271 symtab_index
= ELF_R_SYM(rpnt
->r_info
);
274 reloc_addr
= (ElfW(Addr
)*)(tpnt
->loadaddr
+ rpnt
->r_offset
);
275 reloc_type
= ELF_R_TYPE(rpnt
->r_info
);
277 #if defined (__SUPPORT_LD_DEBUG__)
278 old_val
= *reloc_addr
;
281 switch (reloc_type
) {
285 *reloc_addr
+= (unsigned int) tpnt
->loadaddr
;
291 #if defined (__SUPPORT_LD_DEBUG__)
292 if (_dl_debug_reloc
&& _dl_debug_detail
)
293 _dl_dprintf(_dl_debug_file
, "\tpatched_lazy: %x ==> %x @ %x\n",
294 old_val
, *reloc_addr
, reloc_addr
);
302 _dl_parse_lazy_relocation_information(struct dyn_elf
*rpnt
,
303 unsigned long rel_addr
,
304 unsigned long rel_size
)
306 #ifdef LAZY_RELOC_WORKS
307 (void)_dl_parse(rpnt
->dyn
, NULL
, rel_addr
, rel_size
, _dl_do_lazy_reloc
);
309 _dl_parse_relocation_information(rpnt
, rel_addr
, rel_size
);
314 _dl_parse_relocation_information(struct dyn_elf
*rpnt
,
315 unsigned long rel_addr
,
316 unsigned long rel_size
)
318 return _dl_parse(rpnt
->dyn
, rpnt
->dyn
->symbol_scope
, rel_addr
, rel_size
, _dl_do_reloc
);