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-2002, 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
32 #if defined (__SUPPORT_LD_DEBUG__)
33 static const char *_dl_reltypes_tab[] =
35 [0] "R_386_NONE", "R_386_32", "R_386_PC32", "R_386_GOT32",
36 [4] "R_386_PLT32", "R_386_COPY", "R_386_GLOB_DAT", "R_386_JMP_SLOT",
37 [8] "R_386_RELATIVE", "R_386_GOTOFF", "R_386_GOTPC",
41 _dl_reltypes(int type)
46 if (type >= (sizeof (_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) ||
47 NULL == (str = _dl_reltypes_tab[type]))
49 str =_dl_simple_ltoa( buf, (unsigned long)(type));
55 void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
60 _dl_dprintf(_dl_debug_file, "\n%s\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",
61 strtab + symtab[symtab_index].st_name,
62 symtab[symtab_index].st_value,
63 symtab[symtab_index].st_size,
64 symtab[symtab_index].st_info,
65 symtab[symtab_index].st_other,
66 symtab[symtab_index].st_shndx);
71 static void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt)
77 symtab_index = ELF32_R_SYM(rpnt->r_info);
78 sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0";
80 #ifdef ELF_USES_RELOCA
81 _dl_dprintf(_dl_debug_file, "\n%s\toffset=%x\taddend=%x %s",
82 _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
87 _dl_dprintf(_dl_debug_file, "\n%s\toffset=%x %s",
88 _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
96 /* Program to load an ELF binary on a linux system, and run it.
97 References to symbols in sharable libraries can be resolved by either
98 an ELF sharable library or a linux style of shared library. */
100 /* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
101 I ever taken any courses on internals. This program was developed using
102 information available through the book "UNIX SYSTEM V RELEASE 4,
103 Programmers guide: Ansi C and Programming Support Tools", which did
104 a more than adequate job of explaining everything required to get this
107 extern int _dl_linux_resolve(void);
109 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
112 ELF_RELOC *this_reloc;
119 unsigned long instr_addr;
121 rel_addr = (ELF_RELOC *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
123 this_reloc = rel_addr + (reloc_entry >> 3);
124 reloc_type = ELF32_R_TYPE(this_reloc->r_info);
125 symtab_index = ELF32_R_SYM(this_reloc->r_info);
127 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
128 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
131 if (reloc_type != R_386_JMP_SLOT) {
132 _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n",
137 /* Address of jump instruction to fix up */
138 instr_addr = ((unsigned long) this_reloc->r_offset +
139 (unsigned long) tpnt->loadaddr);
140 got_addr = (char **) instr_addr;
142 /* Get the address of the GOT entry */
143 new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name,
144 tpnt->symbol_scope, tpnt, resolver);
146 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
147 _dl_progname, strtab + symtab[symtab_index].st_name);
151 #if defined (__SUPPORT_LD_DEBUG__)
152 if ((unsigned long) got_addr < 0x40000000)
154 if (_dl_debug_bindings)
156 _dl_dprintf(_dl_debug_file, "\nresolve function: %s",
157 strtab + symtab[symtab_index].st_name);
158 if(_dl_debug_detail) _dl_dprintf(_dl_debug_file,
159 "\tpatch %x ==> %x @ %x", *got_addr, new_addr, got_addr);
162 if (!_dl_debug_nofixups) {
163 *got_addr = new_addr;
166 *got_addr = new_addr;
169 return (unsigned long) new_addr;
173 _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
174 unsigned long rel_addr, unsigned long rel_size,
175 int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
176 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
184 /* Now parse the relocation information */
186 rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
187 rel_size = rel_size / sizeof(ELF_RELOC);
189 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
190 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
192 for (i = 0; i < rel_size; i++, rpnt++) {
195 symtab_index = ELF32_R_SYM(rpnt->r_info);
197 /* When the dynamic linker bootstrapped itself, it resolved some symbols.
198 Make sure we do not do them again */
199 if (!symtab_index && tpnt->libtype == program_interpreter)
201 if (symtab_index && tpnt->libtype == program_interpreter &&
202 _dl_symbol(strtab + symtab[symtab_index].st_name))
205 #if defined (__SUPPORT_LD_DEBUG__)
206 debug_sym(symtab,strtab,symtab_index);
207 debug_reloc(symtab,strtab,rpnt);
210 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
212 if (res==0) continue;
214 _dl_dprintf(2, "\n%s: ",_dl_progname);
217 _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
221 int reloc_type = ELF32_R_TYPE(rpnt->r_info);
222 #if defined (__SUPPORT_LD_DEBUG__)
223 _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
225 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
231 _dl_dprintf(2, "can't resolve symbol\n");
239 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
240 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
244 unsigned long *reloc_addr;
245 unsigned long symbol_addr;
248 reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
249 reloc_type = ELF32_R_TYPE(rpnt->r_info);
250 symtab_index = ELF32_R_SYM(rpnt->r_info);
255 symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name,
256 scope, (reloc_type == R_386_JMP_SLOT ? tpnt : NULL), symbolrel);
259 * We want to allow undefined references to weak symbols - this might
260 * have been intentional. We should not be linking local symbols
261 * here, so all bases should be covered.
263 if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
268 #if defined (__SUPPORT_LD_DEBUG__)
270 unsigned long old_val = *reloc_addr;
272 switch (reloc_type) {
276 *reloc_addr += symbol_addr;
279 *reloc_addr += symbol_addr - (unsigned long) reloc_addr;
283 *reloc_addr = symbol_addr;
286 *reloc_addr += (unsigned long) tpnt->loadaddr;
291 _dl_dprintf(2, "Doing copy for symbol ");
292 if (symtab_index) _dl_dprintf(2, strtab + symtab[symtab_index].st_name);
293 _dl_dprintf(2, "\n");
294 _dl_memcpy((void *) symtab[symtab_index].st_value,
295 (void *) symbol_addr, symtab[symtab_index].st_size);
300 return -1; /*call _dl_exit(1) */
302 #if defined (__SUPPORT_LD_DEBUG__)
303 if(_dl_debug_reloc && _dl_debug_detail)
304 _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
313 _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
314 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
317 unsigned long *reloc_addr;
319 reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
320 reloc_type = ELF32_R_TYPE(rpnt->r_info);
322 #if defined (__SUPPORT_LD_DEBUG__)
324 unsigned long old_val = *reloc_addr;
326 switch (reloc_type) {
330 *reloc_addr += (unsigned long) tpnt->loadaddr;
334 return -1; /*call _dl_exit(1) */
336 #if defined (__SUPPORT_LD_DEBUG__)
337 if(_dl_debug_reloc && _dl_debug_detail)
338 _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
346 /* This is done as a separate step, because there are cases where
347 information is first copied and later initialized. This results in
348 the wrong information being copied. Someone at Sun was complaining about
349 a bug in the handling of _COPY by SVr4, and this may in fact be what he
350 was talking about. Sigh. */
352 /* No, there are cases where the SVr4 linker fails to emit COPY relocs
355 _dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope,
356 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
360 unsigned long *reloc_addr;
361 unsigned long symbol_addr;
364 reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
365 reloc_type = ELF32_R_TYPE(rpnt->r_info);
366 if (reloc_type != R_386_COPY)
368 symtab_index = ELF32_R_SYM(rpnt->r_info);
373 symbol_addr = (unsigned long) _dl_find_hash(strtab +
374 symtab[symtab_index].st_name, scope,
376 if (!symbol_addr) goof++;
379 #if defined (__SUPPORT_LD_DEBUG__)
381 _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
382 strtab + symtab[symtab_index].st_name,
383 symtab[symtab_index].st_size,
384 symbol_addr, symtab[symtab_index].st_value);
386 _dl_memcpy((char *) symtab[symtab_index].st_value,
387 (char *) symbol_addr, symtab[symtab_index].st_size);
393 void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
394 unsigned long rel_addr, unsigned long rel_size, int type)
396 (void)_dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
399 int _dl_parse_relocation_information(struct elf_resolve *tpnt,
400 unsigned long rel_addr, unsigned long rel_size, int type)
402 return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
405 int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
406 unsigned long rel_size, int type)
408 return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy);