OSDN Git Service

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