OSDN Git Service

Rework naming for shared lib loader to avoid potential
[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 "linuxelf.h"
43 #include "ld_hash.h"
44 #include "ld_syscall.h"
45 #include "ld_string.h"
46
47 extern char *_dl_progname;
48
49 extern int _dl_linux_resolve(void);
50
51 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
52 {
53         int reloc_type;
54         Elf32_Rel *this_reloc;
55         char *strtab;
56         Elf32_Sym *symtab;
57         Elf32_Rel *rel_addr;
58         int symtab_index;
59         char *new_addr;
60         char **got_addr;
61         unsigned long instr_addr;
62
63         rel_addr = (Elf32_Rel *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
64
65         this_reloc = rel_addr + (reloc_entry >> 3);
66         reloc_type = ELF32_R_TYPE(this_reloc->r_info);
67         symtab_index = ELF32_R_SYM(this_reloc->r_info);
68
69         symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
70         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
71
72
73         if (reloc_type != R_386_JMP_SLOT) {
74                 _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n", 
75                         _dl_progname);
76                 _dl_exit(1);
77         };
78
79         /* Address of jump instruction to fix up */
80         instr_addr = ((unsigned long) this_reloc->r_offset + 
81                 (unsigned long) tpnt->loadaddr);
82         got_addr = (char **) instr_addr;
83
84 #ifdef DEBUG
85         _dl_dprintf(2, "Resolving symbol %s\n", 
86                 strtab + symtab[symtab_index].st_name);
87 #endif
88
89         /* Get the address of the GOT entry */
90         new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name, 
91                 tpnt->symbol_scope, (unsigned long) got_addr, tpnt, 0);
92         if (!new_addr) {
93                 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", 
94                         _dl_progname, strtab + symtab[symtab_index].st_name);
95                 _dl_exit(1);
96         };
97 /* #define DEBUG_LIBRARY */
98 #ifdef DEBUG_LIBRARY
99         if ((unsigned long) got_addr < 0x40000000) {
100                 _dl_dprintf(2, "Calling library function: %s\n", 
101                         strtab + symtab[symtab_index].st_name);
102         } else {
103                 *got_addr = new_addr;
104         }
105 #else
106         *got_addr = new_addr;
107 #endif
108         return (unsigned long) new_addr;
109 }
110
111 void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, 
112         unsigned long rel_addr, unsigned long rel_size, int type)
113 {
114         int i;
115         char *strtab;
116         int reloc_type;
117         int symtab_index;
118         Elf32_Sym *symtab;
119         Elf32_Rel *rpnt;
120         unsigned long *reloc_addr;
121
122         /* Now parse the relocation information */
123         rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr);
124         rel_size = rel_size / sizeof(Elf32_Rel);
125
126         symtab =
127                 (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
128         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
129
130         for (i = 0; i < rel_size; i++, rpnt++) {
131                 reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
132                 reloc_type = ELF32_R_TYPE(rpnt->r_info);
133                 symtab_index = ELF32_R_SYM(rpnt->r_info);
134
135                 /* When the dynamic linker bootstrapped itself, it resolved some symbols.
136                    Make sure we do not do them again */
137                 if (!symtab_index && tpnt->libtype == program_interpreter)
138                         continue;
139                 if (symtab_index && tpnt->libtype == program_interpreter &&
140                         _dl_symbol(strtab + symtab[symtab_index].st_name))
141                         continue;
142
143                 switch (reloc_type) {
144                 case R_386_NONE:
145                         break;
146                 case R_386_JMP_SLOT:
147                         *reloc_addr += (unsigned long) tpnt->loadaddr;
148                         break;
149                 default:
150                         _dl_dprintf(2, "%s: (LAZY) can't handle reloc type ", 
151                                 _dl_progname);
152 #ifdef VERBOSE_DLINKER
153                         _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
154 #endif
155                         if (symtab_index)
156                                 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
157                         _dl_exit(1);
158                 };
159         };
160 }
161
162 int _dl_parse_relocation_information(struct elf_resolve *tpnt, 
163         unsigned long rel_addr, unsigned long rel_size, int type)
164 {
165         int i;
166         char *strtab;
167         int reloc_type;
168         int goof = 0;
169         Elf32_Sym *symtab;
170         Elf32_Rel *rpnt;
171         unsigned long *reloc_addr;
172         unsigned long symbol_addr;
173         int symtab_index;
174
175         /* Now parse the relocation information */
176
177         rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr);
178         rel_size = rel_size / sizeof(Elf32_Rel);
179
180         symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
181         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
182
183         for (i = 0; i < rel_size; i++, rpnt++) {
184                 reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
185                 reloc_type = ELF32_R_TYPE(rpnt->r_info);
186                 symtab_index = ELF32_R_SYM(rpnt->r_info);
187                 symbol_addr = 0;
188
189                 if (!symtab_index && tpnt->libtype == program_interpreter)
190                         continue;
191
192                 if (symtab_index) {
193
194                         if (tpnt->libtype == program_interpreter &&
195                                 _dl_symbol(strtab + symtab[symtab_index].st_name))
196                                 continue;
197
198                         symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name, 
199                                         tpnt->symbol_scope, (unsigned long) reloc_addr, 
200                                         (reloc_type == R_386_JMP_SLOT ? tpnt : NULL), 0);
201
202                         /*
203                          * We want to allow undefined references to weak symbols - this might
204                          * have been intentional.  We should not be linking local symbols
205                          * here, so all bases should be covered.
206                          */
207                         if (!symbol_addr &&
208                                 ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
209                                 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", 
210                                         _dl_progname, strtab + symtab[symtab_index].st_name);
211                                 goof++;
212                         }
213                 }
214                 switch (reloc_type) {
215                 case R_386_NONE:
216                         break;
217                 case R_386_32:
218                         *reloc_addr += symbol_addr;
219                         break;
220                 case R_386_PC32:
221                         *reloc_addr += symbol_addr - (unsigned long) reloc_addr;
222                         break;
223                 case R_386_GLOB_DAT:
224                 case R_386_JMP_SLOT:
225                         *reloc_addr = symbol_addr;
226                         break;
227                 case R_386_RELATIVE:
228                         *reloc_addr += (unsigned long) tpnt->loadaddr;
229                         break;
230                 case R_386_COPY:
231 #if 0                                                   
232                         /* Do this later */
233                         _dl_dprintf(2, "Doing copy for symbol ");
234                         if (symtab_index) _dl_dprintf(2, strtab + symtab[symtab_index].st_name);
235                         _dl_dprintf(2, "\n");
236                         _dl_memcpy((void *) symtab[symtab_index].st_value, 
237                                 (void *) symbol_addr, symtab[symtab_index].st_size);
238 #endif
239                         break;
240                 default:
241                         _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
242 #ifdef VERBOSE_DLINKER
243                         _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
244 #endif
245                         if (symtab_index)
246                                 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
247                         _dl_exit(1);
248                 };
249
250         };
251         return goof;
252 }
253
254
255 /* This is done as a separate step, because there are cases where
256    information is first copied and later initialized.  This results in
257    the wrong information being copied.  Someone at Sun was complaining about
258    a bug in the handling of _COPY by SVr4, and this may in fact be what he
259    was talking about.  Sigh. */
260
261 /* No, there are cases where the SVr4 linker fails to emit COPY relocs
262    at all */
263
264 int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, 
265         unsigned long rel_size, int type)
266 {
267         int i;
268         char *strtab;
269         int reloc_type;
270         int goof = 0;
271         Elf32_Sym *symtab;
272         Elf32_Rel *rpnt;
273         unsigned long *reloc_addr;
274         unsigned long symbol_addr;
275         struct elf_resolve *tpnt;
276         int symtab_index;
277
278         /* Now parse the relocation information */
279
280         tpnt = xpnt->dyn;
281
282         rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr);
283         rel_size = rel_size / sizeof(Elf32_Rel);
284
285         symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
286         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
287
288         for (i = 0; i < rel_size; i++, rpnt++) {
289                 reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
290                 reloc_type = ELF32_R_TYPE(rpnt->r_info);
291                 if (reloc_type != R_386_COPY)
292                         continue;
293                 symtab_index = ELF32_R_SYM(rpnt->r_info);
294                 symbol_addr = 0;
295                 if (!symtab_index && tpnt->libtype == program_interpreter)
296                         continue;
297                 if (symtab_index) {
298
299                         if (tpnt->libtype == program_interpreter &&
300                                 _dl_symbol(strtab + symtab[symtab_index].st_name))
301                                 continue;
302
303                         symbol_addr = (unsigned long) _dl_find_hash(strtab + 
304                                 symtab[symtab_index].st_name, xpnt->next, 
305                                 (unsigned long) reloc_addr, NULL, 1);
306                         if (!symbol_addr) {
307                                 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", 
308                                         _dl_progname, strtab + symtab[symtab_index].st_name);
309                                 goof++;
310                         };
311                 };
312                 if (!goof) {
313                         _dl_memcpy((char *) symtab[symtab_index].st_value, 
314                                 (char *) symbol_addr, symtab[symtab_index].st_size);
315                 }
316         };
317         return goof;
318 }