OSDN Git Service

Let ldso decide if it should relocate itselft a second time. This
[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 (unlikely(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, ELF_RTYPE_CLASS_PLT);
149         if (unlikely(!new_addr)) {
150                 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
151                 _dl_exit(1);
152         };
153
154 #if defined (__SUPPORT_LD_DEBUG__)
155         if ((unsigned long) got_addr < 0x40000000)
156         {
157                 if (_dl_debug_bindings)
158                 {
159                         _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
160                         if(_dl_debug_detail) _dl_dprintf(_dl_debug_file,
161                                         "\n\tpatched %x ==> %x @ %x\n", *got_addr, new_addr, got_addr);
162                 }
163         }
164         if (!_dl_debug_nofixups) {
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         unsigned int i;
181         char *strtab;
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 #if defined (__SUPPORT_LD_DEBUG__)
199                 debug_sym(symtab,strtab,symtab_index);
200                 debug_reloc(symtab,strtab,rpnt);
201 #endif
202
203                 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
204
205                 if (res==0) continue;
206
207                 _dl_dprintf(2, "\n%s: ",_dl_progname);
208
209                 if (symtab_index)
210                   _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
211
212                 if (unlikely(res <0))
213                 {
214                         int reloc_type = ELF32_R_TYPE(rpnt->r_info);
215 #if defined (__SUPPORT_LD_DEBUG__)
216                         _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
217 #else
218                         _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
219 #endif
220                         _dl_exit(-res);
221                 }
222                 if (unlikely(res >0))
223                 {
224                         _dl_dprintf(2, "can't resolve symbol\n");
225                         return res;
226                 }
227           }
228           return 0;
229 }
230
231
232 static int
233 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
234               ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
235 {
236         int reloc_type;
237         int symtab_index;
238         char *symname;
239         unsigned long *reloc_addr;
240         unsigned long symbol_addr;
241 #if defined (__SUPPORT_LD_DEBUG__)
242         unsigned long old_val;
243 #endif
244
245         reloc_addr   = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
246         reloc_type   = ELF32_R_TYPE(rpnt->r_info);
247         symtab_index = ELF32_R_SYM(rpnt->r_info);
248         symbol_addr  = 0;
249         symname      = strtab + symtab[symtab_index].st_name;
250
251         if (symtab_index) {
252
253                 symbol_addr = (unsigned long) _dl_find_hash(symname, scope,
254                                                             elf_machine_type_class(reloc_type));
255
256                 /*
257                  * We want to allow undefined references to weak symbols - this might
258                  * have been intentional.  We should not be linking local symbols
259                  * here, so all bases should be covered.
260                  */
261
262                 if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
263 #if defined (__SUPPORT_LD_DEBUG__)
264                         _dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s', rel type: %s\n",
265                                         symname, tpnt->libname, _dl_reltypes(reloc_type));
266 #endif
267                         return 0;
268                 }
269         }
270
271 #if defined (__SUPPORT_LD_DEBUG__)
272         old_val = *reloc_addr;
273 #endif
274                 switch (reloc_type) {
275                         case R_386_NONE:
276                                 break;
277                         case R_386_32:
278                                 *reloc_addr += symbol_addr;
279                                 break;
280                         case R_386_PC32:
281                                 *reloc_addr += symbol_addr - (unsigned long) reloc_addr;
282                                 break;
283                         case R_386_GLOB_DAT:
284                         case R_386_JMP_SLOT:
285                                 *reloc_addr = symbol_addr;
286                                 break;
287                         case R_386_RELATIVE:
288                                 *reloc_addr += (unsigned long) tpnt->loadaddr;
289                                 break;
290                         case R_386_COPY:
291                                 /* handled later on */
292                                 break;
293                         default:
294                                 return -1; /*call _dl_exit(1) */
295                 }
296 #if defined (__SUPPORT_LD_DEBUG__)
297         if(_dl_debug_reloc && _dl_debug_detail)
298                 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
299 #endif
300
301         return 0;
302 }
303
304 static int
305 _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
306                    ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
307 {
308         int reloc_type;
309         unsigned long *reloc_addr;
310 #if defined (__SUPPORT_LD_DEBUG__)
311         unsigned long old_val;
312 #endif
313         (void)scope;
314         (void)symtab;
315         (void)strtab;
316
317         reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
318         reloc_type = ELF32_R_TYPE(rpnt->r_info);
319
320 #if defined (__SUPPORT_LD_DEBUG__)
321         old_val = *reloc_addr;
322 #endif
323                 switch (reloc_type) {
324                         case R_386_NONE:
325                                 break;
326                         case R_386_JMP_SLOT:
327                                 *reloc_addr += (unsigned long) tpnt->loadaddr;
328                                 break;
329                         default:
330                                 return -1; /*call _dl_exit(1) */
331                 }
332 #if defined (__SUPPORT_LD_DEBUG__)
333         if(_dl_debug_reloc && _dl_debug_detail)
334                 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
335 #endif
336         return 0;
337
338 }
339
340 /* This is done as a separate step, because there are cases where
341    information is first copied and later initialized.  This results in
342    the wrong information being copied.  Someone at Sun was complaining about
343    a bug in the handling of _COPY by SVr4, and this may in fact be what he
344    was talking about.  Sigh. */
345
346 /* No, there are cases where the SVr4 linker fails to emit COPY relocs
347    at all */
348 static int
349 _dl_do_copy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
350              ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
351 {
352         int reloc_type;
353         int symtab_index;
354         unsigned long *reloc_addr;
355         unsigned long symbol_addr;
356         int goof = 0;
357         char *symname;
358
359         reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
360         reloc_type = ELF32_R_TYPE(rpnt->r_info);
361         if (reloc_type != R_386_COPY)
362                 return 0;
363         symtab_index = ELF32_R_SYM(rpnt->r_info);
364         symbol_addr = 0;
365         symname      = strtab + symtab[symtab_index].st_name;
366
367         if (symtab_index) {
368                 symbol_addr = (unsigned long) _dl_find_hash(symname, scope, ELF_RTYPE_CLASS_COPY);
369                 if (!symbol_addr) goof++;
370         }
371         if (!goof) {
372 #if defined (__SUPPORT_LD_DEBUG__)
373                 if(_dl_debug_move)
374                   _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
375                              symname, symtab[symtab_index].st_size,
376                              symbol_addr, symtab[symtab_index].st_value);
377 #endif
378                 _dl_memcpy((char *) symtab[symtab_index].st_value,
379                         (char *) symbol_addr, symtab[symtab_index].st_size);
380         }
381
382         return goof;
383 }
384
385 void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
386         unsigned long rel_addr, unsigned long rel_size, int type)
387 {
388         (void)_dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
389 }
390
391 int _dl_parse_relocation_information(struct dyn_elf *rpnt,
392         unsigned long rel_addr, unsigned long rel_size, int type)
393 {
394         return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
395 }
396
397 int _dl_parse_copy_information(struct dyn_elf *rpnt,
398         unsigned long rel_addr, unsigned long rel_size, int type)
399 {
400         return _dl_parse(rpnt->dyn, rpnt->next, rel_addr, rel_size, _dl_do_copy_reloc);
401 }
402