OSDN Git Service

Moved the addition of load address from the fast path
[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
60 _dl_linux_resolver (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         ELF_RELOC *rel_addr;
67         int symtab_index;
68         char *new_addr;
69         char **got_addr;
70         unsigned int instr_addr;
71
72         rel_addr = (ELF_RELOC *)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         strtab = (char *)tpnt->dynamic_info[DT_STRTAB];
79
80         if (unlikely(reloc_type != R_68K_JMP_SLOT)) {
81                 _dl_dprintf (2, "%s: incorrect relocation type in jump relocations\n",
82                              _dl_progname);
83                 _dl_exit (1);
84         }
85
86         /* Address of jump instruction to fix up.  */
87         instr_addr = (int) this_reloc->r_offset + (int) tpnt->loadaddr;
88         got_addr = (char **) instr_addr;
89
90 #ifdef __SUPPORT_LD_DEBUG__
91         if (_dl_debug_symbols) {
92                 _dl_dprintf (2, "Resolving symbol %s\n",
93                              strtab + symtab[symtab_index].st_name);
94         }
95 #endif
96
97         /* Get the address of the GOT entry.  */
98         new_addr = _dl_find_hash (strtab + symtab[symtab_index].st_name,
99                    tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT);
100         if (unlikely(!new_addr)) {
101                 _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
102                              _dl_progname, strtab + symtab[symtab_index].st_name);
103                 _dl_exit (1);
104         }
105 #if defined (__SUPPORT_LD_DEBUG__)
106         if ((unsigned long) got_addr < 0x40000000) {
107                 if (_dl_debug_bindings) {
108                         _dl_dprintf(_dl_debug_file, "\nresolve function: %s",
109                                     strtab + symtab[symtab_index].st_name);
110                         if(_dl_debug_detail)
111                                 _dl_dprintf(_dl_debug_file, "\tpatch %x ==> %x @ %x",
112                                             *got_addr, new_addr, got_addr);
113                 }
114         }
115         if (!_dl_debug_nofixups) {
116                 *got_addr = new_addr;
117         }
118 #else
119         *got_addr = new_addr;
120 #endif
121
122   return (unsigned int) new_addr;
123 }
124
125 void
126 _dl_parse_lazy_relocation_information(struct dyn_elf *arg_rpnt,
127         unsigned long rel_addr, unsigned long rel_size)
128 {
129         int i;
130         char *strtab;
131         int reloc_type;
132         int symtab_index;
133         Elf32_Sym *symtab;
134         Elf32_Rela *rpnt;
135         unsigned int *reloc_addr;
136         struct elf_resolve *tpnt = arg_rpnt->dyn;
137
138         /* Now parse the relocation information.  */
139         rpnt = (Elf32_Rela *)rel_addr;
140         rel_size = rel_size / sizeof (Elf32_Rela);
141
142         symtab = (Elf32_Sym *)tpnt->dynamic_info[DT_SYMTAB];
143         strtab = (char *)tpnt->dynamic_info[DT_STRTAB];
144
145         for (i = 0; i < rel_size; i++, rpnt++) {
146                 reloc_addr = (int *) (tpnt->loadaddr + (int) rpnt->r_offset);
147                 reloc_type = ELF32_R_TYPE (rpnt->r_info);
148                 symtab_index = ELF32_R_SYM (rpnt->r_info);
149
150                 switch (reloc_type)
151                 {
152                 case R_68K_NONE:
153                         break;
154                 case R_68K_JMP_SLOT:
155                         *reloc_addr += (unsigned int) tpnt->loadaddr;
156                 break;
157                 default:
158                         _dl_dprintf (2, "%s: (LAZY) can't handle reloc type ", _dl_progname);
159 #if defined (__SUPPORT_LD_DEBUG__)
160                         _dl_dprintf (2, "%s ", _dl_reltypes[reloc_type]);
161 #endif
162                         if (symtab_index)
163                                 _dl_dprintf (2, "'%s'", strtab + symtab[symtab_index].st_name);
164                         _dl_dprintf (2, "\n");
165                         _dl_exit (1);
166                 }
167         }
168 }
169
170 int
171 _dl_parse_relocation_information(struct dyn_elf *arg_rpnt,
172         unsigned long rel_addr, unsigned long rel_size)
173 {
174         int i;
175         char *strtab;
176         int reloc_type;
177         int goof = 0;
178         Elf32_Sym *symtab;
179         Elf32_Rela *rpnt;
180         unsigned int *reloc_addr;
181         unsigned int symbol_addr;
182         int symtab_index;
183         struct elf_resolve *tpnt = arg_rpnt->dyn;
184         /* Now parse the relocation information */
185
186         rpnt = (Elf32_Rela *)rel_addr;
187         rel_size = rel_size / sizeof (Elf32_Rela);
188
189         symtab = (Elf32_Sym *)tpnt->dynamic_info[DT_SYMTAB];
190         strtab = (char *)tpnt->dynamic_info[DT_STRTAB];
191
192         for (i = 0; i < rel_size; i++, rpnt++) {
193                 reloc_addr = (int *) (tpnt->loadaddr + (int) rpnt->r_offset);
194                 reloc_type = ELF32_R_TYPE (rpnt->r_info);
195                 symtab_index = ELF32_R_SYM (rpnt->r_info);
196                 symbol_addr = 0;
197                 if (symtab_index) {
198                         symbol_addr = (unsigned int)
199                         _dl_find_hash (strtab + symtab[symtab_index].st_name,
200                                        tpnt->symbol_scope, tpnt,
201                                        elf_machine_type_class(reloc_type));
202
203                         /* We want to allow undefined references to weak symbols -
204                            this might have been intentional.  We should not be
205                            linking local symbols here, so all bases should be
206                            covered.  */
207                         if (!symbol_addr
208                             && ELF32_ST_BIND (symtab[symtab_index].st_info) != STB_WEAK)
209                         {
210                                 _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
211                                              _dl_progname, strtab + symtab[symtab_index].st_name);
212                                 _dl_exit (1);
213                         }
214                 }
215                 switch (reloc_type)
216                 {
217                         case R_68K_NONE:
218                                 break;
219                         case R_68K_8:
220                                 *(char *) reloc_addr = symbol_addr + rpnt->r_addend;
221                                 break;
222                         case R_68K_16:
223                                 *(short *) reloc_addr = symbol_addr + rpnt->r_addend;
224                                 break;
225                         case R_68K_32:
226                                 *reloc_addr = symbol_addr + rpnt->r_addend;
227                                 break;
228                         case R_68K_PC8:
229                                 *(char *) reloc_addr = (symbol_addr + rpnt->r_addend
230                                                        - (unsigned int) reloc_addr);
231                                 break;
232                         case R_68K_PC16:
233                                 *(short *) reloc_addr = (symbol_addr + rpnt->r_addend
234                                                         - (unsigned int) reloc_addr);
235                                 break;
236                         case R_68K_PC32:
237                                 *reloc_addr = (symbol_addr + rpnt->r_addend
238                                               - (unsigned int) reloc_addr);
239                                 break;
240                         case R_68K_GLOB_DAT:
241                         case R_68K_JMP_SLOT:
242                                 *reloc_addr = symbol_addr;
243                                 break;
244                         case R_68K_RELATIVE:
245                                 *reloc_addr = ((unsigned int) tpnt->loadaddr
246                                               /* Compatibility kludge.  */
247                                               + (rpnt->r_addend ? : *reloc_addr));
248                                 break;
249                         case R_68K_COPY:
250                                 _dl_memcpy ((void *) reloc_addr,
251                                             (void *) symbol_addr,
252                                             symtab[symtab_index].st_size);
253                                 break;
254                         default:
255                                 _dl_dprintf (2, "%s: can't handle reloc type ", _dl_progname);
256 #if defined (__SUPPORT_LD_DEBUG__)
257                                 _dl_dprintf (2, "%s ", _dl_reltypes[reloc_type]);
258 #endif
259                                 if (symtab_index)
260                                         _dl_dprintf (2, "'%s'", strtab + symtab[symtab_index].st_name);
261                                 _dl_dprintf (2, "\n");
262                                 _dl_exit (1);
263                 }
264         }
265         return goof;
266 }