OSDN Git Service

whitespace and debug updates
[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",
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
123         rel_addr = (char *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
124
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);
128
129         symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
130         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
131
132         if (reloc_type != R_386_JMP_SLOT) {
133                 _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n", 
134                                 _dl_progname);
135                 _dl_exit(1);
136         }
137
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;
142
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);
146         if (!new_addr) {
147                 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", 
148                         _dl_progname, strtab + symtab[symtab_index].st_name);
149                 _dl_exit(1);
150         }
151
152 #if defined (__SUPPORT_LD_DEBUG__)
153         if ((unsigned long) got_addr < 0x40000000)
154         {
155                 if (_dl_debug_bindings)
156                 {
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);
161                 }
162         }
163         if (!_dl_debug_nofixups) {
164                 *got_addr = new_addr;
165         }
166 #else
167         *got_addr = new_addr;
168 #endif
169
170         return (unsigned long) new_addr;
171 }
172
173 static int
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))
178 {
179         unsigned int i;
180         char *strtab;
181         int goof = 0;
182         Elf32_Sym *symtab;
183         ELF_RELOC *rpnt;
184         int symtab_index;
185
186         /* Now parse the relocation information */
187         rpnt = (ELF_RELOC *)(intptr_t) (rel_addr + tpnt->loadaddr);
188         rel_size = rel_size / sizeof(ELF_RELOC);
189
190         symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
191         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
192
193           for (i = 0; i < rel_size; i++, rpnt++) {
194                 int res;
195             
196                 symtab_index = ELF32_R_SYM(rpnt->r_info);
197                 
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)
201                         continue;
202                 if (symtab_index && tpnt->libtype == program_interpreter &&
203                     _dl_symbol(strtab + symtab[symtab_index].st_name))
204                         continue;
205
206 #if defined (__SUPPORT_LD_DEBUG__)
207                 debug_sym(symtab,strtab,symtab_index);
208                 debug_reloc(symtab,strtab,rpnt);
209 #endif
210
211                 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
212
213                 if (res==0) continue;
214
215                 _dl_dprintf(2, "\n%s: ",_dl_progname);
216                 
217                 if (symtab_index)
218                   _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
219                   
220                 if (res <0)
221                 {
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));
225 #else
226                         _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
227 #endif                  
228                         _dl_exit(-res);
229                 }
230                 else if (res >0)
231                 {
232                         _dl_dprintf(2, "can't resolve symbol\n");
233                         //goof += res;
234                 }
235           }
236           return goof;
237 }
238
239
240 static int
241 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
242               ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
243 {
244         int reloc_type;
245         int symtab_index;
246         unsigned long *reloc_addr;
247         unsigned long symbol_addr;
248         int goof = 0;
249
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);
253         symbol_addr  = 0;
254
255         if (symtab_index) {
256
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);
259
260                 /*
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.
264                  */
265
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);
270 #endif
271                         goof++;
272                 }
273         }
274
275 #if defined (__SUPPORT_LD_DEBUG__)
276         {
277                 unsigned long old_val = *reloc_addr;
278 #endif
279                 switch (reloc_type) {
280                         case R_386_NONE:
281                                 break;
282                         case R_386_32:
283                                 *reloc_addr += symbol_addr;
284                                 break;
285                         case R_386_PC32:
286                                 *reloc_addr += symbol_addr - (unsigned long) reloc_addr;
287                                 break;
288                         case R_386_GLOB_DAT:
289                         case R_386_JMP_SLOT:
290                                 *reloc_addr = symbol_addr;
291                                 break;
292                         case R_386_RELATIVE:
293                                 *reloc_addr += (unsigned long) tpnt->loadaddr;
294                                 break;
295                         case R_386_COPY:
296                                 /* handled later on */
297                                 break;
298                         default:
299                                 return -1; /*call _dl_exit(1) */
300                 }
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);
304         }
305
306 #endif
307
308         return goof;
309 }
310
311 static int
312 _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
313                    ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
314 {
315         int reloc_type;
316         unsigned long *reloc_addr;
317         (void)scope;
318         (void)symtab;
319         (void)strtab;
320
321         reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
322         reloc_type = ELF32_R_TYPE(rpnt->r_info);
323
324 #if defined (__SUPPORT_LD_DEBUG__)
325         {
326                 unsigned long old_val = *reloc_addr;
327 #endif
328                 switch (reloc_type) {
329                         case R_386_NONE:
330                                 break;
331                         case R_386_JMP_SLOT:
332                                 *reloc_addr += (unsigned long) tpnt->loadaddr;
333                                 break;
334                         default:
335                                 return -1; /*call _dl_exit(1) */
336                 }
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);
340         }
341
342 #endif
343         return 0;
344
345 }
346
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. */
352
353 /* No, there are cases where the SVr4 linker fails to emit COPY relocs
354    at all */
355 static int
356 _dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope,
357              ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
358 {
359         int reloc_type;
360         int symtab_index;
361         unsigned long *reloc_addr;
362         unsigned long symbol_addr;
363         int goof = 0;
364           
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) 
368                 return 0;
369         symtab_index = ELF32_R_SYM(rpnt->r_info);
370         symbol_addr = 0;
371                 
372         if (symtab_index) {
373
374                 symbol_addr = (unsigned long) _dl_find_hash(strtab + 
375                         symtab[symtab_index].st_name, scope, 
376                         NULL, copyrel);
377                 if (!symbol_addr) goof++;
378         }
379         if (!goof) {
380 #if defined (__SUPPORT_LD_DEBUG__)
381                 if(_dl_debug_move)
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);
386 #endif
387                 _dl_memcpy((char *) symtab[symtab_index].st_value, 
388                         (char *) symbol_addr, symtab[symtab_index].st_size);
389         }
390
391         return goof;
392 }
393
394 void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, 
395         unsigned long rel_addr, unsigned long rel_size, int type)
396 {
397         (void) type;
398         (void)_dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
399 }
400
401 int _dl_parse_relocation_information(struct elf_resolve *tpnt, 
402         unsigned long rel_addr, unsigned long rel_size, int type)
403 {
404         (void) type;
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         (void) type;
412         return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy);
413 }
414