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>
61 static void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index);
62 static void debug_reloc(ELF_RELOC *rpnt);
63 #define DPRINTF(fmt,args...) _dl_dprintf(2,fmt,args)
65 #define debug_sym(a,b,c)
66 #define debug_reloc(a)
67 #define DPRINTF(fmt,args...)
70 extern char *_dl_progname;
72 extern int _dl_linux_resolve(void);
74 void _dl_init_got(unsigned long *plt,struct elf_resolve *tpnt)
76 unsigned long target_addr = (unsigned long)_dl_linux_resolve;
77 unsigned int n_plt_entries;
79 unsigned long data_words;
80 unsigned int rel_offset_words;
82 DPRINTF("init_got plt=%x, tpnt=%x\n",
83 (unsigned long)plt,(unsigned long)tpnt);
85 n_plt_entries = tpnt->dynamic_info[DT_PLTRELSZ] / sizeof(ELF_RELOC);
86 DPRINTF("n_plt_entries %d\n",n_plt_entries);
88 rel_offset_words = PLT_DATA_START_WORDS(n_plt_entries);
89 DPRINTF("rel_offset_words %x\n",rel_offset_words);
90 data_words = (unsigned long)(plt + rel_offset_words);
91 DPRINTF("data_words %x\n",data_words);
93 tpnt->data_words = data_words;
95 plt[PLT_LONGBRANCH_ENTRY_WORDS] = OPCODE_ADDIS_HI(11, 11, data_words);
96 plt[PLT_LONGBRANCH_ENTRY_WORDS+1] = OPCODE_LWZ(11,data_words,11);
98 plt[PLT_LONGBRANCH_ENTRY_WORDS+2] = OPCODE_MTCTR(11);
99 plt[PLT_LONGBRANCH_ENTRY_WORDS+3] = OPCODE_BCTR();
104 tramp = plt + PLT_TRAMPOLINE_ENTRY_WORDS;
105 tramp[0] = OPCODE_ADDIS_HI(11,11,-data_words);
106 tramp[1] = OPCODE_ADDI(11,11,-data_words);
107 tramp[2] = OPCODE_SLWI(12,11,1);
108 tramp[3] = OPCODE_ADD(11,12,11);
109 tramp[4] = OPCODE_LI(12,target_addr);
110 tramp[5] = OPCODE_ADDIS_HI(12,12,target_addr);
111 tramp[6] = OPCODE_MTCTR(12);
112 tramp[7] = OPCODE_LI(12,(unsigned long)tpnt);
113 tramp[8] = OPCODE_ADDIS_HI(12,12,(unsigned long)tpnt);
114 tramp[9] = OPCODE_BCTR();
119 /* instructions were modified */
130 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
133 ELF_RELOC *this_reloc;
138 unsigned long insn_addr;
139 unsigned long *insns;
140 unsigned long targ_addr;
143 //DPRINTF("linux_resolver tpnt=%x reloc_entry=%x\n", tpnt, reloc_entry);
145 rel_addr = (ELF_RELOC *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
147 this_reloc = (void *)rel_addr + reloc_entry;
148 reloc_type = ELF32_R_TYPE(this_reloc->r_info);
149 symtab_index = ELF32_R_SYM(this_reloc->r_info);
151 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
152 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
154 //debug_reloc(this_reloc);
156 if (reloc_type != R_PPC_JMP_SLOT) {
157 _dl_dprintf(2, "%s: Incorrect relocation type [%s] in jump relocations\n",
159 (reloc_type<N_RELTYPES)?_dl_reltypes[reloc_type]:"unknown");
163 /* Address of dump instruction to fix up */
164 insn_addr = (unsigned long) tpnt->loadaddr +
165 (unsigned long) this_reloc->r_offset;
167 DPRINTF("Resolving symbol %s %x --> ",
168 strtab + symtab[symtab_index].st_name,
171 /* Get the address of the GOT entry */
172 targ_addr = (unsigned long) _dl_find_hash(
173 strtab + symtab[symtab_index].st_name,
174 tpnt->symbol_scope, insn_addr, tpnt, 0);
176 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
177 _dl_progname, strtab + symtab[symtab_index].st_name);
180 DPRINTF("%x\n", targ_addr);
182 insns = (unsigned long *)insn_addr;
183 delta = targ_addr - insn_addr;
185 if(delta<<6>>6 == delta){
186 insns[0] = OPCODE_B(delta);
187 }else if (targ_addr <= 0x01fffffc || targ_addr >= 0xfe000000){
188 insns[0] = OPCODE_BA (targ_addr);
190 /* Warning: we don't handle double-sized PLT entries */
192 unsigned long plt_addr;
193 unsigned long lbranch_addr;
197 plt_addr = (unsigned long)tpnt->dynamic_info[DT_PLTGOT] +
198 (unsigned long)tpnt->loadaddr;
199 lbranch_addr = plt_addr + PLT_LONGBRANCH_ENTRY_WORDS*4;
200 delta = lbranch_addr - insn_addr;
201 index = (insn_addr - plt_addr - PLT_INITIAL_ENTRY_WORDS*4)/2;
203 ptr = (unsigned long *)tpnt->data_words;
204 DPRINTF("plt_addr=%x delta=%x index=%x ptr=%x\n",
205 plt_addr, delta, index, ptr);
206 ptr[index] = targ_addr;
208 insns[1] = OPCODE_B(delta - 4);
211 /* instructions were modified */
212 PPC_DCBST(insn_addr);
219 void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
220 unsigned long rel_addr, unsigned long rel_size, int type)
228 unsigned long reloc_addr;
229 unsigned long *insns;
233 DPRINTF("_dl_parse_lazy_relocation_information(tpnt=%x, rel_addr=%x, rel_size=%x, type=%d)\n",
234 tpnt,rel_addr,rel_size,type);
236 /* Now parse the relocation information */
237 rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
238 rel_size = rel_size / sizeof(ELF_RELOC);
240 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
241 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
242 plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
244 for (i = 0; i < rel_size; i++, rpnt++) {
245 reloc_addr = (unsigned long)tpnt->loadaddr +
246 (unsigned long) rpnt->r_offset;
247 reloc_type = ELF32_R_TYPE(rpnt->r_info);
248 symtab_index = ELF32_R_SYM(rpnt->r_info);
250 /* When the dynamic linker bootstrapped itself, it resolved some symbols.
251 Make sure we do not do them again */
252 if (!symtab_index && tpnt->libtype == program_interpreter)
254 if (symtab_index && tpnt->libtype == program_interpreter &&
255 _dl_symbol(strtab + symtab[symtab_index].st_name))
258 DPRINTF("L %x %s %s %x %x\n",
259 reloc_addr, _dl_reltypes[reloc_type],
260 symtab_index?strtab + symtab[symtab_index].st_name:"",0,0);
262 switch (reloc_type) {
269 delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2)
272 index = (reloc_addr -
273 (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
274 /sizeof(unsigned long);
276 DPRINTF(" index %x delta %x\n",index,delta);
277 insns = (unsigned long *)reloc_addr;
278 insns[0] = OPCODE_LI(11,index*4);
279 insns[1] = OPCODE_B(delta);
283 _dl_dprintf(2, "%s: (LAZY) can't handle reloc type ",
285 #ifdef VERBOSE_DLINKER
286 _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
289 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
293 /* instructions were modified */
294 PPC_DCBST(reloc_addr);
296 PPC_ICBI(reloc_addr);
300 int _dl_parse_relocation_information(struct elf_resolve *tpnt,
301 unsigned long rel_addr, unsigned long rel_size, int type)
309 unsigned long *reloc_addr;
310 unsigned long symbol_addr;
312 unsigned long addend;
315 DPRINTF("_dl_parse_relocation_information(tpnt=%x, rel_addr=%x, rel_size=%x, type=%d)\n",
316 tpnt,rel_addr,rel_size,type);
318 /* Now parse the relocation information */
320 rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
321 rel_size = rel_size / sizeof(ELF_RELOC);
323 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
324 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
325 plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
327 for (i = 0; i < rel_size; i++, rpnt++) {
330 reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
331 reloc_type = ELF32_R_TYPE(rpnt->r_info);
332 symtab_index = ELF32_R_SYM(rpnt->r_info);
333 addend = rpnt->r_addend;
336 if (!symtab_index && tpnt->libtype == program_interpreter)
341 if (tpnt->libtype == program_interpreter &&
342 _dl_symbol(strtab + symtab[symtab_index].st_name))
345 symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name,
346 tpnt->symbol_scope, (unsigned long) reloc_addr,
347 (reloc_type == R_PPC_JMP_SLOT ? tpnt : NULL), 0);
350 * We want to allow undefined references to weak symbols - this might
351 * have been intentional. We should not be linking local symbols
352 * here, so all bases should be covered.
355 ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
356 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
357 _dl_progname, strtab + symtab[symtab_index].st_name);
361 debug_sym(symtab,strtab,symtab_index);
363 switch (reloc_type) {
368 int delta = symbol_addr - (unsigned long)reloc_addr;
369 if(delta<<6>>6 != delta){
370 _dl_dprintf(2,"R_PPC_REL24: Reloc out of range\n");
373 *reloc_addr &= 0xfc000003;
374 *reloc_addr |= delta&0x03fffffc;
378 *reloc_addr += (unsigned long)tpnt->loadaddr + addend;
381 *reloc_addr += symbol_addr;
383 case R_PPC_ADDR16_HA:
384 /* XXX is this correct? */
385 *(short *)reloc_addr += (symbol_addr+0x8000)>>16;
387 case R_PPC_ADDR16_HI:
388 *(short *)reloc_addr += symbol_addr>>16;
390 case R_PPC_ADDR16_LO:
391 *(short *)reloc_addr += symbol_addr;
395 unsigned long targ_addr = (unsigned long)_dl_linux_resolve;
396 int delta = targ_addr - (unsigned long)reloc_addr;
397 if(delta<<6>>6 == delta){
398 *reloc_addr = OPCODE_B(delta);
399 }else if (targ_addr <= 0x01fffffc || targ_addr >= 0xfe000000){
400 *reloc_addr = OPCODE_BA (targ_addr);
406 delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2)
407 - (unsigned long)(reloc_addr+1);
409 index = ((unsigned long)reloc_addr -
410 (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
411 /sizeof(unsigned long);
413 DPRINTF(" index %x delta %x\n",index,delta);
414 reloc_addr[0] = OPCODE_LI(11,index*4);
415 reloc_addr[1] = OPCODE_B(delta);
421 *reloc_addr += symbol_addr;
427 _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
428 #ifdef VERBOSE_DLINKER
429 _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
432 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
436 /* instructions were modified */
437 PPC_DCBST(reloc_addr);
439 PPC_ICBI(reloc_addr);
441 DPRINTF("reloc_addr %x: %x\n",reloc_addr,*reloc_addr);
447 /* This is done as a separate step, because there are cases where
448 information is first copied and later initialized. This results in
449 the wrong information being copied. Someone at Sun was complaining about
450 a bug in the handling of _COPY by SVr4, and this may in fact be what he
451 was talking about. Sigh. */
453 /* No, there are cases where the SVr4 linker fails to emit COPY relocs
456 int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
457 unsigned long rel_size, int type)
465 unsigned long *reloc_addr;
466 unsigned long symbol_addr;
467 struct elf_resolve *tpnt;
470 DPRINTF("parse_copy xpnt=%x rel_addr=%x rel_size=%x type=%d\n",
471 (int)xpnt,rel_addr,rel_size,type);
473 /* Now parse the relocation information */
477 rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
478 rel_size = rel_size / sizeof(ELF_RELOC);
480 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
481 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
483 for (i = 0; i < rel_size; i++, rpnt++) {
484 reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
485 reloc_type = ELF32_R_TYPE(rpnt->r_info);
486 if (reloc_type != R_PPC_COPY)
491 symtab_index = ELF32_R_SYM(rpnt->r_info);
493 if (!symtab_index && tpnt->libtype == program_interpreter)
497 if (tpnt->libtype == program_interpreter &&
498 _dl_symbol(strtab + symtab[symtab_index].st_name))
501 symbol_addr = (unsigned long) _dl_find_hash(strtab +
502 symtab[symtab_index].st_name, xpnt->next,
503 (unsigned long) reloc_addr, NULL, 1);
505 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
506 _dl_progname, strtab + symtab[symtab_index].st_name);
511 debug_sym(symtab,strtab,symtab_index);
513 DPRINTF("copy: to=%x from=%x size=%x\n",
514 symtab[symtab_index].st_value,
515 symbol_addr, symtab[symtab_index].st_size);
518 _dl_memcpy((char *) symtab[symtab_index].st_value,
519 (char *) symbol_addr,
520 symtab[symtab_index].st_size);
528 static void fixup_jmpslot(unsigned long reloc_addr, unsigned long targ_addr)
530 int delta = targ_addr - reloc_addr;
533 if(delta<<6>>6 == delta){
534 *reloc_addr = OPCODE_B(delta);
535 }else if (targ_addr <= 0x01fffffc || targ_addr >= 0xfe000000){
536 *reloc_addr = OPCODE_BA (targ_addr);
538 delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2)
539 - (unsigned long)(reloc_addr+1);
541 index = ((unsigned long)reloc_addr -
542 (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
543 /sizeof(unsigned long);
546 DPRINTF(" index %x delta %x\n",index,delta);
548 reloc_addr[0] = OPCODE_LI(11,index*4);
549 reloc_addr[1] = OPCODE_B(delta);
556 static void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
559 _dl_dprintf(2, "sym: name=%s value=%x size=%x info=%x other=%x shndx=%x\n",
560 strtab + symtab[symtab_index].st_name,
561 symtab[symtab_index].st_value,
562 symtab[symtab_index].st_size,
563 symtab[symtab_index].st_info,
564 symtab[symtab_index].st_other,
565 symtab[symtab_index].st_shndx);
567 _dl_dprintf(2, "sym: null\n");
571 static void debug_reloc(ELF_RELOC *rpnt)
573 _dl_dprintf(2, "reloc: offset=%x type=%x sym=%x addend=%x\n",
575 ELF32_R_TYPE(rpnt->r_info),
576 ELF32_R_SYM(rpnt->r_info),