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
44 #include "ld_syscall.h"
45 #include "ld_string.h"
47 extern char *_dl_progname;
49 extern int _dl_linux_resolve(void);
51 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
54 Elf32_Rel *this_reloc;
61 unsigned long instr_addr;
63 rel_addr = (Elf32_Rel *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
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);
69 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
70 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
73 if (reloc_type != R_386_JMP_SLOT) {
74 _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n",
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;
85 _dl_dprintf(2, "Resolving symbol %s\n",
86 strtab + symtab[symtab_index].st_name);
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);
93 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
94 _dl_progname, strtab + symtab[symtab_index].st_name);
97 /* #define 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);
103 *got_addr = new_addr;
106 *got_addr = new_addr;
108 return (unsigned long) new_addr;
111 void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
112 unsigned long rel_addr, unsigned long rel_size, int type)
120 unsigned long *reloc_addr;
122 /* Now parse the relocation information */
123 rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr);
124 rel_size = rel_size / sizeof(Elf32_Rel);
127 (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
128 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
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);
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)
139 if (symtab_index && tpnt->libtype == program_interpreter &&
140 _dl_symbol(strtab + symtab[symtab_index].st_name))
143 switch (reloc_type) {
147 *reloc_addr += (unsigned long) tpnt->loadaddr;
150 _dl_dprintf(2, "%s: (LAZY) can't handle reloc type ",
152 #ifdef VERBOSE_DLINKER
153 _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
156 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
162 int _dl_parse_relocation_information(struct elf_resolve *tpnt,
163 unsigned long rel_addr, unsigned long rel_size, int type)
171 unsigned long *reloc_addr;
172 unsigned long symbol_addr;
175 /* Now parse the relocation information */
177 rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr);
178 rel_size = rel_size / sizeof(Elf32_Rel);
180 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
181 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
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);
189 if (!symtab_index && tpnt->libtype == program_interpreter)
194 if (tpnt->libtype == program_interpreter &&
195 _dl_symbol(strtab + symtab[symtab_index].st_name))
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);
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.
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);
214 switch (reloc_type) {
218 *reloc_addr += symbol_addr;
221 *reloc_addr += symbol_addr - (unsigned long) reloc_addr;
225 *reloc_addr = symbol_addr;
228 *reloc_addr += (unsigned long) tpnt->loadaddr;
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);
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]);
246 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
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. */
261 /* No, there are cases where the SVr4 linker fails to emit COPY relocs
264 int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
265 unsigned long rel_size, int type)
273 unsigned long *reloc_addr;
274 unsigned long symbol_addr;
275 struct elf_resolve *tpnt;
278 /* Now parse the relocation information */
282 rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr);
283 rel_size = rel_size / sizeof(Elf32_Rel);
285 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
286 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
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)
293 symtab_index = ELF32_R_SYM(rpnt->r_info);
295 if (!symtab_index && tpnt->libtype == program_interpreter)
299 if (tpnt->libtype == program_interpreter &&
300 _dl_symbol(strtab + symtab[symtab_index].st_name))
303 symbol_addr = (unsigned long) _dl_find_hash(strtab +
304 symtab[symtab_index].st_name, xpnt->next,
305 (unsigned long) reloc_addr, NULL, 1);
307 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
308 _dl_progname, strtab + symtab[symtab_index].st_name);
313 _dl_memcpy((char *) symtab[symtab_index].st_value,
314 (char *) symbol_addr, symtab[symtab_index].st_size);