OSDN Git Service

Add RTLD_LOCAL support for dlopened libs. Reported by
[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 (unlikely(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, ELF_RTYPE_CLASS_PLT);
102   if (unlikely(!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)
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       switch (reloc_type)
156         {
157         case R_68K_NONE:
158           break;
159         case R_68K_JMP_SLOT:
160           *reloc_addr += (unsigned int) tpnt->loadaddr;
161           break;
162         default:
163           _dl_dprintf (2, "%s: (LAZY) can't handle reloc type ", _dl_progname);
164 #if defined (__SUPPORT_LD_DEBUG__)
165           _dl_dprintf (2, "%s ", _dl_reltypes[reloc_type]);
166 #endif
167           if (symtab_index)
168             _dl_dprintf (2, "'%s'", strtab + symtab[symtab_index].st_name);
169           _dl_dprintf (2, "\n");
170           _dl_exit (1);
171         }
172     }
173 }
174
175 int _dl_parse_relocation_information(struct dyn_elf *rpnt,
176         unsigned long rel_addr, unsigned long rel_size)
177 {
178   int i;
179   char *strtab;
180   int reloc_type;
181   int goof = 0;
182   Elf32_Sym *symtab;
183   Elf32_Rela *rpnt;
184   unsigned int *reloc_addr;
185   unsigned int symbol_addr;
186   int symtab_index;
187   struct elf_resolve *tpnt = rpnt->dyn;
188   /* Now parse the relocation information */
189
190   rpnt = (Elf32_Rela *) (rel_addr + tpnt->loadaddr);
191   rel_size = rel_size / sizeof (Elf32_Rela);
192
193   symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB]
194                                  + tpnt->loadaddr);
195   strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
196
197   for (i = 0; i < rel_size; i++, rpnt++)
198     {
199       reloc_addr = (int *) (tpnt->loadaddr + (int) rpnt->r_offset);
200       reloc_type = ELF32_R_TYPE (rpnt->r_info);
201       symtab_index = ELF32_R_SYM (rpnt->r_info);
202       symbol_addr = 0;
203       if (symtab_index)
204         {
205           symbol_addr = (unsigned int)
206             _dl_find_hash (strtab + symtab[symtab_index].st_name,
207                            tpnt->symbol_scope, tpnt,
208                            elf_machine_type_class(reloc_type));
209
210           /* We want to allow undefined references to weak symbols -
211              this might have been intentional.  We should not be
212              linking local symbols here, so all bases should be
213              covered.  */
214           if (!symbol_addr
215               && ELF32_ST_BIND (symtab[symtab_index].st_info) != STB_WEAK)
216             {
217                         _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
218                                      _dl_progname, strtab + symtab[symtab_index].st_name);
219                         _dl_exit (1);
220             }
221         }
222       switch (reloc_type)
223         {
224         case R_68K_NONE:
225           break;
226         case R_68K_8:
227           *(char *) reloc_addr = symbol_addr + rpnt->r_addend;
228           break;
229         case R_68K_16:
230           *(short *) reloc_addr = symbol_addr + rpnt->r_addend;
231           break;
232         case R_68K_32:
233           *reloc_addr = symbol_addr + rpnt->r_addend;
234           break;
235         case R_68K_PC8:
236           *(char *) reloc_addr = (symbol_addr + rpnt->r_addend
237                                   - (unsigned int) reloc_addr);
238           break;
239         case R_68K_PC16:
240           *(short *) reloc_addr = (symbol_addr + rpnt->r_addend
241                                    - (unsigned int) reloc_addr);
242           break;
243         case R_68K_PC32:
244           *reloc_addr = (symbol_addr + rpnt->r_addend
245                          - (unsigned int) reloc_addr);
246           break;
247         case R_68K_GLOB_DAT:
248         case R_68K_JMP_SLOT:
249           *reloc_addr = symbol_addr;
250           break;
251         case R_68K_RELATIVE:
252           *reloc_addr = ((unsigned int) tpnt->loadaddr
253                          /* Compatibility kludge.  */
254                          + (rpnt->r_addend ? : *reloc_addr));
255           break;
256         case R_68K_COPY:
257           _dl_memcpy ((void *) reloc_addr,
258                       (void *) symbol_addr,
259                       symtab[symtab_index].st_size);
260           break;
261         default:
262           _dl_dprintf (2, "%s: can't handle reloc type ", _dl_progname);
263 #if defined (__SUPPORT_LD_DEBUG__)
264           _dl_dprintf (2, "%s ", _dl_reltypes[reloc_type]);
265 #endif
266           if (symtab_index)
267             _dl_dprintf (2, "'%s'", strtab + symtab[symtab_index].st_name);
268           _dl_dprintf (2, "\n");
269           _dl_exit (1);
270         }
271
272     }
273   return goof;
274 }