OSDN Git Service

98435cbd4384a4b6c9d5d6db739e6f54c3ce69ca
[uclinux-h8/uClibc.git] / ldso / ldso / sparc / elfinterp.c
1 /* vi: set sw=4 ts=4: */
2 /* sparc 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  *
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. The name of the above contributors may not be
15  *    used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 #if defined (__SUPPORT_LD_DEBUG__)
32 static const char * _dl_reltypes[] = { "R_SPARC_NONE", "R_SPARC_8",
33   "R_SPARC_16", "R_SPARC_32", "R_SPARC_DISP8", "R_SPARC_DISP16",
34   "R_SPARC_DISP32", "R_SPARC_WDISP30", "R_SPARC_WDISP22",
35   "R_SPARC_HI22", "R_SPARC_22", "R_SPARC_13", "R_SPARC_LO10",
36   "R_SPARC_GOT10", "R_SPARC_GOT13", "R_SPARC_GOT22", "R_SPARC_PC10",
37   "R_SPARC_PC22", "R_SPARC_WPLT30", "R_SPARC_COPY",
38   "R_SPARC_GLOB_DAT", "R_SPARC_JMP_SLOT", "R_SPARC_RELATIVE",
39   "R_SPARC_UA32"};
40 #endif
41
42 /* Program to load an ELF binary on a linux system, and run it.
43 References to symbols in sharable libraries can be resolved by either
44 an ELF sharable library or a linux style of shared library. */
45
46 /* Disclaimer:  I have never seen any AT&T source code for SVr4, nor have
47    I ever taken any courses on internals.  This program was developed using
48    information available through the book "UNIX SYSTEM V RELEASE 4,
49    Programmers guide: Ansi C and Programming Support Tools", which did
50    a more than adequate job of explaining everything required to get this
51    working. */
52
53 extern _dl_linux_resolve(void);
54
55 unsigned int _dl_linux_resolver(unsigned int reloc_entry, unsigned int * plt)
56 {
57   int reloc_type;
58   Elf32_Rela * this_reloc;
59   char * strtab;
60   Elf32_Sym * symtab;
61   Elf32_Rela * rel_addr;
62   struct elf_resolve * tpnt;
63   int symtab_index;
64   char * new_addr;
65   char ** got_addr;
66   unsigned int instr_addr;
67   tpnt = (struct elf_resolve *) plt[2];
68
69   rel_addr = (Elf32_Rela *) (tpnt->dynamic_info[DT_JMPREL] +
70                                    tpnt->loadaddr);
71
72   /*
73    * Generate the correct relocation index into the .rela.plt section.
74    */
75   reloc_entry = (reloc_entry >> 10) - 0xc;
76
77   this_reloc = (Elf32_Rela *) ((char *) rel_addr + reloc_entry);
78
79   reloc_type = ELF32_R_TYPE(this_reloc->r_info);
80   symtab_index = ELF32_R_SYM(this_reloc->r_info);
81
82   symtab =  (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
83   strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
84
85 #ifdef __SUPPORT_LD_DEBUG__
86   if (_dl_debug_symbols) {
87   _dl_dprintf(2, "tpnt = %x\n", tpnt);
88   _dl_dprintf(2, "reloc = %x\n", this_reloc);
89   _dl_dprintf(2, "symtab = %x\n", symtab);
90   _dl_dprintf(2, "strtab = %x\n", strtab);
91   }
92 #endif
93
94
95   if (unlikely(reloc_type != R_SPARC_JMP_SLOT)) {
96     _dl_dprintf(2, "%s: incorrect relocation type in jump relocations (%d)\n",
97                   _dl_progname, reloc_type);
98     _dl_exit(30);
99   };
100
101   /* Address of jump instruction to fix up */
102   instr_addr  = ((int)this_reloc->r_offset  + (int)tpnt->loadaddr);
103   got_addr = (char **) instr_addr;
104
105 #ifdef __SUPPORT_LD_DEBUG__
106   if (_dl_debug_symbols) {
107   _dl_dprintf(2, "symtab_index %x\n", symtab_index);
108
109           _dl_dprintf(2, "Resolving symbol %s\n",
110                           strtab + symtab[symtab_index].st_name);
111   }
112 #endif
113
114   /* Get the address of the GOT entry */
115   new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name,
116                         tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
117   if(unlikely(!new_addr)) {
118     _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
119                _dl_progname, strtab + symtab[symtab_index].st_name);
120     _dl_exit(31);
121   };
122
123 #if defined (__SUPPORT_LD_DEBUG__)
124         if ((unsigned long) got_addr < 0x40000000)
125         {
126                 if (_dl_debug_bindings)
127                 {
128                         _dl_dprintf(_dl_debug_file, "\nresolve function: %s",
129                                         strtab + symtab[symtab_index].st_name);
130                         if(_dl_debug_detail) _dl_dprintf(_dl_debug_file,
131                                         "\tpatch %x ==> %x @ %x", *got_addr, new_addr, got_addr);
132                 }
133         }
134         if (!_dl_debug_nofixups) {
135                 got_addr[1] = (char *) (0x03000000 | (((unsigned int) new_addr >> 10) & 0x3fffff));
136                 got_addr[2] = (char *) (0x81c06000 | ((unsigned int) new_addr & 0x3ff));
137         }
138 #else
139         got_addr[1] = (char *) (0x03000000 | (((unsigned int) new_addr >> 10) & 0x3fffff));
140         got_addr[2] = (char *) (0x81c06000 | ((unsigned int) new_addr & 0x3ff));
141 #endif
142
143         _dl_dprintf(2, "Address = %x\n",new_addr);
144         _dl_exit(32);
145
146   return (unsigned int) new_addr;
147 }
148
149 void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
150         unsigned long rel_addr, unsigned long rel_size, int type)
151 {
152   int i;
153   char * strtab;
154   int reloc_type;
155   int symtab_index;
156   Elf32_Sym * symtab;
157   Elf32_Rela * rpnt;
158   unsigned int * reloc_addr;
159   struct elf_resolve * tpnt = rpnt->dyn;
160
161   /* Now parse the relocation information */
162   rpnt = (Elf32_Rela *) (rel_addr + tpnt->loadaddr);
163
164   symtab =  (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
165   strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
166
167   for(i=0; i< rel_size; i += sizeof(Elf32_Rela), rpnt++){
168     reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
169     reloc_type = ELF32_R_TYPE(rpnt->r_info);
170     symtab_index = ELF32_R_SYM(rpnt->r_info);
171
172     /* When the dynamic linker bootstrapped itself, it resolved some symbols.
173        Make sure we do not do them again */
174     if(!symtab_index && tpnt->libtype == program_interpreter) continue;
175     if(symtab_index && tpnt->libtype == program_interpreter &&
176        _dl_symbol(strtab + symtab[symtab_index].st_name))
177       continue;
178
179     switch(reloc_type){
180     case R_SPARC_NONE:
181       break;
182     case R_SPARC_JMP_SLOT:
183       break;
184     default:
185       _dl_dprintf(2, "%s: (LAZY) can't handle reloc type ", _dl_progname);
186 #if defined (__SUPPORT_LD_DEBUG__)
187       _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
188 #endif
189       if(symtab_index) _dl_dprintf(2, "'%s'\n",
190                                   strtab + symtab[symtab_index].st_name);
191       _dl_exit(33);
192     };
193   };
194 }
195
196 int _dl_parse_relocation_information(struct dyn_elf *rpnt,
197         unsigned long rel_addr, unsigned long rel_size, int type)
198 {
199   int i;
200   char * strtab;
201   int reloc_type;
202   int goof = 0;
203   Elf32_Sym * symtab;
204   Elf32_Rela * rpnt;
205   unsigned int * reloc_addr;
206   unsigned int symbol_addr;
207   int symtab_index;
208   struct elf_resolve * tpnt = rpnt->dyn;
209   /* Now parse the relocation information */
210
211   rpnt = (Elf32_Rela *) (rel_addr + tpnt->loadaddr);
212
213   symtab =  (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
214   strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
215
216   for(i=0; i< rel_size; i+= sizeof(Elf32_Rela), rpnt++){
217     reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
218     reloc_type = ELF32_R_TYPE(rpnt->r_info);
219     symtab_index = ELF32_R_SYM(rpnt->r_info);
220     symbol_addr = 0;
221
222     if(!symtab_index && tpnt->libtype == program_interpreter) continue;
223
224     if(symtab_index) {
225
226       if(tpnt->libtype == program_interpreter &&
227          _dl_symbol(strtab + symtab[symtab_index].st_name))
228         continue;
229
230       symbol_addr = (unsigned int)
231         _dl_find_hash(strtab + symtab[symtab_index].st_name,
232                       tpnt->symbol_scope, elf_machine_type_class(reloc_type));
233
234       if(!symbol_addr &&
235          ELF32_ST_BIND(symtab [symtab_index].st_info) == STB_GLOBAL) {
236         _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
237                      _dl_progname, strtab + symtab[symtab_index].st_name);
238         goof++;
239       };
240     };
241     switch(reloc_type){
242     case R_SPARC_NONE:
243         break;
244     case R_SPARC_32:
245       *reloc_addr = symbol_addr + rpnt->r_addend;
246       break;
247     case R_SPARC_DISP32:
248       *reloc_addr = symbol_addr + rpnt->r_addend - (unsigned int) reloc_addr;
249       break;
250     case R_SPARC_GLOB_DAT:
251       *reloc_addr = symbol_addr + rpnt->r_addend;
252       break;
253     case R_SPARC_JMP_SLOT:
254       reloc_addr[1] = 0x03000000 | ((symbol_addr >> 10) & 0x3fffff);
255       reloc_addr[2] = 0x81c06000 | (symbol_addr & 0x3ff);
256       break;
257     case R_SPARC_RELATIVE:
258       *reloc_addr += (unsigned int) tpnt->loadaddr + rpnt->r_addend;
259       break;
260     case R_SPARC_HI22:
261       if (!symbol_addr)
262         symbol_addr = tpnt->loadaddr + rpnt->r_addend;
263       else
264         symbol_addr += rpnt->r_addend;
265       *reloc_addr = (*reloc_addr & 0xffc00000)|(symbol_addr >> 10);
266       break;
267     case R_SPARC_LO10:
268       if (!symbol_addr)
269         symbol_addr = tpnt->loadaddr + rpnt->r_addend;
270       else
271         symbol_addr += rpnt->r_addend;
272       *reloc_addr = (*reloc_addr & ~0x3ff)|(symbol_addr & 0x3ff);
273       break;
274     case R_SPARC_WDISP30:
275       *reloc_addr = (*reloc_addr & 0xc0000000)|
276         ((symbol_addr - (unsigned int) reloc_addr) >> 2);
277       break;
278     case R_SPARC_COPY:
279 #if 0 /* This one is done later */
280       _dl_dprintf(2, "Doing copy for symbol ");
281       if(symtab_index) _dl_dprintf(2, strtab + symtab[symtab_index].st_name);
282       _dl_dprintf(2, "\n");
283       _dl_memcpy((void *) symtab[symtab_index].st_value,
284                  (void *) symbol_addr,
285                  symtab[symtab_index].st_size);
286 #endif
287       break;
288     default:
289       _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
290 #if defined (__SUPPORT_LD_DEBUG__)
291       _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
292 #endif
293       if (symtab_index)
294         _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
295       _dl_exit(34);
296     };
297
298   };
299   return goof;
300 }
301
302
303 /* This is done as a separate step, because there are cases where
304    information is first copied and later initialized.  This results in
305    the wrong information being copied.  Someone at Sun was complaining about
306    a bug in the handling of _COPY by SVr4, and this may in fact be what he
307    was talking about.  Sigh. */
308
309 /* No, there are cases where the SVr4 linker fails to emit COPY relocs
310    at all */
311
312 int _dl_parse_copy_information(struct dyn_elf *xpnt,
313         unsigned long rel_addr, unsigned long rel_size, int type)
314 {
315   int i;
316   char * strtab;
317   int reloc_type;
318   int goof = 0;
319   Elf32_Sym * symtab;
320   Elf32_Rela * rpnt;
321   unsigned int * reloc_addr;
322   unsigned int symbol_addr;
323   struct elf_resolve *tpnt;
324   int symtab_index;
325   /* Now parse the relocation information */
326
327   tpnt = xpnt->dyn;
328
329   rpnt = (Elf32_Rela *) (rel_addr + tpnt->loadaddr);
330
331   symtab =  (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
332   strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
333
334   for(i=0; i< rel_size; i+= sizeof(Elf32_Rela), rpnt++){
335     reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
336     reloc_type = ELF32_R_TYPE(rpnt->r_info);
337     if(reloc_type != R_SPARC_COPY) continue;
338     symtab_index = ELF32_R_SYM(rpnt->r_info);
339     symbol_addr = 0;
340     if(!symtab_index && tpnt->libtype == program_interpreter) continue;
341     if(symtab_index) {
342
343       if(tpnt->libtype == program_interpreter &&
344          _dl_symbol(strtab + symtab[symtab_index].st_name))
345         continue;
346
347       symbol_addr = (unsigned int)
348         _dl_find_hash(strtab + symtab[symtab_index].st_name,
349                       xpnt->next,  ELF_RTYPE_CLASS_COPY);
350       if(!symbol_addr) {
351         _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
352                    _dl_progname, strtab + symtab[symtab_index].st_name);
353         goof++;
354       };
355     };
356     if (!goof)
357       _dl_memcpy((char *) symtab[symtab_index].st_value,
358                   (char *) symbol_addr,
359                   symtab[symtab_index].st_size);
360   };
361   return goof;
362 }
363
364