OSDN Git Service

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