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)/8;
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;
207 /* icache sync is not necessary, since this will be a data load */
208 //PPC_DCBST(ptr+index);
210 //PPC_ICBI(ptr+index);
212 insns[1] = OPCODE_B(delta - 4);
215 /* instructions were modified */
216 PPC_DCBST(insn_addr);
224 void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
225 unsigned long rel_addr, unsigned long rel_size, int type)
233 unsigned long reloc_addr;
234 unsigned long *insns;
238 DPRINTF("_dl_parse_lazy_relocation_information(tpnt=%x, rel_addr=%x, rel_size=%x, type=%d)\n",
239 tpnt,rel_addr,rel_size,type);
241 /* Now parse the relocation information */
242 rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
243 rel_size = rel_size / sizeof(ELF_RELOC);
245 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
246 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
247 plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
249 for (i = 0; i < rel_size; i++, rpnt++) {
250 reloc_addr = (unsigned long)tpnt->loadaddr +
251 (unsigned long) rpnt->r_offset;
252 reloc_type = ELF32_R_TYPE(rpnt->r_info);
253 symtab_index = ELF32_R_SYM(rpnt->r_info);
255 /* When the dynamic linker bootstrapped itself, it resolved some symbols.
256 Make sure we do not do them again */
257 if (!symtab_index && tpnt->libtype == program_interpreter)
259 if (symtab_index && tpnt->libtype == program_interpreter &&
260 _dl_symbol(strtab + symtab[symtab_index].st_name))
263 DPRINTF("L %x %s %s %x %x\n",
264 reloc_addr, _dl_reltypes[reloc_type],
265 symtab_index?strtab + symtab[symtab_index].st_name:"",0,0);
267 switch (reloc_type) {
274 delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2)
277 index = (reloc_addr -
278 (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
279 /sizeof(unsigned long);
281 DPRINTF(" index %x delta %x\n",index,delta);
282 insns = (unsigned long *)reloc_addr;
283 insns[0] = OPCODE_LI(11,index*4);
284 insns[1] = OPCODE_B(delta);
288 _dl_dprintf(2, "%s: (LAZY) can't handle reloc type ",
290 #ifdef VERBOSE_DLINKER
291 _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
294 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
298 /* instructions were modified */
299 PPC_DCBST(reloc_addr);
301 PPC_ICBI(reloc_addr);
305 int _dl_parse_relocation_information(struct elf_resolve *tpnt,
306 unsigned long rel_addr, unsigned long rel_size, int type)
314 unsigned long *reloc_addr;
315 unsigned long symbol_addr;
317 unsigned long addend;
320 DPRINTF("_dl_parse_relocation_information(tpnt=%x, rel_addr=%x, rel_size=%x, type=%d)\n",
321 tpnt,rel_addr,rel_size,type);
323 /* Now parse the relocation information */
325 rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
326 rel_size = rel_size / sizeof(ELF_RELOC);
328 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
329 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
330 plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
332 for (i = 0; i < rel_size; i++, rpnt++) {
335 reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
336 reloc_type = ELF32_R_TYPE(rpnt->r_info);
337 symtab_index = ELF32_R_SYM(rpnt->r_info);
338 addend = rpnt->r_addend;
341 if (!symtab_index && tpnt->libtype == program_interpreter)
346 if (tpnt->libtype == program_interpreter &&
347 _dl_symbol(strtab + symtab[symtab_index].st_name))
350 symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name,
351 tpnt->symbol_scope, (unsigned long) reloc_addr,
352 (reloc_type == R_PPC_JMP_SLOT ? tpnt : NULL), 0);
355 * We want to allow undefined references to weak symbols - this might
356 * have been intentional. We should not be linking local symbols
357 * here, so all bases should be covered.
360 ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
361 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
362 _dl_progname, strtab + symtab[symtab_index].st_name);
366 debug_sym(symtab,strtab,symtab_index);
368 switch (reloc_type) {
373 int delta = symbol_addr - (unsigned long)reloc_addr;
374 if(delta<<6>>6 != delta){
375 _dl_dprintf(2,"R_PPC_REL24: Reloc out of range\n");
378 *reloc_addr &= 0xfc000003;
379 *reloc_addr |= delta&0x03fffffc;
383 *reloc_addr = (unsigned long)tpnt->loadaddr + addend;
386 *reloc_addr += symbol_addr;
388 case R_PPC_ADDR16_HA:
389 /* XXX is this correct? */
390 *(short *)reloc_addr += (symbol_addr+0x8000)>>16;
392 case R_PPC_ADDR16_HI:
393 *(short *)reloc_addr += symbol_addr>>16;
395 case R_PPC_ADDR16_LO:
396 *(short *)reloc_addr += symbol_addr;
400 unsigned long targ_addr = (unsigned long)_dl_linux_resolve;
401 int delta = targ_addr - (unsigned long)reloc_addr;
402 if(delta<<6>>6 == delta){
403 *reloc_addr = OPCODE_B(delta);
404 }else if (targ_addr <= 0x01fffffc || targ_addr >= 0xfe000000){
405 *reloc_addr = OPCODE_BA (targ_addr);
411 delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2)
412 - (unsigned long)(reloc_addr+1);
414 index = ((unsigned long)reloc_addr -
415 (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
416 /sizeof(unsigned long);
418 DPRINTF(" index %x delta %x\n",index,delta);
419 reloc_addr[0] = OPCODE_LI(11,index*4);
420 reloc_addr[1] = OPCODE_B(delta);
426 *reloc_addr += symbol_addr;
432 _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
433 #ifdef VERBOSE_DLINKER
434 _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
437 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
441 /* instructions were modified */
442 PPC_DCBST(reloc_addr);
444 PPC_ICBI(reloc_addr);
446 DPRINTF("reloc_addr %x: %x\n",reloc_addr,*reloc_addr);
452 /* This is done as a separate step, because there are cases where
453 information is first copied and later initialized. This results in
454 the wrong information being copied. Someone at Sun was complaining about
455 a bug in the handling of _COPY by SVr4, and this may in fact be what he
456 was talking about. Sigh. */
458 /* No, there are cases where the SVr4 linker fails to emit COPY relocs
461 int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
462 unsigned long rel_size, int type)
470 unsigned long *reloc_addr;
471 unsigned long symbol_addr;
472 struct elf_resolve *tpnt;
475 DPRINTF("parse_copy xpnt=%x rel_addr=%x rel_size=%x type=%d\n",
476 (int)xpnt,rel_addr,rel_size,type);
478 /* Now parse the relocation information */
482 rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
483 rel_size = rel_size / sizeof(ELF_RELOC);
485 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
486 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
488 for (i = 0; i < rel_size; i++, rpnt++) {
489 reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
490 reloc_type = ELF32_R_TYPE(rpnt->r_info);
491 if (reloc_type != R_PPC_COPY)
496 symtab_index = ELF32_R_SYM(rpnt->r_info);
498 if (!symtab_index && tpnt->libtype == program_interpreter)
502 if (tpnt->libtype == program_interpreter &&
503 _dl_symbol(strtab + symtab[symtab_index].st_name))
506 symbol_addr = (unsigned long) _dl_find_hash(strtab +
507 symtab[symtab_index].st_name, xpnt->next,
508 (unsigned long) reloc_addr, NULL, 1);
510 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
511 _dl_progname, strtab + symtab[symtab_index].st_name);
516 debug_sym(symtab,strtab,symtab_index);
518 DPRINTF("copy: to=%x from=%x size=%x\n",
519 symtab[symtab_index].st_value,
520 symbol_addr, symtab[symtab_index].st_size);
523 _dl_memcpy((char *) symtab[symtab_index].st_value,
524 (char *) symbol_addr,
525 symtab[symtab_index].st_size);
533 static void fixup_jmpslot(unsigned long reloc_addr, unsigned long targ_addr)
535 int delta = targ_addr - reloc_addr;
538 if(delta<<6>>6 == delta){
539 *reloc_addr = OPCODE_B(delta);
540 }else if (targ_addr <= 0x01fffffc || targ_addr >= 0xfe000000){
541 *reloc_addr = OPCODE_BA (targ_addr);
543 delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2)
544 - (unsigned long)(reloc_addr+1);
546 index = ((unsigned long)reloc_addr -
547 (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
548 /sizeof(unsigned long);
551 DPRINTF(" index %x delta %x\n",index,delta);
553 reloc_addr[0] = OPCODE_LI(11,index*4);
554 reloc_addr[1] = OPCODE_B(delta);
561 static void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
564 _dl_dprintf(2, "sym: name=%s value=%x size=%x info=%x other=%x shndx=%x\n",
565 strtab + symtab[symtab_index].st_name,
566 symtab[symtab_index].st_value,
567 symtab[symtab_index].st_size,
568 symtab[symtab_index].st_info,
569 symtab[symtab_index].st_other,
570 symtab[symtab_index].st_shndx);
572 _dl_dprintf(2, "sym: null\n");
576 static void debug_reloc(ELF_RELOC *rpnt)
578 _dl_dprintf(2, "reloc: offset=%x type=%x sym=%x addend=%x\n",
580 ELF32_R_TYPE(rpnt->r_info),
581 ELF32_R_SYM(rpnt->r_info),