1 /* Run an ELF binary on a linux system.
3 Copyright (C) 1993, Eric Youngdale.
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)
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.
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. */
19 #ifndef VERBOSE_DLINKER
20 #define VERBOSE_DLINKER
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"
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. */
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
42 #include <sys/types.h>
50 extern char *_dl_progname;
52 extern int _dl_linux_resolve(void);
54 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
57 Elf32_Rel *this_reloc;
64 unsigned long instr_addr;
66 rel_addr = (Elf32_Rel *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
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);
72 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
73 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
76 if (reloc_type != R_386_JMP_SLOT) {
77 _dl_fdprintf(2, "%s: Incorrect relocation type in jump relocations\n",
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;
87 _dl_fdprintf(2, "Resolving symbol %s\n",
88 strtab + symtab[symtab_index].st_name);
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);
95 _dl_fdprintf(2, "%s: can't resolve symbol '%s'\n",
96 _dl_progname, strtab + symtab[symtab_index].st_name);
99 /* #define 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);
105 *got_addr = new_addr;
108 *got_addr = new_addr;
110 return (unsigned long) new_addr;
113 void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
114 unsigned long rel_addr, unsigned long rel_size, int type)
122 unsigned long *reloc_addr;
124 /* Now parse the relocation information */
125 rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr);
126 rel_size = rel_size / sizeof(Elf32_Rel);
129 (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
130 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
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);
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)
141 if (symtab_index && tpnt->libtype == program_interpreter &&
142 _dl_symbol(strtab + symtab[symtab_index].st_name))
145 switch (reloc_type) {
149 *reloc_addr += (unsigned long) tpnt->loadaddr;
152 _dl_fdprintf(2, "%s: (LAZY) can't handle reloc type ",
154 #ifdef VERBOSE_DLINKER
155 _dl_fdprintf(2, "%s ", _dl_reltypes[reloc_type]);
158 _dl_fdprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
164 int _dl_parse_relocation_information(struct elf_resolve *tpnt,
165 unsigned long rel_addr, unsigned long rel_size, int type)
173 unsigned long *reloc_addr;
174 unsigned long symbol_addr;
177 /* Now parse the relocation information */
179 rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr);
180 rel_size = rel_size / sizeof(Elf32_Rel);
183 (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
184 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
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);
192 if (!symtab_index && tpnt->libtype == program_interpreter)
197 if (tpnt->libtype == program_interpreter &&
198 _dl_symbol(strtab + symtab[symtab_index].st_name))
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);
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.
212 ELF32_ST_BIND(symtab[symtab_index].st_info) ==
214 _dl_fdprintf(2, "%s: can't resolve symbol '%s'\n",
215 _dl_progname, strtab + symtab[symtab_index].st_name);
219 switch (reloc_type) {
223 *reloc_addr += symbol_addr;
226 *reloc_addr += symbol_addr - (unsigned long) reloc_addr;
230 *reloc_addr = symbol_addr;
233 *reloc_addr += (unsigned long) tpnt->loadaddr;
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);
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]);
251 _dl_fdprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
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. */
266 /* No, there are cases where the SVr4 linker fails to emit COPY relocs
269 int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
270 unsigned long rel_size, int type)
278 unsigned long *reloc_addr;
279 unsigned long symbol_addr;
280 struct elf_resolve *tpnt;
283 /* Now parse the relocation information */
287 rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr);
288 rel_size = rel_size / sizeof(Elf32_Rel);
290 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
291 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
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)
298 symtab_index = ELF32_R_SYM(rpnt->r_info);
300 if (!symtab_index && tpnt->libtype == program_interpreter)
304 if (tpnt->libtype == program_interpreter &&
305 _dl_symbol(strtab + symtab[symtab_index].st_name))
308 symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name,
309 xpnt->next, (int) reloc_addr, NULL, 1);
311 _dl_fdprintf(2, "%s: can't resolve symbol '%s'\n",
312 _dl_progname, strtab + symtab[symtab_index].st_name);
317 _dl_memcpy((char *) symtab[symtab_index].st_value,
318 (char *) symbol_addr, symtab[symtab_index].st_size);