OSDN Git Service

Add missing _dl_dprintf arguments, as noticed by Tero Lyytik�inen <tero@paravant.fi>
[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) || defined (LD_DEBUG_SYMBOLS)
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 #if defined (SUPPORT_LD_DEBUG) || defined (LD_NEVER_FIXUP_SYMBOLS)
151         if ((unsigned long) got_addr < 0x40000000)
152         {
153 #ifndef SUPPORT_LD_DEBUG
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, "\tpatch %x ==> %x @ %x", *got_addr, new_addr, got_addr);
159           }
160 #endif    
161 #ifndef LD_NEVER_FIXUP_SYMBOLS
162           *got_addr = new_addr;
163 #endif          
164         } else {
165           *got_addr = new_addr;
166         }
167 #else
168         *got_addr = new_addr;
169 #endif
170
171         return (unsigned long) new_addr;
172 }
173
174 static int
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))
179 {
180         int i;
181         char *strtab;
182         int goof = 0;
183         Elf32_Sym *symtab;
184         ELF_RELOC *rpnt;
185         int symtab_index;
186         /* Now parse the relocation information */
187
188         rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
189         rel_size = rel_size / sizeof(ELF_RELOC);
190
191         symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
192         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
193
194           for (i = 0; i < rel_size; i++, rpnt++) {
195                 int res;
196             
197                 symtab_index = ELF32_R_SYM(rpnt->r_info);
198                 
199                 /* When the dynamic linker bootstrapped itself, it resolved some symbols.
200                    Make sure we do not do them again */
201                 if (!symtab_index && tpnt->libtype == program_interpreter)
202                         continue;
203                 if (symtab_index && tpnt->libtype == program_interpreter &&
204                     _dl_symbol(strtab + symtab[symtab_index].st_name))
205                         continue;
206
207 #if defined (SUPPORT_LD_DEBUG) || defined (LD_DEBUG_SYMBOLS)
208                 debug_sym(symtab,strtab,symtab_index);
209                 debug_reloc(symtab,strtab,rpnt);
210 #endif
211
212                 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
213
214                 if (res==0) continue;
215
216                 _dl_dprintf(2, "\n%s: ",_dl_progname);
217                 
218                 if (symtab_index)
219                   _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
220                   
221                 if (res <0)
222                 {
223                         int reloc_type = ELF32_R_TYPE(rpnt->r_info);
224 #if defined (SUPPORT_LD_DEBUG)
225                         _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
226 #else
227                         _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
228 #endif                  
229                         _dl_exit(-res);
230                 }
231                 else if (res >0)
232                 {
233                         _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
234                                         _dl_progname, strtab + symtab[symtab_index].st_name);
235                         goof += res;
236                 }
237           }
238           return goof;
239 }
240
241 static int
242 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
243               ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
244 {
245         int reloc_type;
246         int symtab_index;
247         unsigned long *reloc_addr;
248         unsigned long symbol_addr;
249         int goof = 0;
250
251         reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
252         reloc_type = ELF32_R_TYPE(rpnt->r_info);
253         symtab_index = ELF32_R_SYM(rpnt->r_info);
254         symbol_addr = 0;
255
256         if (symtab_index) {
257
258                 symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name, 
259                                 scope, (reloc_type == R_386_JMP_SLOT ? tpnt : NULL), symbolrel);
260
261                 /*
262                  * We want to allow undefined references to weak symbols - this might
263                  * have been intentional.  We should not be linking local symbols
264                  * here, so all bases should be covered.
265                  */
266                 if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
267                         goof++;
268                 }
269         }
270
271 #if defined (SUPPORT_LD_DEBUG)
272         {
273                 unsigned long old_val = *reloc_addr;
274 #endif
275                 switch (reloc_type) {
276                         case R_386_NONE:
277                                 break;
278                         case R_386_32:
279                                 *reloc_addr += symbol_addr;
280                                 break;
281                         case R_386_PC32:
282                                 *reloc_addr += symbol_addr - (unsigned long) reloc_addr;
283                                 break;
284                         case R_386_GLOB_DAT:
285                         case R_386_JMP_SLOT:
286                                 *reloc_addr = symbol_addr;
287                                 break;
288                         case R_386_RELATIVE:
289                                 *reloc_addr += (unsigned long) tpnt->loadaddr;
290                                 break;
291                         case R_386_COPY:
292 #if 0
293                                 /* Do this later */
294                                 _dl_dprintf(2, "Doing copy for symbol ");
295                                 if (symtab_index) _dl_dprintf(2, strtab + symtab[symtab_index].st_name);
296                                 _dl_dprintf(2, "\n");
297                                 _dl_memcpy((void *) symtab[symtab_index].st_value, 
298                                                 (void *) symbol_addr, symtab[symtab_index].st_size);
299 #endif
300                                 break;
301
302                         default:
303                                 return -1; /*call _dl_exit(1) */
304                 }
305 #if defined (SUPPORT_LD_DEBUG)
306                 if(_dl_debug_reloc && _dl_debug_detail)
307                         _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
308         }
309
310 #endif
311
312         return goof;
313 }
314
315 static int
316 _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
317                    ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
318 {
319         int reloc_type;
320         unsigned long *reloc_addr;
321
322         reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
323         reloc_type = ELF32_R_TYPE(rpnt->r_info);
324
325 #if defined (SUPPORT_LD_DEBUG)
326         {
327                 unsigned long old_val = *reloc_addr;
328 #endif
329                 switch (reloc_type) {
330                         case R_386_NONE:
331                                 break;
332                         case R_386_JMP_SLOT:
333                                 *reloc_addr += (unsigned long) tpnt->loadaddr;
334                                 break;
335
336                         default:
337                                 return -1; /*call _dl_exit(1) */
338                 }
339 #if defined (SUPPORT_LD_DEBUG)
340                 if(_dl_debug_reloc && _dl_debug_detail)
341                         _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
342         }
343
344 #endif
345         return 0;
346
347 }
348
349 /* This is done as a separate step, because there are cases where
350    information is first copied and later initialized.  This results in
351    the wrong information being copied.  Someone at Sun was complaining about
352    a bug in the handling of _COPY by SVr4, and this may in fact be what he
353    was talking about.  Sigh. */
354
355 /* No, there are cases where the SVr4 linker fails to emit COPY relocs
356    at all */
357 static int
358 _dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope,
359              ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
360 {
361         int reloc_type;
362         int symtab_index;
363         unsigned long *reloc_addr;
364         unsigned long symbol_addr;
365         int goof = 0;
366           
367         reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
368         reloc_type = ELF32_R_TYPE(rpnt->r_info);
369         if (reloc_type != R_386_COPY) 
370                 return 0;
371         symtab_index = ELF32_R_SYM(rpnt->r_info);
372         symbol_addr = 0;
373                 
374         if (symtab_index) {
375
376                 symbol_addr = (unsigned long) _dl_find_hash(strtab + 
377                         symtab[symtab_index].st_name, scope, 
378                         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                              strtab + symtab[symtab_index].st_name,
386                              symtab[symtab_index].st_size,
387                              symbol_addr, symtab[symtab_index].st_value);
388 #endif
389                 _dl_memcpy((char *) symtab[symtab_index].st_value, 
390                         (char *) symbol_addr, symtab[symtab_index].st_size);
391         }
392
393         return goof;
394 }
395
396 void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, 
397         unsigned long rel_addr, unsigned long rel_size, int type)
398 {
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   return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
406 }
407
408 int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, 
409         unsigned long rel_size, int type)
410 {
411   return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy);
412 }
413