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
52 #ifdef DL_DEBUG_SYMBOLS
53 static void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index);
54 static void debug_reloc(ELF_RELOC *rpnt);
55 #define DPRINTF(fmt,args...) _dl_dprintf(2,fmt,args)
57 #define debug_sym(a,b,c)
58 #define debug_reloc(a)
59 #define DPRINTF(fmt,args...)
62 extern int _dl_linux_resolve(void);
64 void _dl_init_got(unsigned long *plt,struct elf_resolve *tpnt)
66 unsigned long target_addr = (unsigned long)_dl_linux_resolve;
67 unsigned int n_plt_entries;
69 unsigned long data_words;
70 unsigned int rel_offset_words;
72 DPRINTF("init_got plt=%x, tpnt=%x\n",
73 (unsigned long)plt,(unsigned long)tpnt);
75 n_plt_entries = tpnt->dynamic_info[DT_PLTRELSZ] / sizeof(ELF_RELOC);
76 DPRINTF("n_plt_entries %d\n",n_plt_entries);
78 rel_offset_words = PLT_DATA_START_WORDS(n_plt_entries);
79 DPRINTF("rel_offset_words %x\n",rel_offset_words);
80 data_words = (unsigned long)(plt + rel_offset_words);
81 DPRINTF("data_words %x\n",data_words);
83 tpnt->data_words = data_words;
85 plt[PLT_LONGBRANCH_ENTRY_WORDS] = OPCODE_ADDIS_HI(11, 11, data_words);
86 plt[PLT_LONGBRANCH_ENTRY_WORDS+1] = OPCODE_LWZ(11,data_words,11);
88 plt[PLT_LONGBRANCH_ENTRY_WORDS+2] = OPCODE_MTCTR(11);
89 plt[PLT_LONGBRANCH_ENTRY_WORDS+3] = OPCODE_BCTR();
94 tramp = plt + PLT_TRAMPOLINE_ENTRY_WORDS;
95 tramp[0] = OPCODE_ADDIS_HI(11,11,-data_words);
96 tramp[1] = OPCODE_ADDI(11,11,-data_words);
97 tramp[2] = OPCODE_SLWI(12,11,1);
98 tramp[3] = OPCODE_ADD(11,12,11);
99 tramp[4] = OPCODE_LI(12,target_addr);
100 tramp[5] = OPCODE_ADDIS_HI(12,12,target_addr);
101 tramp[6] = OPCODE_MTCTR(12);
102 tramp[7] = OPCODE_LI(12,(unsigned long)tpnt);
103 tramp[8] = OPCODE_ADDIS_HI(12,12,(unsigned long)tpnt);
104 tramp[9] = OPCODE_BCTR();
109 /* instructions were modified */
120 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
123 ELF_RELOC *this_reloc;
128 unsigned long insn_addr;
129 unsigned long *insns;
130 unsigned long targ_addr;
133 //DPRINTF("linux_resolver tpnt=%x reloc_entry=%x\n", tpnt, reloc_entry);
135 rel_addr = (ELF_RELOC *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
137 this_reloc = (void *)rel_addr + reloc_entry;
138 reloc_type = ELF32_R_TYPE(this_reloc->r_info);
139 symtab_index = ELF32_R_SYM(this_reloc->r_info);
141 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
142 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
144 //debug_reloc(this_reloc);
146 if (reloc_type != R_PPC_JMP_SLOT) {
147 _dl_dprintf(2, "%s: Incorrect relocation type [%s] in jump relocations\n",
149 (reloc_type<N_RELTYPES)?_dl_reltypes[reloc_type]:"unknown");
153 /* Address of dump instruction to fix up */
154 insn_addr = (unsigned long) tpnt->loadaddr +
155 (unsigned long) this_reloc->r_offset;
157 DPRINTF("Resolving symbol %s %x --> ",
158 strtab + symtab[symtab_index].st_name,
161 /* Get the address of the GOT entry */
162 targ_addr = (unsigned long) _dl_find_hash(
163 strtab + symtab[symtab_index].st_name,
164 tpnt->symbol_scope, insn_addr, tpnt, 0);
166 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
167 _dl_progname, strtab + symtab[symtab_index].st_name);
170 DPRINTF("%x\n", targ_addr);
172 insns = (unsigned long *)insn_addr;
173 delta = targ_addr - insn_addr;
175 if(delta<<6>>6 == delta){
176 insns[0] = OPCODE_B(delta);
177 }else if (targ_addr <= 0x01fffffc || targ_addr >= 0xfe000000){
178 insns[0] = OPCODE_BA (targ_addr);
180 /* Warning: we don't handle double-sized PLT entries */
182 unsigned long plt_addr;
183 unsigned long lbranch_addr;
187 plt_addr = (unsigned long)tpnt->dynamic_info[DT_PLTGOT] +
188 (unsigned long)tpnt->loadaddr;
189 lbranch_addr = plt_addr + PLT_LONGBRANCH_ENTRY_WORDS*4;
190 delta = lbranch_addr - insn_addr;
191 index = (insn_addr - plt_addr - PLT_INITIAL_ENTRY_WORDS*4)/8;
193 ptr = (unsigned long *)tpnt->data_words;
194 DPRINTF("plt_addr=%x delta=%x index=%x ptr=%x\n",
195 plt_addr, delta, index, ptr);
196 ptr[index] = targ_addr;
197 /* icache sync is not necessary, since this will be a data load */
198 //PPC_DCBST(ptr+index);
200 //PPC_ICBI(ptr+index);
202 insns[1] = OPCODE_B(delta - 4);
205 /* instructions were modified */
206 PPC_DCBST(insn_addr);
214 void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
215 unsigned long rel_addr, unsigned long rel_size, int type)
223 unsigned long reloc_addr;
224 unsigned long *insns;
228 DPRINTF("_dl_parse_lazy_relocation_information(tpnt=%x, rel_addr=%x, rel_size=%x, type=%d)\n",
229 tpnt,rel_addr,rel_size,type);
231 /* Now parse the relocation information */
232 rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
233 rel_size = rel_size / sizeof(ELF_RELOC);
235 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
236 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
237 plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
239 for (i = 0; i < rel_size; i++, rpnt++) {
240 reloc_addr = (unsigned long)tpnt->loadaddr +
241 (unsigned long) rpnt->r_offset;
242 reloc_type = ELF32_R_TYPE(rpnt->r_info);
243 symtab_index = ELF32_R_SYM(rpnt->r_info);
245 /* When the dynamic linker bootstrapped itself, it resolved some symbols.
246 Make sure we do not do them again */
247 if (!symtab_index && tpnt->libtype == program_interpreter)
249 if (symtab_index && tpnt->libtype == program_interpreter &&
250 _dl_symbol(strtab + symtab[symtab_index].st_name))
253 DPRINTF("L %x %s %s %x %x\n",
254 reloc_addr, _dl_reltypes[reloc_type],
255 symtab_index?strtab + symtab[symtab_index].st_name:"",0,0);
257 switch (reloc_type) {
264 delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2)
267 index = (reloc_addr -
268 (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
269 /sizeof(unsigned long);
271 DPRINTF(" index %x delta %x\n",index,delta);
272 insns = (unsigned long *)reloc_addr;
273 insns[0] = OPCODE_LI(11,index*4);
274 insns[1] = OPCODE_B(delta);
278 _dl_dprintf(2, "%s: (LAZY) can't handle reloc type ",
280 #ifdef VERBOSE_DLINKER
281 _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
284 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
288 /* instructions were modified */
289 PPC_DCBST(reloc_addr);
291 PPC_ICBI(reloc_addr);
295 int _dl_parse_relocation_information(struct elf_resolve *tpnt,
296 unsigned long rel_addr, unsigned long rel_size, int type)
304 unsigned long *reloc_addr;
305 unsigned long symbol_addr;
307 unsigned long addend;
310 DPRINTF("_dl_parse_relocation_information(tpnt=%x, rel_addr=%x, rel_size=%x, type=%d)\n",
311 tpnt,rel_addr,rel_size,type);
313 /* Now parse the relocation information */
315 rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
316 rel_size = rel_size / sizeof(ELF_RELOC);
318 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
319 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
320 plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
322 for (i = 0; i < rel_size; i++, rpnt++) {
325 reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
326 reloc_type = ELF32_R_TYPE(rpnt->r_info);
327 symtab_index = ELF32_R_SYM(rpnt->r_info);
328 addend = rpnt->r_addend;
331 if (!symtab_index && tpnt->libtype == program_interpreter)
336 if (tpnt->libtype == program_interpreter &&
337 _dl_symbol(strtab + symtab[symtab_index].st_name))
340 symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name,
341 tpnt->symbol_scope, (unsigned long) reloc_addr,
342 (reloc_type == R_PPC_JMP_SLOT ? tpnt : NULL), 0);
345 * We want to allow undefined references to weak symbols - this might
346 * have been intentional. We should not be linking local symbols
347 * here, so all bases should be covered.
350 ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
351 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
352 _dl_progname, strtab + symtab[symtab_index].st_name);
356 debug_sym(symtab,strtab,symtab_index);
358 switch (reloc_type) {
363 int delta = symbol_addr - (unsigned long)reloc_addr;
364 if(delta<<6>>6 != delta){
365 _dl_dprintf(2,"R_PPC_REL24: Reloc out of range\n");
368 *reloc_addr &= 0xfc000003;
369 *reloc_addr |= delta&0x03fffffc;
373 *reloc_addr = (unsigned long)tpnt->loadaddr + addend;
376 *reloc_addr += symbol_addr;
378 case R_PPC_ADDR16_HA:
379 /* XXX is this correct? */
380 *(short *)reloc_addr += (symbol_addr+0x8000)>>16;
382 case R_PPC_ADDR16_HI:
383 *(short *)reloc_addr += symbol_addr>>16;
385 case R_PPC_ADDR16_LO:
386 *(short *)reloc_addr += symbol_addr;
390 unsigned long targ_addr = (unsigned long)_dl_linux_resolve;
391 int delta = targ_addr - (unsigned long)reloc_addr;
392 if(delta<<6>>6 == delta){
393 *reloc_addr = OPCODE_B(delta);
394 }else if (targ_addr <= 0x01fffffc || targ_addr >= 0xfe000000){
395 *reloc_addr = OPCODE_BA (targ_addr);
401 delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2)
402 - (unsigned long)(reloc_addr+1);
404 index = ((unsigned long)reloc_addr -
405 (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
406 /sizeof(unsigned long);
408 DPRINTF(" index %x delta %x\n",index,delta);
409 reloc_addr[0] = OPCODE_LI(11,index*4);
410 reloc_addr[1] = OPCODE_B(delta);
416 *reloc_addr += symbol_addr;
422 _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
423 #ifdef VERBOSE_DLINKER
424 _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
427 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
431 /* instructions were modified */
432 PPC_DCBST(reloc_addr);
434 PPC_ICBI(reloc_addr);
436 DPRINTF("reloc_addr %x: %x\n",reloc_addr,*reloc_addr);
442 /* This is done as a separate step, because there are cases where
443 information is first copied and later initialized. This results in
444 the wrong information being copied. Someone at Sun was complaining about
445 a bug in the handling of _COPY by SVr4, and this may in fact be what he
446 was talking about. Sigh. */
448 /* No, there are cases where the SVr4 linker fails to emit COPY relocs
451 int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
452 unsigned long rel_size, int type)
460 unsigned long *reloc_addr;
461 unsigned long symbol_addr;
462 struct elf_resolve *tpnt;
465 DPRINTF("parse_copy xpnt=%x rel_addr=%x rel_size=%x type=%d\n",
466 (int)xpnt,rel_addr,rel_size,type);
468 /* Now parse the relocation information */
472 rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
473 rel_size = rel_size / sizeof(ELF_RELOC);
475 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
476 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
478 for (i = 0; i < rel_size; i++, rpnt++) {
479 reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
480 reloc_type = ELF32_R_TYPE(rpnt->r_info);
481 if (reloc_type != R_PPC_COPY)
486 symtab_index = ELF32_R_SYM(rpnt->r_info);
488 if (!symtab_index && tpnt->libtype == program_interpreter)
492 if (tpnt->libtype == program_interpreter &&
493 _dl_symbol(strtab + symtab[symtab_index].st_name))
496 symbol_addr = (unsigned long) _dl_find_hash(strtab +
497 symtab[symtab_index].st_name, xpnt->next,
498 (unsigned long) reloc_addr, NULL, 1);
500 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
501 _dl_progname, strtab + symtab[symtab_index].st_name);
506 debug_sym(symtab,strtab,symtab_index);
508 DPRINTF("copy: to=%x from=%x size=%x\n",
509 symtab[symtab_index].st_value,
510 symbol_addr, symtab[symtab_index].st_size);
513 _dl_memcpy((char *) symtab[symtab_index].st_value,
514 (char *) symbol_addr,
515 symtab[symtab_index].st_size);
523 static void fixup_jmpslot(unsigned long reloc_addr, unsigned long targ_addr)
525 int delta = targ_addr - reloc_addr;
528 if(delta<<6>>6 == delta){
529 *reloc_addr = OPCODE_B(delta);
530 }else if (targ_addr <= 0x01fffffc || targ_addr >= 0xfe000000){
531 *reloc_addr = OPCODE_BA (targ_addr);
533 delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2)
534 - (unsigned long)(reloc_addr+1);
536 index = ((unsigned long)reloc_addr -
537 (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
538 /sizeof(unsigned long);
541 DPRINTF(" index %x delta %x\n",index,delta);
543 reloc_addr[0] = OPCODE_LI(11,index*4);
544 reloc_addr[1] = OPCODE_B(delta);
550 #ifdef DL_DEBUG_SYMBOLS
551 static void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
554 _dl_dprintf(2, "sym: name=%s value=%x size=%x info=%x other=%x shndx=%x\n",
555 strtab + symtab[symtab_index].st_name,
556 symtab[symtab_index].st_value,
557 symtab[symtab_index].st_size,
558 symtab[symtab_index].st_info,
559 symtab[symtab_index].st_other,
560 symtab[symtab_index].st_shndx);
562 _dl_dprintf(2, "sym: null\n");
566 static void debug_reloc(ELF_RELOC *rpnt)
568 _dl_dprintf(2, "reloc: offset=%x type=%x sym=%x addend=%x\n",
570 ELF32_R_TYPE(rpnt->r_info),
571 ELF32_R_SYM(rpnt->r_info),