OSDN Git Service

Massive scrubbing of the shared lib loader error handling.
[uclinux-h8/uClibc.git] / ldso / ldso / i386 / elfinterp.c
1 /* vi: set sw=4 ts=4: */
2 /* i386 ELF shared library loader suppport
3  *
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
7  *
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
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.
18  *
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
29  * SUCH DAMAGE.
30  */
31
32 #if defined (__SUPPORT_LD_DEBUG__)
33 static const char *_dl_reltypes_tab[] =
34 {
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",
38 };
39
40 static const char *
41 _dl_reltypes(int type)
42 {
43   static char buf[22];  
44   const char *str;
45   
46   if (type >= (sizeof (_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) ||
47       NULL == (str = _dl_reltypes_tab[type]))
48   {
49     str =_dl_simple_ltoa( buf, (unsigned long)(type));
50   }
51   return str;
52 }
53
54 static 
55 void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
56 {
57   if(_dl_debug_symbols)
58   {
59     if(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);
67     }
68   }
69 }
70
71 static void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt)
72 {
73   if(_dl_debug_reloc)
74   {
75     int symtab_index;
76     const char *sym;
77     symtab_index = ELF32_R_SYM(rpnt->r_info);
78     sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0";
79     
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)),
83                 rpnt->r_offset,
84                 rpnt->r_addend,
85                 sym);
86 #else
87     _dl_dprintf(_dl_debug_file, "\n%s\toffset=%x %s",
88                 _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
89                 rpnt->r_offset,
90                 sym);
91 #endif
92   }
93 }
94 #endif
95
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. */
99
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
105    working. */
106
107 extern int _dl_linux_resolve(void);
108
109 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
110 {
111         int reloc_type;
112         ELF_RELOC *this_reloc;
113         char *strtab;
114         Elf32_Sym *symtab;
115         ELF_RELOC *rel_addr;
116         int symtab_index;
117         char *new_addr;
118         char **got_addr;
119         unsigned long instr_addr;
120
121         rel_addr = (ELF_RELOC *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
122
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);
126
127         symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
128         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
129
130
131         if (reloc_type != R_386_JMP_SLOT) {
132                 _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n", 
133                         _dl_progname);
134                 _dl_exit(1);
135         };
136
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;
141
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);
145         if (!new_addr) {
146                 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", 
147                         _dl_progname, strtab + symtab[symtab_index].st_name);
148                 _dl_exit(1);
149         };
150
151 #if defined (__SUPPORT_LD_DEBUG__)
152         if ((unsigned long) got_addr < 0x40000000)
153         {
154                 if (_dl_debug_bindings)
155                 {
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);
160                 }
161         }
162         if (!_dl_debug_nofixups) {
163                 *got_addr = new_addr;
164         }
165 #else
166         *got_addr = new_addr;
167 #endif
168
169         return (unsigned long) new_addr;
170 }
171
172 static int
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))
177 {
178         int i;
179         char *strtab;
180         int goof = 0;
181         Elf32_Sym *symtab;
182         ELF_RELOC *rpnt;
183         int symtab_index;
184         /* Now parse the relocation information */
185
186         rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
187         rel_size = rel_size / sizeof(ELF_RELOC);
188
189         symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
190         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
191
192           for (i = 0; i < rel_size; i++, rpnt++) {
193                 int res;
194             
195                 symtab_index = ELF32_R_SYM(rpnt->r_info);
196                 
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)
200                         continue;
201                 if (symtab_index && tpnt->libtype == program_interpreter &&
202                     _dl_symbol(strtab + symtab[symtab_index].st_name))
203                         continue;
204
205 #if defined (__SUPPORT_LD_DEBUG__)
206                 debug_sym(symtab,strtab,symtab_index);
207                 debug_reloc(symtab,strtab,rpnt);
208 #endif
209
210                 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
211
212                 if (res==0) continue;
213
214                 _dl_dprintf(2, "\n%s: ",_dl_progname);
215                 
216                 if (symtab_index)
217                   _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
218                   
219                 if (res <0)
220                 {
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));
224 #else
225                         _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
226 #endif                  
227                         _dl_exit(-res);
228                 }
229                 else if (res >0)
230                 {
231                         _dl_dprintf(2, "can't resolve symbol\n");
232                         goof += res;
233                 }
234           }
235           return goof;
236 }
237
238 static int
239 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
240               ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
241 {
242         int reloc_type;
243         int symtab_index;
244         unsigned long *reloc_addr;
245         unsigned long symbol_addr;
246         int goof = 0;
247
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);
251         symbol_addr = 0;
252
253         if (symtab_index) {
254
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);
257
258                 /*
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.
262                  */
263                 if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
264                         goof++;
265                 }
266         }
267
268 #if defined (__SUPPORT_LD_DEBUG__)
269         {
270                 unsigned long old_val = *reloc_addr;
271 #endif
272                 switch (reloc_type) {
273                         case R_386_NONE:
274                                 break;
275                         case R_386_32:
276                                 *reloc_addr += symbol_addr;
277                                 break;
278                         case R_386_PC32:
279                                 *reloc_addr += symbol_addr - (unsigned long) reloc_addr;
280                                 break;
281                         case R_386_GLOB_DAT:
282                         case R_386_JMP_SLOT:
283                                 *reloc_addr = symbol_addr;
284                                 break;
285                         case R_386_RELATIVE:
286                                 *reloc_addr += (unsigned long) tpnt->loadaddr;
287                                 break;
288                         case R_386_COPY:
289 #if 0
290                                 /* Do this later */
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);
296 #endif
297                                 break;
298
299                         default:
300                                 return -1; /*call _dl_exit(1) */
301                 }
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);
305         }
306
307 #endif
308
309         return goof;
310 }
311
312 static int
313 _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
314                    ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
315 {
316         int reloc_type;
317         unsigned long *reloc_addr;
318
319         reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
320         reloc_type = ELF32_R_TYPE(rpnt->r_info);
321
322 #if defined (__SUPPORT_LD_DEBUG__)
323         {
324                 unsigned long old_val = *reloc_addr;
325 #endif
326                 switch (reloc_type) {
327                         case R_386_NONE:
328                                 break;
329                         case R_386_JMP_SLOT:
330                                 *reloc_addr += (unsigned long) tpnt->loadaddr;
331                                 break;
332
333                         default:
334                                 return -1; /*call _dl_exit(1) */
335                 }
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);
339         }
340
341 #endif
342         return 0;
343
344 }
345
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. */
351
352 /* No, there are cases where the SVr4 linker fails to emit COPY relocs
353    at all */
354 static int
355 _dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope,
356              ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
357 {
358         int reloc_type;
359         int symtab_index;
360         unsigned long *reloc_addr;
361         unsigned long symbol_addr;
362         int goof = 0;
363           
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) 
367                 return 0;
368         symtab_index = ELF32_R_SYM(rpnt->r_info);
369         symbol_addr = 0;
370                 
371         if (symtab_index) {
372
373                 symbol_addr = (unsigned long) _dl_find_hash(strtab + 
374                         symtab[symtab_index].st_name, scope, 
375                         NULL, copyrel);
376                 if (!symbol_addr) goof++;
377         }
378         if (!goof) {
379 #if defined (__SUPPORT_LD_DEBUG__)
380                 if(_dl_debug_move)
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);
385 #endif
386                 _dl_memcpy((char *) symtab[symtab_index].st_value, 
387                         (char *) symbol_addr, symtab[symtab_index].st_size);
388         }
389
390         return goof;
391 }
392
393 void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, 
394         unsigned long rel_addr, unsigned long rel_size, int type)
395 {
396   (void)_dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
397 }
398
399 int _dl_parse_relocation_information(struct elf_resolve *tpnt, 
400         unsigned long rel_addr, unsigned long rel_size, int type)
401 {
402   return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
403 }
404
405 int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, 
406         unsigned long rel_size, int type)
407 {
408   return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy);
409 }
410