2 /* Run an ELF binary on a linux system.
4 Copyright (C) 1993, Eric Youngdale.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
20 #ifndef VERBOSE_DLINKER
21 #define VERBOSE_DLINKER
23 #ifdef VERBOSE_DLINKER
24 static char *_dl_reltypes[] =
25 { "R_PPC_NONE", "R_PPC_ADDR32", "R_PPC_ADDR24", "R_PPC_ADDR16",
26 "R_PPC_ADDR16_LO", "R_PPC_ADDR16_HI", "R_PPC_ADDR16_HA",
27 "R_PPC_ADDR14", "R_PPC_ADDR14_BRTAKEN", "R_PPC_ADDR14_BRNTAKEN",
28 "R_PPC_REL24", "R_PPC_REL14", "R_PPC_REL14_BRTAKEN",
29 "R_PPC_REL14_BRNTAKEN", "R_PPC_GOT16", "R_PPC_GOT16_LO",
30 "R_PPC_GOT16_HI", "R_PPC_GOT16_HA", "R_PPC_PLTREL24",
31 "R_PPC_COPY", "R_PPC_GLOB_DAT", "R_PPC_JMP_SLOT", "R_PPC_RELATIVE",
32 "R_PPC_LOCAL24PC", "R_PPC_UADDR32", "R_PPC_UADDR16", "R_PPC_REL32",
33 "R_PPC_PLT32", "R_PPC_PLTREL32", "R_PPC_PLT16_LO", "R_PPC_PLT16_HI",
34 "R_PPC_PLT16_HA", "R_PPC_SDAREL16", "R_PPC_SECTOFF",
35 "R_PPC_SECTOFF_LO", "R_PPC_SECTOFF_HI", "R_PPC_SECTOFF_HA",
37 #define N_RELTYPES (sizeof(_dl_reltypes)/sizeof(_dl_reltypes[0]))
40 /* Program to load an ELF binary on a linux system, and run it.
41 References to symbols in sharable libraries can be resolved by either
42 an ELF sharable library or a linux style of shared library. */
44 /* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
45 I ever taken any courses on internals. This program was developed using
46 information available through the book "UNIX SYSTEM V RELEASE 4,
47 Programmers guide: Ansi C and Programming Support Tools", which did
48 a more than adequate job of explaining everything required to get this
51 #include <sys/types.h>
60 extern char *_dl_progname;
62 extern int _dl_linux_resolve(void);
64 void _dl_init_got(unsigned long *plt,struct elf_resolve *tpnt)
67 unsigned long target_addr = (unsigned long)_dl_linux_resolve;
68 unsigned int n_plt_entries;
70 unsigned long data_words;
71 unsigned int rel_offset_words;
74 _dl_dprintf(2,"init_got plt=%x, tpnt=%x\n",
75 (unsigned long)plt,(unsigned long)tpnt);
77 n_plt_entries = tpnt->dynamic_info[DT_PLTRELSZ] / sizeof(ELF_RELOC);
78 _dl_dprintf(2,"n_plt_entries %d\n",n_plt_entries);
80 rel_offset_words = PLT_DATA_START_WORDS(n_plt_entries);
81 _dl_dprintf(2,"rel_offset_words %x\n",rel_offset_words);
82 data_words = (unsigned long)(plt + rel_offset_words);
83 _dl_dprintf(2,"data_words %x\n",data_words);
85 //lpnt += PLT_INITIAL_ENTRY_WORDS;
87 plt[PLT_LONGBRANCH_ENTRY_WORDS] = OPCODE_ADDIS_HI(11, 11, data_words);
88 plt[PLT_LONGBRANCH_ENTRY_WORDS+1] = OPCODE_LWZ(11,data_words,11);
90 plt[PLT_LONGBRANCH_ENTRY_WORDS+2] = OPCODE_MTCTR(11);
91 plt[PLT_LONGBRANCH_ENTRY_WORDS+3] = OPCODE_BCTR();
93 tramp = plt + PLT_TRAMPOLINE_ENTRY_WORDS;
94 tramp[0] = OPCODE_ADDIS_HI(11,11,-data_words);
95 tramp[1] = OPCODE_ADDI(11,11,-data_words);
96 tramp[2] = OPCODE_SLWI(12,11,1);
97 tramp[3] = OPCODE_ADD(11,12,11);
98 tramp[4] = OPCODE_LI(12,target_addr);
99 tramp[5] = OPCODE_ADDIS_HI(12,12,target_addr);
100 tramp[6] = OPCODE_MTCTR(12);
101 tramp[7] = OPCODE_LI(12,(unsigned long)tpnt);
102 tramp[8] = OPCODE_ADDIS_HI(12,12,(unsigned long)tpnt);
103 tramp[9] = OPCODE_BCTR();
115 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
118 ELF_RELOC *this_reloc;
125 unsigned long instr_addr;
127 _dl_dprintf(2,"linux_resolver tpnt=%x reloc_entry=%x\n",tpnt,reloc_entry);
128 rel_addr = (ELF_RELOC *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
130 this_reloc = (void *)rel_addr + reloc_entry;
131 reloc_type = ELF32_R_TYPE(this_reloc->r_info);
132 symtab_index = ELF32_R_SYM(this_reloc->r_info);
134 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
135 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
138 if (reloc_type != R_PPC_JMP_SLOT) {
139 _dl_dprintf(2, "%s: Incorrect relocation type [%s] in jump relocations\n",
141 (reloc_type<N_RELTYPES)?_dl_reltypes[reloc_type]:"unknown");
145 /* Address of dump instruction to fix up */
146 instr_addr = ((unsigned long) this_reloc->r_offset +
147 (unsigned long) tpnt->loadaddr);
148 got_addr = (char **) instr_addr;
151 _dl_dprintf(2, "Resolving symbol %s %x --> ",
152 strtab + symtab[symtab_index].st_name,
156 /* Get the address of the GOT entry */
157 new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name,
158 tpnt->symbol_scope, (unsigned long) got_addr, tpnt, 0);
160 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
161 _dl_progname, strtab + symtab[symtab_index].st_name);
165 _dl_dprintf(2, "%x\n", new_addr);
168 /* #define DEBUG_LIBRARY */
170 if ((unsigned long) got_addr < 0x40000000) {
171 _dl_dprintf(2, "Calling library function: %s\n",
172 strtab + symtab[symtab_index].st_name);
174 *got_addr = new_addr;
177 *got_addr = new_addr;
179 return (unsigned long) new_addr;
182 void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
183 unsigned long rel_addr, unsigned long rel_size, int type)
191 unsigned long *reloc_addr;
196 _dl_dprintf(2,"_dl_parse_lazy_relocation_information(tpnt=%x, rel_addr=%x, rel_size=%x, type=%d)\n",
197 tpnt,rel_addr,rel_size,type);
199 /* Now parse the relocation information */
200 rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
201 rel_size = rel_size / sizeof(ELF_RELOC);
204 (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
205 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
206 plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
208 for (i = 0; i < rel_size; i++, rpnt++) {
209 reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
210 reloc_type = ELF32_R_TYPE(rpnt->r_info);
211 symtab_index = ELF32_R_SYM(rpnt->r_info);
213 /* When the dynamic linker bootstrapped itself, it resolved some symbols.
214 Make sure we do not do them again */
215 if (!symtab_index && tpnt->libtype == program_interpreter)
217 if (symtab_index && tpnt->libtype == program_interpreter &&
218 _dl_symbol(strtab + symtab[symtab_index].st_name))
222 _dl_dprintf(2, "L %x %s %s %x %x\n",
223 reloc_addr, _dl_reltypes[reloc_type],
224 symtab_index?strtab + symtab[symtab_index].st_name:"",0,0);
228 switch (reloc_type) {
235 delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2)
236 - (unsigned long)(reloc_addr+1);
238 index = ((unsigned long)reloc_addr -
239 (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
240 /sizeof(unsigned long);
243 _dl_dprintf(2, " index %x delta %x\n",index,delta);
245 reloc_addr[0] = OPCODE_LI(11,index*4);
246 reloc_addr[1] = OPCODE_B(delta);
250 _dl_dprintf(2, "%s: (LAZY) can't handle reloc type ",
252 #ifdef VERBOSE_DLINKER
253 _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
256 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
260 /* instructions were modified */
261 PPC_DCBST(reloc_addr);
263 PPC_ICBI(reloc_addr);
267 int _dl_parse_relocation_information(struct elf_resolve *tpnt,
268 unsigned long rel_addr, unsigned long rel_size, int type)
276 unsigned long *reloc_addr;
277 unsigned long symbol_addr;
279 unsigned long addend;
283 _dl_dprintf(2,"_dl_parse_relocation_information(tpnt=%x, rel_addr=%x, rel_size=%x, type=%d)\n",
284 tpnt,rel_addr,rel_size,type);
286 /* Now parse the relocation information */
288 rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
289 rel_size = rel_size / sizeof(ELF_RELOC);
291 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
292 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
293 plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
295 for (i = 0; i < rel_size; i++, rpnt++) {
296 reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
297 reloc_type = ELF32_R_TYPE(rpnt->r_info);
298 symtab_index = ELF32_R_SYM(rpnt->r_info);
299 addend = rpnt->r_addend;
302 if (!symtab_index && tpnt->libtype == program_interpreter)
307 if (tpnt->libtype == program_interpreter &&
308 _dl_symbol(strtab + symtab[symtab_index].st_name))
311 symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name,
312 tpnt->symbol_scope, (unsigned long) reloc_addr,
313 (reloc_type == R_PPC_JMP_SLOT ? tpnt : NULL), 0);
316 * We want to allow undefined references to weak symbols - this might
317 * have been intentional. We should not be linking local symbols
318 * here, so all bases should be covered.
321 ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
322 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
323 _dl_progname, strtab + symtab[symtab_index].st_name);
328 _dl_dprintf(2, " %x %s %s %x %x\n",
329 reloc_addr, _dl_reltypes[reloc_type],
330 symtab_index?strtab + symtab[symtab_index].st_name:"",
331 symbol_addr, addend);
333 switch (reloc_type) {
338 int delta = symbol_addr - (unsigned long)reloc_addr;
339 if(delta<<6>>6 != delta){
340 _dl_dprintf(2,"R_PPC_REL24: Reloc out of range\n");
343 *reloc_addr &= 0xfc000003;
344 *reloc_addr |= delta&0x03fffffc;
348 *reloc_addr += (unsigned long)tpnt->loadaddr + addend;
351 *reloc_addr += symbol_addr;
353 case R_PPC_ADDR16_HA:
354 /* XXX is this correct? */
355 *(short *)reloc_addr += (symbol_addr+0x8000)>>16;
357 case R_PPC_ADDR16_HI:
358 *(short *)reloc_addr += symbol_addr>>16;
360 case R_PPC_ADDR16_LO:
361 *(short *)reloc_addr += symbol_addr;
365 unsigned long targ_addr = (unsigned long)_dl_linux_resolve;
366 int delta = targ_addr - (unsigned long)reloc_addr;
367 if(delta<<6>>6 == delta){
368 *reloc_addr = OPCODE_B(delta);
369 }else if (targ_addr <= 0x01fffffc || targ_addr >= 0xfe000000){
370 *reloc_addr = OPCODE_BA (targ_addr);
376 delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2)
377 - (unsigned long)(reloc_addr+1);
379 index = ((unsigned long)reloc_addr -
380 (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
381 /sizeof(unsigned long);
384 _dl_dprintf(2, " index %x delta %x\n",index,delta);
386 reloc_addr[0] = OPCODE_LI(11,index*4);
387 reloc_addr[1] = OPCODE_B(delta);
393 _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
394 #ifdef VERBOSE_DLINKER
395 _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
398 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
402 /* instructions were modified */
403 PPC_DCBST(reloc_addr);
405 PPC_ICBI(reloc_addr);
407 //_dl_dprintf(2,"reloc_addr %x: %x\n",reloc_addr,*reloc_addr);
413 /* This is done as a separate step, because there are cases where
414 information is first copied and later initialized. This results in
415 the wrong information being copied. Someone at Sun was complaining about
416 a bug in the handling of _COPY by SVr4, and this may in fact be what he
417 was talking about. Sigh. */
419 /* No, there are cases where the SVr4 linker fails to emit COPY relocs
422 int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
423 unsigned long rel_size, int type)
431 unsigned long *reloc_addr;
432 unsigned long symbol_addr;
433 struct elf_resolve *tpnt;
436 _dl_dprintf(2,"parse_copy xpnt=%x rel_addr=%x rel_size=%x type=%d\n",
437 (int)xpnt,rel_addr,rel_size,type);
439 /* Now parse the relocation information */
443 rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
444 rel_size = rel_size / sizeof(ELF_RELOC);
446 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
447 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
449 for (i = 0; i < rel_size; i++, rpnt++) {
450 reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
451 reloc_type = ELF32_R_TYPE(rpnt->r_info);
452 if (reloc_type != R_386_COPY)
454 symtab_index = ELF32_R_SYM(rpnt->r_info);
456 if (!symtab_index && tpnt->libtype == program_interpreter)
460 if (tpnt->libtype == program_interpreter &&
461 _dl_symbol(strtab + symtab[symtab_index].st_name))
464 symbol_addr = (unsigned long) _dl_find_hash(strtab +
465 symtab[symtab_index].st_name, xpnt->next,
466 (unsigned long) reloc_addr, NULL, 1);
468 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
469 _dl_progname, strtab + symtab[symtab_index].st_name);
474 _dl_memcpy((char *) symtab[symtab_index].st_value,
475 (char *) symbol_addr, symtab[symtab_index].st_size);