OSDN Git Service

423ae190a83f7622a7f3648027c2b1b32e842459
[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 int _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, tpnt, 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 *arg_rpnt,
150         unsigned long rel_addr, unsigned long rel_size)
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 = arg_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     switch(reloc_type){
173     case R_SPARC_NONE:
174       break;
175     case R_SPARC_JMP_SLOT:
176       break;
177     default:
178       _dl_dprintf(2, "%s: (LAZY) can't handle reloc type ", _dl_progname);
179 #if defined (__SUPPORT_LD_DEBUG__)
180       _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
181 #endif
182       if(symtab_index) _dl_dprintf(2, "'%s'\n",
183                                   strtab + symtab[symtab_index].st_name);
184       _dl_exit(33);
185     };
186   };
187 }
188
189 int _dl_parse_relocation_information(struct dyn_elf *arg_rpnt,
190         unsigned long rel_addr, unsigned long rel_size)
191 {
192   int i;
193   char * strtab;
194   int reloc_type;
195   int goof = 0;
196   Elf32_Sym * symtab;
197   Elf32_Rela * rpnt;
198   unsigned int * reloc_addr;
199   unsigned int symbol_addr;
200   int symtab_index;
201   struct elf_resolve * tpnt = arg_rpnt->dyn;
202   /* Now parse the relocation information */
203
204   rpnt = (Elf32_Rela *) (rel_addr + tpnt->loadaddr);
205
206   symtab =  (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
207   strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
208
209   for(i=0; i< rel_size; i+= sizeof(Elf32_Rela), rpnt++){
210     reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
211     reloc_type = ELF32_R_TYPE(rpnt->r_info);
212     symtab_index = ELF32_R_SYM(rpnt->r_info);
213     symbol_addr = 0;
214
215     if(symtab_index) {
216
217       symbol_addr = (unsigned int)
218         _dl_find_hash(strtab + symtab[symtab_index].st_name,
219                       tpnt->symbol_scope, tpnt, elf_machine_type_class(reloc_type));
220
221       if(!symbol_addr &&
222          ELF32_ST_BIND(symtab [symtab_index].st_info) != STB_WEAK) {
223                         _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
224                                      _dl_progname, strtab + symtab[symtab_index].st_name);
225                         _dl_exit (1);
226       };
227     };
228     switch(reloc_type){
229     case R_SPARC_NONE:
230         break;
231     case R_SPARC_32:
232       *reloc_addr = symbol_addr + rpnt->r_addend;
233       break;
234     case R_SPARC_DISP32:
235       *reloc_addr = symbol_addr + rpnt->r_addend - (unsigned int) reloc_addr;
236       break;
237     case R_SPARC_GLOB_DAT:
238       *reloc_addr = symbol_addr + rpnt->r_addend;
239       break;
240     case R_SPARC_JMP_SLOT:
241       reloc_addr[1] = 0x03000000 | ((symbol_addr >> 10) & 0x3fffff);
242       reloc_addr[2] = 0x81c06000 | (symbol_addr & 0x3ff);
243       break;
244     case R_SPARC_RELATIVE:
245       *reloc_addr += (unsigned int) tpnt->loadaddr + rpnt->r_addend;
246       break;
247     case R_SPARC_HI22:
248       if (!symbol_addr)
249         symbol_addr = tpnt->loadaddr + rpnt->r_addend;
250       else
251         symbol_addr += rpnt->r_addend;
252       *reloc_addr = (*reloc_addr & 0xffc00000)|(symbol_addr >> 10);
253       break;
254     case R_SPARC_LO10:
255       if (!symbol_addr)
256         symbol_addr = tpnt->loadaddr + rpnt->r_addend;
257       else
258         symbol_addr += rpnt->r_addend;
259       *reloc_addr = (*reloc_addr & ~0x3ff)|(symbol_addr & 0x3ff);
260       break;
261     case R_SPARC_WDISP30:
262       *reloc_addr = (*reloc_addr & 0xc0000000)|
263         ((symbol_addr - (unsigned int) reloc_addr) >> 2);
264       break;
265     case R_SPARC_COPY:
266       _dl_memcpy((void *) reloc_addr, (void *) symbol_addr, symtab[symtab_index].st_size);
267       break;
268     default:
269       _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
270 #if defined (__SUPPORT_LD_DEBUG__)
271       _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
272 #endif
273       if (symtab_index)
274         _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
275       _dl_exit(34);
276     };
277
278   };
279   return goof;
280 }