1 /* vi: set sw=4 ts=4: */
2 /* i386 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 #if defined (__SUPPORT_LD_DEBUG__)
35 static const char *_dl_reltypes_tab[] =
37 [0] "R_386_NONE", "R_386_32", "R_386_PC32", "R_386_GOT32",
38 [4] "R_386_PLT32", "R_386_COPY", "R_386_GLOB_DAT", "R_386_JMP_SLOT",
39 [8] "R_386_RELATIVE", "R_386_GOTOFF", "R_386_GOTPC",
43 _dl_reltypes(int type)
48 if (type >= (int)(sizeof (_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) ||
49 NULL == (str = _dl_reltypes_tab[type]))
51 str =_dl_simple_ltoa( buf, (unsigned long)(type));
57 void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
62 _dl_dprintf(_dl_debug_file, "\n%s\n\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",
63 strtab + symtab[symtab_index].st_name,
64 symtab[symtab_index].st_value,
65 symtab[symtab_index].st_size,
66 symtab[symtab_index].st_info,
67 symtab[symtab_index].st_other,
68 symtab[symtab_index].st_shndx);
73 static void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt)
79 symtab_index = ELF32_R_SYM(rpnt->r_info);
80 sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0";
83 _dl_dprintf(_dl_debug_file, "\n\t");
85 _dl_dprintf(_dl_debug_file, "\n%s\n\t", sym);
86 #ifdef ELF_USES_RELOCA
87 _dl_dprintf(_dl_debug_file, "%s\toffset=%x\taddend=%x",
88 _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
92 _dl_dprintf(_dl_debug_file, "%s\toffset=%x\n",
93 _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
100 /* Program to load an ELF binary on a linux system, and run it.
101 References to symbols in sharable libraries can be resolved by either
102 an ELF sharable library or a linux style of shared library. */
104 /* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
105 I ever taken any courses on internals. This program was developed using
106 information available through the book "UNIX SYSTEM V RELEASE 4,
107 Programmers guide: Ansi C and Programming Support Tools", which did
108 a more than adequate job of explaining everything required to get this
111 extern int _dl_linux_resolve(void);
113 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
116 ELF_RELOC *this_reloc;
123 unsigned long instr_addr;
126 rel_addr = (char *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
128 this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
129 reloc_type = ELF32_R_TYPE(this_reloc->r_info);
130 symtab_index = ELF32_R_SYM(this_reloc->r_info);
132 symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
133 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
134 symname= strtab + symtab[symtab_index].st_name;
136 if (reloc_type != R_386_JMP_SLOT) {
137 _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n",
142 /* Address of jump instruction to fix up */
143 instr_addr = ((unsigned long) this_reloc->r_offset +
144 (unsigned long) tpnt->loadaddr);
145 got_addr = (char **) instr_addr;
147 /* Get the address of the GOT entry */
148 new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, resolver);
150 new_addr = _dl_find_hash(symname, NULL, NULL, resolver);
152 return (unsigned long) new_addr;
154 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
158 #if defined (__SUPPORT_LD_DEBUG__)
159 if ((unsigned long) got_addr < 0x40000000)
161 if (_dl_debug_bindings)
163 _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
164 if(_dl_debug_detail) _dl_dprintf(_dl_debug_file,
165 "\n\tpatched %x ==> %x @ %x\n", *got_addr, new_addr, got_addr);
168 if (!_dl_debug_nofixups) {
169 *got_addr = new_addr;
172 *got_addr = new_addr;
175 return (unsigned long) new_addr;
179 _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
180 unsigned long rel_addr, unsigned long rel_size,
181 int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
182 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
190 /* Now parse the relocation information */
191 rpnt = (ELF_RELOC *)(intptr_t) (rel_addr + tpnt->loadaddr);
192 rel_size = rel_size / sizeof(ELF_RELOC);
194 symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
195 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
197 for (i = 0; i < rel_size; i++, rpnt++) {
200 symtab_index = ELF32_R_SYM(rpnt->r_info);
202 /* When the dynamic linker bootstrapped itself, it resolved some symbols.
203 Make sure we do not do them again */
204 if (!symtab_index && tpnt->libtype == program_interpreter)
206 if (symtab_index && tpnt->libtype == program_interpreter &&
207 _dl_symbol(strtab + symtab[symtab_index].st_name))
210 #if defined (__SUPPORT_LD_DEBUG__)
211 debug_sym(symtab,strtab,symtab_index);
212 debug_reloc(symtab,strtab,rpnt);
215 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
217 if (res==0) continue;
219 _dl_dprintf(2, "\n%s: ",_dl_progname);
222 _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
226 int reloc_type = ELF32_R_TYPE(rpnt->r_info);
227 #if defined (__SUPPORT_LD_DEBUG__)
228 _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
230 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
236 _dl_dprintf(2, "can't resolve symbol\n");
245 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
246 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
251 unsigned long *reloc_addr;
252 unsigned long symbol_addr;
253 #if defined (__SUPPORT_LD_DEBUG__)
254 unsigned long old_val;
257 reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
258 reloc_type = ELF32_R_TYPE(rpnt->r_info);
259 symtab_index = ELF32_R_SYM(rpnt->r_info);
261 symname = strtab + symtab[symtab_index].st_name;
265 symbol_addr = (unsigned long) _dl_find_hash(symname, scope,
266 (reloc_type == R_386_JMP_SLOT ? tpnt : NULL), symbolrel);
269 * We want to allow undefined references to weak symbols - this might
270 * have been intentional. We should not be linking local symbols
271 * here, so all bases should be covered.
274 if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
275 #if defined (__SUPPORT_LD_DEBUG__)
276 _dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s', rel type: %s\n",
277 symname, tpnt->libname, _dl_reltypes(reloc_type));
283 #if defined (__SUPPORT_LD_DEBUG__)
284 old_val = *reloc_addr;
286 switch (reloc_type) {
290 *reloc_addr += symbol_addr;
293 *reloc_addr += symbol_addr - (unsigned long) reloc_addr;
297 *reloc_addr = symbol_addr;
300 *reloc_addr += (unsigned long) tpnt->loadaddr;
303 /* handled later on */
306 return -1; /*call _dl_exit(1) */
308 #if defined (__SUPPORT_LD_DEBUG__)
309 if(_dl_debug_reloc && _dl_debug_detail)
310 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
317 _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
318 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
321 unsigned long *reloc_addr;
322 #if defined (__SUPPORT_LD_DEBUG__)
323 unsigned long old_val;
329 reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
330 reloc_type = ELF32_R_TYPE(rpnt->r_info);
332 #if defined (__SUPPORT_LD_DEBUG__)
333 old_val = *reloc_addr;
335 switch (reloc_type) {
339 *reloc_addr += (unsigned long) tpnt->loadaddr;
342 return -1; /*call _dl_exit(1) */
344 #if defined (__SUPPORT_LD_DEBUG__)
345 if(_dl_debug_reloc && _dl_debug_detail)
346 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
352 /* This is done as a separate step, because there are cases where
353 information is first copied and later initialized. This results in
354 the wrong information being copied. Someone at Sun was complaining about
355 a bug in the handling of _COPY by SVr4, and this may in fact be what he
356 was talking about. Sigh. */
358 /* No, there are cases where the SVr4 linker fails to emit COPY relocs
361 _dl_do_copy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
362 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
366 unsigned long *reloc_addr;
367 unsigned long symbol_addr;
371 reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
372 reloc_type = ELF32_R_TYPE(rpnt->r_info);
373 if (reloc_type != R_386_COPY)
375 symtab_index = ELF32_R_SYM(rpnt->r_info);
377 symname = strtab + symtab[symtab_index].st_name;
380 symbol_addr = (unsigned long) _dl_find_hash(symname, scope, NULL, copyrel);
381 if (!symbol_addr) goof++;
384 #if defined (__SUPPORT_LD_DEBUG__)
386 _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
387 symname, symtab[symtab_index].st_size,
388 symbol_addr, symtab[symtab_index].st_value);
390 _dl_memcpy((char *) symtab[symtab_index].st_value,
391 (char *) symbol_addr, symtab[symtab_index].st_size);
397 void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
398 unsigned long rel_addr, unsigned long rel_size, int type)
400 (void)_dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
403 int _dl_parse_relocation_information(struct dyn_elf *rpnt,
404 unsigned long rel_addr, unsigned long rel_size, int type)
406 return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
409 int _dl_parse_copy_information(struct dyn_elf *rpnt,
410 unsigned long rel_addr, unsigned long rel_size, int type)
412 return _dl_parse(rpnt->dyn, rpnt->next, rel_addr, rel_size, _dl_do_copy_reloc);