OSDN Git Service

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