OSDN Git Service

1bcbec389efc2f0da5ed754f7c7062e951c4ca1d
[uclinux-h8/uClibc.git] / ldso / ldso / m68k / elfinterp.c
1 /* vi: set sw=4 ts=4: */
2 /* m68k 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  * Adapted to ELF/68k by Andreas Schwab.
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[] =
34 {
35   "R_68K_NONE",
36   "R_68K_32", "R_68K_16", "R_68K_8",
37   "R_68K_PC32", "R_68K_PC16", "R_68K_PC8",
38   "R_68K_GOT32", "R_68K_GOT16", "R_68K_GOT8",
39   "R_68K_GOT32O", "R_68K_GOT16O", "R_68K_GOT8O",
40   "R_68K_PLT32", "R_68K_PLT16", "R_68K_PLT8",
41   "R_68K_PLT32O", "R_68K_PLT16O", "R_68K_PLT8O",
42   "R_68K_COPY", "R_68K_GLOB_DAT", "R_68K_JMP_SLOT", "R_68K_RELATIVE",
43   "R_68K_NUM"
44 };
45 #endif
46
47 /* Program to load an ELF binary on a linux system, and run it.
48    References to symbols in sharable libraries can be resolved by either
49    an ELF sharable library or a linux style of shared library. */
50
51 /* Disclaimer:  I have never seen any AT&T source code for SVr4, nor have
52    I ever taken any courses on internals.  This program was developed using
53    information available through the book "UNIX SYSTEM V RELEASE 4,
54    Programmers guide: Ansi C and Programming Support Tools", which did
55    a more than adequate job of explaining everything required to get this
56    working. */
57
58
59 unsigned int _dl_linux_resolver (int dummy1, int dummy2,
60         struct elf_resolve *tpnt, int reloc_entry)
61 {
62   int reloc_type;
63   Elf32_Rela *this_reloc;
64   char *strtab;
65   Elf32_Sym *symtab;
66   char *rel_addr;
67   int symtab_index;
68   char *new_addr;
69   char **got_addr;
70   unsigned int instr_addr;
71
72   rel_addr = tpnt->loadaddr + tpnt->dynamic_info[DT_JMPREL];
73   this_reloc = (Elf32_Rela *) (rel_addr + reloc_entry);
74   reloc_type = ELF32_R_TYPE (this_reloc->r_info);
75   symtab_index = ELF32_R_SYM (this_reloc->r_info);
76
77   symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB]
78                                  + tpnt->loadaddr);
79   strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
80
81
82   if (reloc_type != R_68K_JMP_SLOT)
83     {
84       _dl_dprintf (2, "%s: incorrect relocation type in jump relocations\n",
85                     _dl_progname);
86       _dl_exit (1);
87     }
88
89   /* Address of jump instruction to fix up.  */
90   instr_addr = (int) this_reloc->r_offset + (int) tpnt->loadaddr;
91   got_addr = (char **) instr_addr;
92
93 #ifdef __SUPPORT_LD_DEBUG__
94   if (_dl_debug_symbols) {
95           _dl_dprintf (2, "Resolving symbol %s\n", strtab + symtab[symtab_index].st_name);
96   }
97 #endif
98
99   /* Get the address of the GOT entry.  */
100   new_addr = _dl_find_hash (strtab + symtab[symtab_index].st_name,
101                             tpnt->symbol_scope, tpnt, resolver);
102   if (!new_addr)
103     {
104       _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
105                     _dl_progname, strtab + symtab[symtab_index].st_name);
106       _dl_exit (1);
107     }
108 #if defined (__SUPPORT_LD_DEBUG__)
109         if ((unsigned long) got_addr < 0x40000000)
110         {
111                 if (_dl_debug_bindings)
112                 {
113                         _dl_dprintf(_dl_debug_file, "\nresolve function: %s",
114                                         strtab + symtab[symtab_index].st_name);
115                         if(_dl_debug_detail) _dl_dprintf(_dl_debug_file,
116                                         "\tpatch %x ==> %x @ %x", *got_addr, new_addr, got_addr);
117                 }
118         }
119         if (!_dl_debug_nofixups) {
120                 *got_addr = new_addr;
121         }
122 #else
123         *got_addr = new_addr;
124 #endif
125
126   return (unsigned int) new_addr;
127 }
128
129 void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
130         unsigned long rel_addr, unsigned long rel_size, int type)
131 {
132   int i;
133   char *strtab;
134   int reloc_type;
135   int symtab_index;
136   Elf32_Sym *symtab;
137   Elf32_Rela *rpnt;
138   unsigned int *reloc_addr;
139   struct elf_resolve *tpnt = rpnt->dyn;
140
141   /* Now parse the relocation information.  */
142   rpnt = (Elf32_Rela *) (rel_addr + tpnt->loadaddr);
143   rel_size = rel_size / sizeof (Elf32_Rela);
144
145   symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB]
146                                  + tpnt->loadaddr);
147   strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
148
149   for (i = 0; i < rel_size; i++, rpnt++)
150     {
151       reloc_addr = (int *) (tpnt->loadaddr + (int) rpnt->r_offset);
152       reloc_type = ELF32_R_TYPE (rpnt->r_info);
153       symtab_index = ELF32_R_SYM (rpnt->r_info);
154
155       /* When the dynamic linker bootstrapped itself, it resolved some symbols.
156          Make sure we do not do them again.  */
157       if (tpnt->libtype == program_interpreter
158           && (!symtab_index
159               || _dl_symbol (strtab + symtab[symtab_index].st_name)))
160         continue;
161
162       switch (reloc_type)
163         {
164         case R_68K_NONE:
165           break;
166         case R_68K_JMP_SLOT:
167           *reloc_addr += (unsigned int) tpnt->loadaddr;
168           break;
169         default:
170           _dl_dprintf (2, "%s: (LAZY) can't handle reloc type ", _dl_progname);
171 #if defined (__SUPPORT_LD_DEBUG__)
172           _dl_dprintf (2, "%s ", _dl_reltypes[reloc_type]);
173 #endif
174           if (symtab_index)
175             _dl_dprintf (2, "'%s'", strtab + symtab[symtab_index].st_name);
176           _dl_dprintf (2, "\n");
177           _dl_exit (1);
178         }
179     }
180 }
181
182 int _dl_parse_relocation_information(struct dyn_elf *rpnt,
183         unsigned long rel_addr, unsigned long rel_size, int type)
184 {
185   int i;
186   char *strtab;
187   int reloc_type;
188   int goof = 0;
189   Elf32_Sym *symtab;
190   Elf32_Rela *rpnt;
191   unsigned int *reloc_addr;
192   unsigned int symbol_addr;
193   int symtab_index;
194   struct elf_resolve *tpnt = rpnt->dyn;
195   /* Now parse the relocation information */
196
197   rpnt = (Elf32_Rela *) (rel_addr + tpnt->loadaddr);
198   rel_size = rel_size / sizeof (Elf32_Rela);
199
200   symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB]
201                                  + tpnt->loadaddr);
202   strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
203
204   for (i = 0; i < rel_size; i++, rpnt++)
205     {
206       reloc_addr = (int *) (tpnt->loadaddr + (int) rpnt->r_offset);
207       reloc_type = ELF32_R_TYPE (rpnt->r_info);
208       symtab_index = ELF32_R_SYM (rpnt->r_info);
209       symbol_addr = 0;
210
211       if (tpnt->libtype == program_interpreter
212           && (!symtab_index
213               || _dl_symbol (strtab + symtab[symtab_index].st_name)))
214         continue;
215
216       if (symtab_index)
217         {
218           symbol_addr = (unsigned int)
219             _dl_find_hash (strtab + symtab[symtab_index].st_name,
220                            tpnt->symbol_scope,
221                            reloc_type == R_68K_JMP_SLOT ? tpnt : NULL, symbolrel);
222
223           /* We want to allow undefined references to weak symbols -
224              this might have been intentional.  We should not be
225              linking local symbols here, so all bases should be
226              covered.  */
227           if (!symbol_addr
228               && ELF32_ST_BIND (symtab[symtab_index].st_info) == STB_GLOBAL)
229             {
230               _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
231                             _dl_progname, strtab + symtab[symtab_index].st_name);
232               goof++;
233             }
234         }
235       switch (reloc_type)
236         {
237         case R_68K_NONE:
238           break;
239         case R_68K_8:
240           *(char *) reloc_addr = symbol_addr + rpnt->r_addend;
241           break;
242         case R_68K_16:
243           *(short *) reloc_addr = symbol_addr + rpnt->r_addend;
244           break;
245         case R_68K_32:
246           *reloc_addr = symbol_addr + rpnt->r_addend;
247           break;
248         case R_68K_PC8:
249           *(char *) reloc_addr = (symbol_addr + rpnt->r_addend
250                                   - (unsigned int) reloc_addr);
251           break;
252         case R_68K_PC16:
253           *(short *) reloc_addr = (symbol_addr + rpnt->r_addend
254                                    - (unsigned int) reloc_addr);
255           break;
256         case R_68K_PC32:
257           *reloc_addr = (symbol_addr + rpnt->r_addend
258                          - (unsigned int) reloc_addr);
259           break;
260         case R_68K_GLOB_DAT:
261         case R_68K_JMP_SLOT:
262           *reloc_addr = symbol_addr;
263           break;
264         case R_68K_RELATIVE:
265           *reloc_addr = ((unsigned int) tpnt->loadaddr
266                          /* Compatibility kludge.  */
267                          + (rpnt->r_addend ? : *reloc_addr));
268           break;
269         case R_68K_COPY:
270 #if 0 /* Do this later.  */
271           _dl_dprintf (2, "Doing copy");
272           if (symtab_index)
273             _dl_dprintf (2, " for symbol %s",
274                           strtab + symtab[symtab_index].st_name);
275           _dl_dprintf (2, "\n");
276           _dl_memcpy ((void *) symtab[symtab_index].st_value,
277                       (void *) symbol_addr,
278                       symtab[symtab_index].st_size);
279 #endif
280           break;
281         default:
282           _dl_dprintf (2, "%s: can't handle reloc type ", _dl_progname);
283 #if defined (__SUPPORT_LD_DEBUG__)
284           _dl_dprintf (2, "%s ", _dl_reltypes[reloc_type]);
285 #endif
286           if (symtab_index)
287             _dl_dprintf (2, "'%s'", strtab + symtab[symtab_index].st_name);
288           _dl_dprintf (2, "\n");
289           _dl_exit (1);
290         }
291
292     }
293   return goof;
294 }
295
296 /* This is done as a separate step, because there are cases where
297    information is first copied and later initialized.  This results in
298    the wrong information being copied.  Someone at Sun was complaining about
299    a bug in the handling of _COPY by SVr4, and this may in fact be what he
300    was talking about.  Sigh.  */
301
302 /* No, there are cases where the SVr4 linker fails to emit COPY relocs
303    at all.  */
304
305 int _dl_parse_copy_information(struct dyn_elf *xpnt,
306         unsigned long rel_addr, unsigned long rel_size, int type)
307 {
308   int i;
309   char *strtab;
310   int reloc_type;
311   int goof = 0;
312   Elf32_Sym *symtab;
313   Elf32_Rela *rpnt;
314   unsigned int *reloc_addr;
315   unsigned int symbol_addr;
316   struct elf_resolve *tpnt;
317   int symtab_index;
318   /* Now parse the relocation information */
319
320   tpnt = xpnt->dyn;
321
322   rpnt = (Elf32_Rela *) (rel_addr + tpnt->loadaddr);
323   rel_size = rel_size / sizeof (Elf32_Rela);
324
325   symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB]
326                                  + tpnt->loadaddr);
327   strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
328
329   for (i = 0; i < rel_size; i++, rpnt++)
330     {
331       reloc_addr = (int *) (tpnt->loadaddr + (int) rpnt->r_offset);
332       reloc_type = ELF32_R_TYPE (rpnt->r_info);
333       if (reloc_type != R_68K_COPY)
334         continue;
335       symtab_index = ELF32_R_SYM (rpnt->r_info);
336       symbol_addr = 0;
337       if (tpnt->libtype == program_interpreter
338           && (!symtab_index
339               || _dl_symbol (strtab + symtab[symtab_index].st_name)))
340         continue;
341       if (symtab_index)
342         {
343           symbol_addr = (unsigned int)
344             _dl_find_hash (strtab + symtab[symtab_index].st_name,
345                            xpnt->next, NULL, copyrel);
346           if (!symbol_addr)
347             {
348               _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
349                             _dl_progname, strtab + symtab[symtab_index].st_name);
350               goof++;
351             }
352         }
353       if (!goof)
354       _dl_memcpy ((void *) symtab[symtab_index].st_value, (void *) symbol_addr,
355                   symtab[symtab_index].st_size);
356     }
357   return goof;
358 }