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 (unlikely(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, ELF_RTYPE_CLASS_PLT);
149 if (unlikely(!new_addr)) {
150 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
154 #if defined (__SUPPORT_LD_DEBUG__)
155 if ((unsigned long) got_addr < 0x40000000)
157 if (_dl_debug_bindings)
159 _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
160 if(_dl_debug_detail) _dl_dprintf(_dl_debug_file,
161 "\n\tpatched %x ==> %x @ %x\n", *got_addr, new_addr, got_addr);
164 if (!_dl_debug_nofixups) {
165 *got_addr = new_addr;
168 *got_addr = new_addr;
171 return (unsigned long) new_addr;
175 _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
176 unsigned long rel_addr, unsigned long rel_size,
177 int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
178 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 #if defined (__SUPPORT_LD_DEBUG__)
199 debug_sym(symtab,strtab,symtab_index);
200 debug_reloc(symtab,strtab,rpnt);
203 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
205 if (res==0) continue;
207 _dl_dprintf(2, "\n%s: ",_dl_progname);
210 _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
212 if (unlikely(res <0))
214 int reloc_type = ELF32_R_TYPE(rpnt->r_info);
215 #if defined (__SUPPORT_LD_DEBUG__)
216 _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
218 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
222 if (unlikely(res >0))
224 _dl_dprintf(2, "can't resolve symbol\n");
233 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
234 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
239 unsigned long *reloc_addr;
240 unsigned long symbol_addr;
241 #if defined (__SUPPORT_LD_DEBUG__)
242 unsigned long old_val;
245 reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
246 reloc_type = ELF32_R_TYPE(rpnt->r_info);
247 symtab_index = ELF32_R_SYM(rpnt->r_info);
249 symname = strtab + symtab[symtab_index].st_name;
253 symbol_addr = (unsigned long) _dl_find_hash(symname, scope,
254 elf_machine_type_class(reloc_type));
257 * We want to allow undefined references to weak symbols - this might
258 * have been intentional. We should not be linking local symbols
259 * here, so all bases should be covered.
262 if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
263 #if defined (__SUPPORT_LD_DEBUG__)
264 _dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s', rel type: %s\n",
265 symname, tpnt->libname, _dl_reltypes(reloc_type));
271 #if defined (__SUPPORT_LD_DEBUG__)
272 old_val = *reloc_addr;
274 switch (reloc_type) {
278 *reloc_addr += symbol_addr;
281 *reloc_addr += symbol_addr - (unsigned long) reloc_addr;
285 *reloc_addr = symbol_addr;
288 *reloc_addr += (unsigned long) tpnt->loadaddr;
291 /* handled later on */
294 return -1; /*call _dl_exit(1) */
296 #if defined (__SUPPORT_LD_DEBUG__)
297 if(_dl_debug_reloc && _dl_debug_detail)
298 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
305 _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
306 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
309 unsigned long *reloc_addr;
310 #if defined (__SUPPORT_LD_DEBUG__)
311 unsigned long old_val;
317 reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
318 reloc_type = ELF32_R_TYPE(rpnt->r_info);
320 #if defined (__SUPPORT_LD_DEBUG__)
321 old_val = *reloc_addr;
323 switch (reloc_type) {
327 *reloc_addr += (unsigned long) tpnt->loadaddr;
330 return -1; /*call _dl_exit(1) */
332 #if defined (__SUPPORT_LD_DEBUG__)
333 if(_dl_debug_reloc && _dl_debug_detail)
334 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
340 /* This is done as a separate step, because there are cases where
341 information is first copied and later initialized. This results in
342 the wrong information being copied. Someone at Sun was complaining about
343 a bug in the handling of _COPY by SVr4, and this may in fact be what he
344 was talking about. Sigh. */
346 /* No, there are cases where the SVr4 linker fails to emit COPY relocs
349 _dl_do_copy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
350 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
354 unsigned long *reloc_addr;
355 unsigned long symbol_addr;
359 reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
360 reloc_type = ELF32_R_TYPE(rpnt->r_info);
361 if (reloc_type != R_386_COPY)
363 symtab_index = ELF32_R_SYM(rpnt->r_info);
365 symname = strtab + symtab[symtab_index].st_name;
368 symbol_addr = (unsigned long) _dl_find_hash(symname, scope, ELF_RTYPE_CLASS_COPY);
369 if (!symbol_addr) goof++;
372 #if defined (__SUPPORT_LD_DEBUG__)
374 _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
375 symname, symtab[symtab_index].st_size,
376 symbol_addr, symtab[symtab_index].st_value);
378 _dl_memcpy((char *) symtab[symtab_index].st_value,
379 (char *) symbol_addr, symtab[symtab_index].st_size);
385 void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
386 unsigned long rel_addr, unsigned long rel_size, int type)
388 (void)_dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
391 int _dl_parse_relocation_information(struct dyn_elf *rpnt,
392 unsigned long rel_addr, unsigned long rel_size, int type)
394 return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
397 int _dl_parse_copy_information(struct dyn_elf *rpnt,
398 unsigned long rel_addr, unsigned long rel_size, int type)
400 return _dl_parse(rpnt->dyn, rpnt->next, rel_addr, rel_size, _dl_do_copy_reloc);