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 >= (int)(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\n\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";
81 _dl_dprintf(_dl_debug_file, "\n\t");
83 _dl_dprintf(_dl_debug_file, "\n%s\n\t", sym);
84 #ifdef ELF_USES_RELOCA
85 _dl_dprintf(_dl_debug_file, "%s\toffset=%x\taddend=%x",
86 _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
90 _dl_dprintf(_dl_debug_file, "%s\toffset=%x",
91 _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
98 /* Program to load an ELF binary on a linux system, and run it.
99 References to symbols in sharable libraries can be resolved by either
100 an ELF sharable library or a linux style of shared library. */
102 /* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
103 I ever taken any courses on internals. This program was developed using
104 information available through the book "UNIX SYSTEM V RELEASE 4,
105 Programmers guide: Ansi C and Programming Support Tools", which did
106 a more than adequate job of explaining everything required to get this
109 extern int _dl_linux_resolve(void);
111 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
114 ELF_RELOC *this_reloc;
121 unsigned long instr_addr;
123 rel_addr = (char *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
125 this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
126 reloc_type = ELF32_R_TYPE(this_reloc->r_info);
127 symtab_index = ELF32_R_SYM(this_reloc->r_info);
129 symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
130 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
132 if (reloc_type != R_386_JMP_SLOT) {
133 _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n",
138 /* Address of jump instruction to fix up */
139 instr_addr = ((unsigned long) this_reloc->r_offset +
140 (unsigned long) tpnt->loadaddr);
141 got_addr = (char **) instr_addr;
143 /* Get the address of the GOT entry */
144 new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name,
145 tpnt->symbol_scope, tpnt, resolver);
147 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
148 _dl_progname, strtab + symtab[symtab_index].st_name);
152 #if defined (__SUPPORT_LD_DEBUG__)
153 if ((unsigned long) got_addr < 0x40000000)
155 if (_dl_debug_bindings)
157 _dl_dprintf(_dl_debug_file, "\nresolve function: %s",
158 strtab + symtab[symtab_index].st_name);
159 if(_dl_debug_detail) _dl_dprintf(_dl_debug_file,
160 "\n\tpatch %x ==> %x @ %x\n", *got_addr, new_addr, got_addr);
163 if (!_dl_debug_nofixups) {
164 *got_addr = new_addr;
167 *got_addr = new_addr;
170 return (unsigned long) new_addr;
174 _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
175 unsigned long rel_addr, unsigned long rel_size,
176 int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
177 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
186 /* Now parse the relocation information */
187 rpnt = (ELF_RELOC *)(intptr_t) (rel_addr + tpnt->loadaddr);
188 rel_size = rel_size / sizeof(ELF_RELOC);
190 symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
191 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
193 for (i = 0; i < rel_size; i++, rpnt++) {
196 symtab_index = ELF32_R_SYM(rpnt->r_info);
198 /* When the dynamic linker bootstrapped itself, it resolved some symbols.
199 Make sure we do not do them again */
200 if (!symtab_index && tpnt->libtype == program_interpreter)
202 if (symtab_index && tpnt->libtype == program_interpreter &&
203 _dl_symbol(strtab + symtab[symtab_index].st_name))
206 #if defined (__SUPPORT_LD_DEBUG__)
207 debug_sym(symtab,strtab,symtab_index);
208 debug_reloc(symtab,strtab,rpnt);
211 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
213 if (res==0) continue;
215 _dl_dprintf(2, "\n%s: ",_dl_progname);
218 _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
222 int reloc_type = ELF32_R_TYPE(rpnt->r_info);
223 #if defined (__SUPPORT_LD_DEBUG__)
224 _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
226 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
232 _dl_dprintf(2, "can't resolve symbol\n");
241 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
242 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
246 unsigned long *reloc_addr;
247 unsigned long symbol_addr;
250 reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
251 reloc_type = ELF32_R_TYPE(rpnt->r_info);
252 symtab_index = ELF32_R_SYM(rpnt->r_info);
257 symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name,
258 scope, (reloc_type == R_386_JMP_SLOT ? tpnt : NULL), symbolrel);
261 * We want to allow undefined references to weak symbols - this might
262 * have been intentional. We should not be linking local symbols
263 * here, so all bases should be covered.
266 if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
267 #if defined (__SUPPORT_LD_DEBUG__)
268 _dl_dprintf(2, "library '%s': NOT resolving global symbol '%s'\n",
269 tpnt->libname, strtab + symtab[symtab_index].st_name);
275 #if defined (__SUPPORT_LD_DEBUG__)
277 unsigned long old_val = *reloc_addr;
279 switch (reloc_type) {
283 *reloc_addr += symbol_addr;
286 *reloc_addr += symbol_addr - (unsigned long) reloc_addr;
290 *reloc_addr = symbol_addr;
293 *reloc_addr += (unsigned long) tpnt->loadaddr;
296 /* handled later on */
299 return -1; /*call _dl_exit(1) */
301 #if defined (__SUPPORT_LD_DEBUG__)
302 if(_dl_debug_reloc && _dl_debug_detail)
303 _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
312 _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
313 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
316 unsigned long *reloc_addr;
321 reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
322 reloc_type = ELF32_R_TYPE(rpnt->r_info);
324 #if defined (__SUPPORT_LD_DEBUG__)
326 unsigned long old_val = *reloc_addr;
328 switch (reloc_type) {
332 *reloc_addr += (unsigned long) tpnt->loadaddr;
335 return -1; /*call _dl_exit(1) */
337 #if defined (__SUPPORT_LD_DEBUG__)
338 if(_dl_debug_reloc && _dl_debug_detail)
339 _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
347 /* This is done as a separate step, because there are cases where
348 information is first copied and later initialized. This results in
349 the wrong information being copied. Someone at Sun was complaining about
350 a bug in the handling of _COPY by SVr4, and this may in fact be what he
351 was talking about. Sigh. */
353 /* No, there are cases where the SVr4 linker fails to emit COPY relocs
356 _dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope,
357 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
361 unsigned long *reloc_addr;
362 unsigned long symbol_addr;
365 reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
366 reloc_type = ELF32_R_TYPE(rpnt->r_info);
367 if (reloc_type != R_386_COPY)
369 symtab_index = ELF32_R_SYM(rpnt->r_info);
374 symbol_addr = (unsigned long) _dl_find_hash(strtab +
375 symtab[symtab_index].st_name, scope,
377 if (!symbol_addr) goof++;
380 #if defined (__SUPPORT_LD_DEBUG__)
382 _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
383 strtab + symtab[symtab_index].st_name,
384 symtab[symtab_index].st_size,
385 symbol_addr, symtab[symtab_index].st_value);
387 _dl_memcpy((char *) symtab[symtab_index].st_value,
388 (char *) symbol_addr, symtab[symtab_index].st_size);
394 void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
395 unsigned long rel_addr, unsigned long rel_size, int type)
398 (void)_dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
401 int _dl_parse_relocation_information(struct elf_resolve *tpnt,
402 unsigned long rel_addr, unsigned long rel_size, int type)
405 return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
408 int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
409 unsigned long rel_size, int type)
412 return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy);