OSDN Git Service

Some very minor cleanups
[uclinux-h8/uClibc.git] / ldso / ldso / i386 / elfinterp.c
1 /* Run an ELF binary on a linux system.
2
3    Copyright (C) 1993, Eric Youngdale.
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2, or (at your option)
8    any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
18 \f
19 #ifndef VERBOSE_DLINKER
20 #define VERBOSE_DLINKER
21 #endif
22 #ifdef VERBOSE_DLINKER
23 static char *_dl_reltypes[] =
24         { "R_386_NONE", "R_386_32", "R_386_PC32", "R_386_GOT32",
25         "R_386_PLT32", "R_386_COPY", "R_386_GLOB_DAT",
26         "R_386_JMP_SLOT", "R_386_RELATIVE", "R_386_GOTOFF",
27         "R_386_GOTPC", "R_386_NUM"
28 };
29 #endif
30
31 /* Program to load an ELF binary on a linux system, and run it.
32    References to symbols in sharable libraries can be resolved by either
33    an ELF sharable library or a linux style of shared library. */
34
35 /* Disclaimer:  I have never seen any AT&T source code for SVr4, nor have
36    I ever taken any courses on internals.  This program was developed using
37    information available through the book "UNIX SYSTEM V RELEASE 4,
38    Programmers guide: Ansi C and Programming Support Tools", which did
39    a more than adequate job of explaining everything required to get this
40    working. */
41
42 #include <sys/types.h>
43 #include <errno.h>
44 #include "elf.h"
45 #include "hash.h"
46 #include "syscall.h"
47 #include "string.h"
48 #include "sysdep.h"
49
50 extern char *_dl_progname;
51
52 extern int _dl_linux_resolve(void);
53
54 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
55 {
56         int reloc_type;
57         Elf32_Rel *this_reloc;
58         char *strtab;
59         Elf32_Sym *symtab;
60         Elf32_Rel *rel_addr;
61         int symtab_index;
62         char *new_addr;
63         char **got_addr;
64         unsigned long instr_addr;
65
66         rel_addr = (Elf32_Rel *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
67
68         this_reloc = rel_addr + (reloc_entry >> 3);
69         reloc_type = ELF32_R_TYPE(this_reloc->r_info);
70         symtab_index = ELF32_R_SYM(this_reloc->r_info);
71
72         symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
73         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
74
75
76         if (reloc_type != R_386_JMP_SLOT) {
77                 _dl_fdprintf(2, "%s: Incorrect relocation type in jump relocations\n", 
78                         _dl_progname);
79                 _dl_exit(1);
80         };
81
82         /* Address of jump instruction to fix up */
83         instr_addr = ((int) this_reloc->r_offset + (int) tpnt->loadaddr);
84         got_addr = (char **) instr_addr;
85
86 #ifdef DEBUG
87         _dl_fdprintf(2, "Resolving symbol %s\n", 
88                 strtab + symtab[symtab_index].st_name);
89 #endif
90
91         /* Get the address of the GOT entry */
92         new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name, 
93                 tpnt->symbol_scope, (int) got_addr, tpnt, 0);
94         if (!new_addr) {
95                 _dl_fdprintf(2, "%s: can't resolve symbol '%s'\n", 
96                         _dl_progname, strtab + symtab[symtab_index].st_name);
97                 _dl_exit(1);
98         };
99 /* #define DEBUG_LIBRARY */
100 #ifdef DEBUG_LIBRARY
101         if ((unsigned long) got_addr < 0x40000000) {
102                 _dl_fdprintf(2, "Calling library function: %s\n", 
103                         strtab + symtab[symtab_index].st_name);
104         } else {
105                 *got_addr = new_addr;
106         }
107 #else
108         *got_addr = new_addr;
109 #endif
110         return (unsigned long) new_addr;
111 }
112
113 void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, 
114         unsigned long rel_addr, unsigned long rel_size, int type)
115 {
116         int i;
117         char *strtab;
118         int reloc_type;
119         int symtab_index;
120         Elf32_Sym *symtab;
121         Elf32_Rel *rpnt;
122         unsigned long *reloc_addr;
123
124         /* Now parse the relocation information */
125         rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr);
126         rel_size = rel_size / sizeof(Elf32_Rel);
127
128         symtab =
129                 (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
130         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
131
132         for (i = 0; i < rel_size; i++, rpnt++) {
133                 reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
134                 reloc_type = ELF32_R_TYPE(rpnt->r_info);
135                 symtab_index = ELF32_R_SYM(rpnt->r_info);
136
137                 /* When the dynamic linker bootstrapped itself, it resolved some symbols.
138                    Make sure we do not do them again */
139                 if (!symtab_index && tpnt->libtype == program_interpreter)
140                         continue;
141                 if (symtab_index && tpnt->libtype == program_interpreter &&
142                         _dl_symbol(strtab + symtab[symtab_index].st_name))
143                         continue;
144
145                 switch (reloc_type) {
146                 case R_386_NONE:
147                         break;
148                 case R_386_JMP_SLOT:
149                         *reloc_addr += (unsigned long) tpnt->loadaddr;
150                         break;
151                 default:
152                         _dl_fdprintf(2, "%s: (LAZY) can't handle reloc type ", 
153                                 _dl_progname);
154 #ifdef VERBOSE_DLINKER
155                         _dl_fdprintf(2, "%s ", _dl_reltypes[reloc_type]);
156 #endif
157                         if (symtab_index)
158                                 _dl_fdprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
159                         _dl_exit(1);
160                 };
161         };
162 }
163
164 int _dl_parse_relocation_information(struct elf_resolve *tpnt, 
165         unsigned long rel_addr, unsigned long rel_size, int type)
166 {
167         int i;
168         char *strtab;
169         int reloc_type;
170         int goof = 0;
171         Elf32_Sym *symtab;
172         Elf32_Rel *rpnt;
173         unsigned long *reloc_addr;
174         unsigned long symbol_addr;
175         int symtab_index;
176
177         /* Now parse the relocation information */
178
179         rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr);
180         rel_size = rel_size / sizeof(Elf32_Rel);
181
182         symtab =
183                 (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
184         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
185
186         for (i = 0; i < rel_size; i++, rpnt++) {
187                 reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
188                 reloc_type = ELF32_R_TYPE(rpnt->r_info);
189                 symtab_index = ELF32_R_SYM(rpnt->r_info);
190                 symbol_addr = 0;
191
192                 if (!symtab_index && tpnt->libtype == program_interpreter)
193                         continue;
194
195                 if (symtab_index) {
196
197                         if (tpnt->libtype == program_interpreter &&
198                                 _dl_symbol(strtab + symtab[symtab_index].st_name))
199                                 continue;
200
201                         symbol_addr = (unsigned long)
202                                 _dl_find_hash(strtab + symtab[symtab_index].st_name, 
203                                         tpnt->symbol_scope, (unsigned long) reloc_addr, 
204                                         (reloc_type == R_386_JMP_SLOT ? tpnt : NULL), 0);
205
206                         /*
207                          * We want to allow undefined references to weak symbols - this might
208                          * have been intentional.  We should not be linking local symbols
209                          * here, so all bases should be covered.
210                          */
211                         if (!symbol_addr &&
212                                 ELF32_ST_BIND(symtab[symtab_index].st_info) ==
213                                 STB_GLOBAL) {
214                                 _dl_fdprintf(2, "%s: can't resolve symbol '%s'\n", 
215                                         _dl_progname, strtab + symtab[symtab_index].st_name);
216                                 goof++;
217                         }
218                 }
219                 switch (reloc_type) {
220                 case R_386_NONE:
221                         break;
222                 case R_386_32:
223                         *reloc_addr += symbol_addr;
224                         break;
225                 case R_386_PC32:
226                         *reloc_addr += symbol_addr - (unsigned long) reloc_addr;
227                         break;
228                 case R_386_GLOB_DAT:
229                 case R_386_JMP_SLOT:
230                         *reloc_addr = symbol_addr;
231                         break;
232                 case R_386_RELATIVE:
233                         *reloc_addr += (unsigned long) tpnt->loadaddr;
234                         break;
235                 case R_386_COPY:
236 #if 0                                                   
237                         /* Do this later */
238                         _dl_fdprintf(2, "Doing copy for symbol ");
239                         if (symtab_index) _dl_fdprintf(2, strtab + symtab[symtab_index].st_name);
240                         _dl_fdprintf(2, "\n");
241                         _dl_memcpy((void *) symtab[symtab_index].st_value, 
242                                 (void *) symbol_addr, symtab[symtab_index].st_size);
243 #endif
244                         break;
245                 default:
246                         _dl_fdprintf(2, "%s: can't handle reloc type ", _dl_progname);
247 #ifdef VERBOSE_DLINKER
248                         _dl_fdprintf(2, "%s ", _dl_reltypes[reloc_type]);
249 #endif
250                         if (symtab_index)
251                                 _dl_fdprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
252                         _dl_exit(1);
253                 };
254
255         };
256         return goof;
257 }
258
259
260 /* This is done as a separate step, because there are cases where
261    information is first copied and later initialized.  This results in
262    the wrong information being copied.  Someone at Sun was complaining about
263    a bug in the handling of _COPY by SVr4, and this may in fact be what he
264    was talking about.  Sigh. */
265
266 /* No, there are cases where the SVr4 linker fails to emit COPY relocs
267    at all */
268
269 int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, 
270         unsigned long rel_size, int type)
271 {
272         int i;
273         char *strtab;
274         int reloc_type;
275         int goof = 0;
276         Elf32_Sym *symtab;
277         Elf32_Rel *rpnt;
278         unsigned long *reloc_addr;
279         unsigned long symbol_addr;
280         struct elf_resolve *tpnt;
281         int symtab_index;
282
283         /* Now parse the relocation information */
284
285         tpnt = xpnt->dyn;
286
287         rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr);
288         rel_size = rel_size / sizeof(Elf32_Rel);
289
290         symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
291         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
292
293         for (i = 0; i < rel_size; i++, rpnt++) {
294                 reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
295                 reloc_type = ELF32_R_TYPE(rpnt->r_info);
296                 if (reloc_type != R_386_COPY)
297                         continue;
298                 symtab_index = ELF32_R_SYM(rpnt->r_info);
299                 symbol_addr = 0;
300                 if (!symtab_index && tpnt->libtype == program_interpreter)
301                         continue;
302                 if (symtab_index) {
303
304                         if (tpnt->libtype == program_interpreter &&
305                                 _dl_symbol(strtab + symtab[symtab_index].st_name))
306                                 continue;
307
308                         symbol_addr = (unsigned long) _dl_find_hash(strtab + 
309                                 symtab[symtab_index].st_name, xpnt->next, 
310                                 (unsigned long) reloc_addr, NULL, 1);
311                         if (!symbol_addr) {
312                                 _dl_fdprintf(2, "%s: can't resolve symbol '%s'\n", 
313                                         _dl_progname, strtab + symtab[symtab_index].st_name);
314                                 goof++;
315                         };
316                 };
317                 if (!goof) {
318                         _dl_memcpy((char *) symtab[symtab_index].st_value, 
319                                 (char *) symbol_addr, symtab[symtab_index].st_size);
320                 }
321         };
322         return goof;
323 }