OSDN Git Service

Moved the addition of load address from the fast path
[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
71   /*
72    * Generate the correct relocation index into the .rela.plt section.
73    */
74   reloc_entry = (reloc_entry >> 10) - 0xc;
75
76   this_reloc = (Elf32_Rela *) ((char *) rel_addr + reloc_entry);
77
78   reloc_type = ELF32_R_TYPE(this_reloc->r_info);
79   symtab_index = ELF32_R_SYM(this_reloc->r_info);
80
81   symtab =  (Elf32_Sym *)tpnt->dynamic_info[DT_SYMTAB];
82   strtab = (char *)tpnt->dynamic_info[DT_STRTAB];
83
84 #ifdef __SUPPORT_LD_DEBUG__
85   if (_dl_debug_symbols) {
86   _dl_dprintf(2, "tpnt = %x\n", tpnt);
87   _dl_dprintf(2, "reloc = %x\n", this_reloc);
88   _dl_dprintf(2, "symtab = %x\n", symtab);
89   _dl_dprintf(2, "strtab = %x\n", strtab);
90   }
91 #endif
92
93
94   if (unlikely(reloc_type != R_SPARC_JMP_SLOT)) {
95     _dl_dprintf(2, "%s: incorrect relocation type in jump relocations (%d)\n",
96                   _dl_progname, reloc_type);
97     _dl_exit(30);
98   };
99
100   /* Address of jump instruction to fix up */
101   instr_addr  = ((int)this_reloc->r_offset  + (int)tpnt->loadaddr);
102   got_addr = (char **) instr_addr;
103
104 #ifdef __SUPPORT_LD_DEBUG__
105   if (_dl_debug_symbols) {
106   _dl_dprintf(2, "symtab_index %x\n", symtab_index);
107
108           _dl_dprintf(2, "Resolving symbol %s\n",
109                           strtab + symtab[symtab_index].st_name);
110   }
111 #endif
112
113   /* Get the address of the GOT entry */
114   new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name,
115                         tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT);
116   if(unlikely(!new_addr)) {
117     _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
118                _dl_progname, strtab + symtab[symtab_index].st_name);
119     _dl_exit(31);
120   };
121
122 #if defined (__SUPPORT_LD_DEBUG__)
123         if ((unsigned long) got_addr < 0x40000000)
124         {
125                 if (_dl_debug_bindings)
126                 {
127                         _dl_dprintf(_dl_debug_file, "\nresolve function: %s",
128                                         strtab + symtab[symtab_index].st_name);
129                         if(_dl_debug_detail) _dl_dprintf(_dl_debug_file,
130                                         "\tpatch %x ==> %x @ %x", *got_addr, new_addr, got_addr);
131                 }
132         }
133         if (!_dl_debug_nofixups) {
134                 got_addr[1] = (char *) (0x03000000 | (((unsigned int) new_addr >> 10) & 0x3fffff));
135                 got_addr[2] = (char *) (0x81c06000 | ((unsigned int) new_addr & 0x3ff));
136         }
137 #else
138         got_addr[1] = (char *) (0x03000000 | (((unsigned int) new_addr >> 10) & 0x3fffff));
139         got_addr[2] = (char *) (0x81c06000 | ((unsigned int) new_addr & 0x3ff));
140 #endif
141
142         _dl_dprintf(2, "Address = %x\n",new_addr);
143         _dl_exit(32);
144
145   return (unsigned int) new_addr;
146 }
147
148 void _dl_parse_lazy_relocation_information(struct dyn_elf *arg_rpnt,
149         unsigned long rel_addr, unsigned long rel_size)
150 {
151   int i;
152   char * strtab;
153   int reloc_type;
154   int symtab_index;
155   Elf32_Sym * symtab;
156   Elf32_Rela * rpnt;
157   unsigned int * reloc_addr;
158   struct elf_resolve * tpnt = arg_rpnt->dyn;
159
160   /* Now parse the relocation information */
161   rpnt = (Elf32_Rela *)rel_addr;
162
163   symtab =  (Elf32_Sym *)tpnt->dynamic_info[DT_SYMTAB];
164   strtab = ( char *)tpnt->dynamic_info[DT_STRTAB];
165
166   for(i=0; i< rel_size; i += sizeof(Elf32_Rela), rpnt++){
167     reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
168     reloc_type = ELF32_R_TYPE(rpnt->r_info);
169     symtab_index = ELF32_R_SYM(rpnt->r_info);
170
171     switch(reloc_type){
172     case R_SPARC_NONE:
173       break;
174     case R_SPARC_JMP_SLOT:
175       break;
176     default:
177       _dl_dprintf(2, "%s: (LAZY) can't handle reloc type ", _dl_progname);
178 #if defined (__SUPPORT_LD_DEBUG__)
179       _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
180 #endif
181       if(symtab_index) _dl_dprintf(2, "'%s'\n",
182                                   strtab + symtab[symtab_index].st_name);
183       _dl_exit(33);
184     };
185   };
186 }
187
188 int _dl_parse_relocation_information(struct dyn_elf *arg_rpnt,
189         unsigned long rel_addr, unsigned long rel_size)
190 {
191   int i;
192   char * strtab;
193   int reloc_type;
194   int goof = 0;
195   Elf32_Sym * symtab;
196   Elf32_Rela * rpnt;
197   unsigned int * reloc_addr;
198   unsigned int symbol_addr;
199   int symtab_index;
200   struct elf_resolve * tpnt = arg_rpnt->dyn;
201   /* Now parse the relocation information */
202
203   rpnt = (Elf32_Rela *)rel_addr;
204
205   symtab =  (Elf32_Sym *)tpnt->dynamic_info[DT_SYMTAB];
206   strtab = ( char *)tpnt->dynamic_info[DT_STRTAB];
207
208   for(i=0; i< rel_size; i+= sizeof(Elf32_Rela), rpnt++){
209     reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
210     reloc_type = ELF32_R_TYPE(rpnt->r_info);
211     symtab_index = ELF32_R_SYM(rpnt->r_info);
212     symbol_addr = 0;
213
214     if(symtab_index) {
215
216       symbol_addr = (unsigned int)
217         _dl_find_hash(strtab + symtab[symtab_index].st_name,
218                       tpnt->symbol_scope, tpnt, elf_machine_type_class(reloc_type));
219
220       if(!symbol_addr &&
221          ELF32_ST_BIND(symtab [symtab_index].st_info) != STB_WEAK) {
222                         _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
223                                      _dl_progname, strtab + symtab[symtab_index].st_name);
224                         _dl_exit (1);
225       };
226     };
227     switch(reloc_type){
228     case R_SPARC_NONE:
229         break;
230     case R_SPARC_32:
231       *reloc_addr = symbol_addr + rpnt->r_addend;
232       break;
233     case R_SPARC_DISP32:
234       *reloc_addr = symbol_addr + rpnt->r_addend - (unsigned int) reloc_addr;
235       break;
236     case R_SPARC_GLOB_DAT:
237       *reloc_addr = symbol_addr + rpnt->r_addend;
238       break;
239     case R_SPARC_JMP_SLOT:
240       reloc_addr[1] = 0x03000000 | ((symbol_addr >> 10) & 0x3fffff);
241       reloc_addr[2] = 0x81c06000 | (symbol_addr & 0x3ff);
242       break;
243     case R_SPARC_RELATIVE:
244       *reloc_addr += (unsigned int) tpnt->loadaddr + rpnt->r_addend;
245       break;
246     case R_SPARC_HI22:
247       if (!symbol_addr)
248         symbol_addr = tpnt->loadaddr + rpnt->r_addend;
249       else
250         symbol_addr += rpnt->r_addend;
251       *reloc_addr = (*reloc_addr & 0xffc00000)|(symbol_addr >> 10);
252       break;
253     case R_SPARC_LO10:
254       if (!symbol_addr)
255         symbol_addr = tpnt->loadaddr + rpnt->r_addend;
256       else
257         symbol_addr += rpnt->r_addend;
258       *reloc_addr = (*reloc_addr & ~0x3ff)|(symbol_addr & 0x3ff);
259       break;
260     case R_SPARC_WDISP30:
261       *reloc_addr = (*reloc_addr & 0xc0000000)|
262         ((symbol_addr - (unsigned int) reloc_addr) >> 2);
263       break;
264     case R_SPARC_COPY:
265       _dl_memcpy((void *) reloc_addr, (void *) symbol_addr, symtab[symtab_index].st_size);
266       break;
267     default:
268       _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
269 #if defined (__SUPPORT_LD_DEBUG__)
270       _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
271 #endif
272       if (symtab_index)
273         _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
274       _dl_exit(34);
275     };
276
277   };
278   return goof;
279 }