OSDN Git Service

5ccad32595a889bddf6897bcafe1c38bb8e95552
[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 >= (int)(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\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);
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   if(_dl_debug_symbols)
81           _dl_dprintf(_dl_debug_file, "\n\t");
82   else
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)),
87                 rpnt->r_offset,
88                 rpnt->r_addend);
89 #else
90     _dl_dprintf(_dl_debug_file, "%s\toffset=%x\n",
91                 _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
92                 rpnt->r_offset);
93 #endif
94   }
95 }
96 #endif
97
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. */
101
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
107    working. */
108
109 extern int _dl_linux_resolve(void);
110
111 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
112 {
113         int reloc_type;
114         ELF_RELOC *this_reloc;
115         char *strtab;
116         Elf32_Sym *symtab;
117         int symtab_index;
118         char *rel_addr;
119         char *new_addr;
120         char **got_addr;
121         unsigned long instr_addr;
122         char *symname;
123
124         rel_addr = (char *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
125
126         this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
127         reloc_type = ELF32_R_TYPE(this_reloc->r_info);
128         symtab_index = ELF32_R_SYM(this_reloc->r_info);
129
130         symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
131         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
132         symname= strtab + symtab[symtab_index].st_name;
133
134         if (reloc_type != R_386_JMP_SLOT) {
135                 _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n", 
136                                 _dl_progname);
137                 _dl_exit(1);
138         }
139
140         /* Address of jump instruction to fix up */
141         instr_addr = ((unsigned long) this_reloc->r_offset + 
142                         (unsigned long) tpnt->loadaddr);
143         got_addr = (char **) instr_addr;
144
145         /* Get the address of the GOT entry */
146         new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, resolver);
147         if (!new_addr) {
148                 new_addr = _dl_find_hash(symname, NULL, NULL, resolver);
149                 if (new_addr) {
150                         return (unsigned long) new_addr;
151                 }
152                 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
153                 _dl_exit(1);
154         }
155
156 #if defined (__SUPPORT_LD_DEBUG__)
157         if ((unsigned long) got_addr < 0x40000000)
158         {
159                 if (_dl_debug_bindings)
160                 {
161                         _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
162                         if(_dl_debug_detail) _dl_dprintf(_dl_debug_file, 
163                                         "\n\tpatched %x ==> %x @ %x\n", *got_addr, new_addr, got_addr);
164                 }
165         }
166         if (!_dl_debug_nofixups) {
167                 *got_addr = new_addr;
168         }
169 #else
170         *got_addr = new_addr;
171 #endif
172
173         return (unsigned long) new_addr;
174 }
175
176 static int
177 _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
178           unsigned long rel_addr, unsigned long rel_size,
179           int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
180                             ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
181 {
182         unsigned int i;
183         char *strtab;
184         Elf32_Sym *symtab;
185         ELF_RELOC *rpnt;
186         int symtab_index;
187
188         /* Now parse the relocation information */
189         rpnt = (ELF_RELOC *)(intptr_t) (rel_addr + tpnt->loadaddr);
190         rel_size = rel_size / sizeof(ELF_RELOC);
191
192         symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
193         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
194
195           for (i = 0; i < rel_size; i++, rpnt++) {
196                 int res;
197             
198                 symtab_index = ELF32_R_SYM(rpnt->r_info);
199                 
200                 /* When the dynamic linker bootstrapped itself, it resolved some symbols.
201                    Make sure we do not do them again */
202                 if (!symtab_index && tpnt->libtype == program_interpreter)
203                         continue;
204                 if (symtab_index && tpnt->libtype == program_interpreter &&
205                     _dl_symbol(strtab + symtab[symtab_index].st_name))
206                         continue;
207
208 #if defined (__SUPPORT_LD_DEBUG__)
209                 debug_sym(symtab,strtab,symtab_index);
210                 debug_reloc(symtab,strtab,rpnt);
211 #endif
212
213                 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
214
215                 if (res==0) continue;
216
217                 _dl_dprintf(2, "\n%s: ",_dl_progname);
218                 
219                 if (symtab_index)
220                   _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
221                   
222                 if (res <0)
223                 {
224                         int reloc_type = ELF32_R_TYPE(rpnt->r_info);
225 #if defined (__SUPPORT_LD_DEBUG__)
226                         _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
227 #else
228                         _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
229 #endif                  
230                         _dl_exit(-res);
231                 }
232                 else if (res >0)
233                 {
234                         _dl_dprintf(2, "can't resolve symbol\n");
235                         return res;
236                 }
237           }
238           return 0;
239 }
240
241
242 static int
243 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
244               ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
245 {
246         int reloc_type;
247         int symtab_index;
248         char *symname;
249         unsigned long *reloc_addr;
250         unsigned long symbol_addr;
251 #if defined (__SUPPORT_LD_DEBUG__)
252         unsigned long old_val;
253 #endif
254
255         reloc_addr   = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
256         reloc_type   = ELF32_R_TYPE(rpnt->r_info);
257         symtab_index = ELF32_R_SYM(rpnt->r_info);
258         symbol_addr  = 0;
259         symname      = strtab + symtab[symtab_index].st_name;
260
261         if (symtab_index) {
262
263                 symbol_addr = (unsigned long) _dl_find_hash(symname, scope, 
264                                 (reloc_type == R_386_JMP_SLOT ? tpnt : NULL), symbolrel);
265
266                 /*
267                  * We want to allow undefined references to weak symbols - this might
268                  * have been intentional.  We should not be linking local symbols
269                  * here, so all bases should be covered.
270                  */
271
272                 if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
273 #if defined (__SUPPORT_LD_DEBUG__)
274                         _dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s'\n",
275                                         symname, tpnt->libname);
276 #endif
277                         return 0;
278                 }
279         }
280
281 #if defined (__SUPPORT_LD_DEBUG__)
282         old_val = *reloc_addr;
283 #endif
284                 switch (reloc_type) {
285                         case R_386_NONE:
286                                 break;
287                         case R_386_32:
288                                 *reloc_addr += symbol_addr;
289                                 break;
290                         case R_386_PC32:
291                                 *reloc_addr += symbol_addr - (unsigned long) reloc_addr;
292                                 break;
293                         case R_386_GLOB_DAT:
294                         case R_386_JMP_SLOT:
295                                 *reloc_addr = symbol_addr;
296                                 break;
297                         case R_386_RELATIVE:
298                                 *reloc_addr += (unsigned long) tpnt->loadaddr;
299                                 break;
300                         case R_386_COPY:
301                                 /* handled later on */
302                                 break;
303                         default:
304                                 return -1; /*call _dl_exit(1) */
305                 }
306 #if defined (__SUPPORT_LD_DEBUG__)
307         if(_dl_debug_reloc && _dl_debug_detail)
308                 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
309 #endif
310
311         return 0;
312 }
313
314 static int
315 _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
316                    ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
317 {
318         int reloc_type;
319         unsigned long *reloc_addr;
320 #if defined (__SUPPORT_LD_DEBUG__)
321         unsigned long old_val;
322 #endif
323         (void)scope;
324         (void)symtab;
325         (void)strtab;
326
327         reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
328         reloc_type = ELF32_R_TYPE(rpnt->r_info);
329
330 #if defined (__SUPPORT_LD_DEBUG__)
331         old_val = *reloc_addr;
332 #endif
333                 switch (reloc_type) {
334                         case R_386_NONE:
335                                 break;
336                         case R_386_JMP_SLOT:
337                                 *reloc_addr += (unsigned long) tpnt->loadaddr;
338                                 break;
339                         default:
340                                 return -1; /*call _dl_exit(1) */
341                 }
342 #if defined (__SUPPORT_LD_DEBUG__)
343         if(_dl_debug_reloc && _dl_debug_detail)
344                 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
345 #endif
346         return 0;
347
348 }
349
350 /* This is done as a separate step, because there are cases where
351    information is first copied and later initialized.  This results in
352    the wrong information being copied.  Someone at Sun was complaining about
353    a bug in the handling of _COPY by SVr4, and this may in fact be what he
354    was talking about.  Sigh. */
355
356 /* No, there are cases where the SVr4 linker fails to emit COPY relocs
357    at all */
358 static int
359 _dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope,
360              ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
361 {
362         int reloc_type;
363         int symtab_index;
364         unsigned long *reloc_addr;
365         unsigned long symbol_addr;
366         int goof = 0;
367         char *symname;
368           
369         reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
370         reloc_type = ELF32_R_TYPE(rpnt->r_info);
371         if (reloc_type != R_386_COPY) 
372                 return 0;
373         symtab_index = ELF32_R_SYM(rpnt->r_info);
374         symbol_addr = 0;
375         symname      = strtab + symtab[symtab_index].st_name;
376                 
377         if (symtab_index) {
378                 symbol_addr = (unsigned long) _dl_find_hash(symname, scope, NULL, copyrel);
379                 if (!symbol_addr) goof++;
380         }
381         if (!goof) {
382 #if defined (__SUPPORT_LD_DEBUG__)
383                 if(_dl_debug_move)
384                   _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
385                              symname, symtab[symtab_index].st_size,
386                              symbol_addr, symtab[symtab_index].st_value);
387 #endif
388                 _dl_memcpy((char *) symtab[symtab_index].st_value, 
389                         (char *) symbol_addr, symtab[symtab_index].st_size);
390         }
391
392         return goof;
393 }
394
395 void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, 
396         unsigned long rel_addr, unsigned long rel_size, int type)
397 {
398         (void) type;
399         (void)_dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
400 }
401
402 int _dl_parse_relocation_information(struct elf_resolve *tpnt, 
403         unsigned long rel_addr, unsigned long rel_size, int type)
404 {
405         (void) type;
406         return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
407 }
408
409 int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, 
410         unsigned long rel_size, int type)
411 {
412         (void) type;
413         return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy);
414 }
415