1 /* vi: set sw=4 ts=4: */
2 /* powerpc shared library loader suppport
4 * Copyright (C) 2001-2002, David A. Schleef
5 * Copyright (C) 2003, Erik Andersen
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. The name of the above contributors may not be
15 * used to endorse or promote products derived from this software
16 * without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #if defined (__SUPPORT_LD_DEBUG__)
32 static const char *_dl_reltypes_tab[] =
33 { "R_PPC_NONE", "R_PPC_ADDR32", "R_PPC_ADDR24", "R_PPC_ADDR16",
34 "R_PPC_ADDR16_LO", "R_PPC_ADDR16_HI", "R_PPC_ADDR16_HA",
35 "R_PPC_ADDR14", "R_PPC_ADDR14_BRTAKEN", "R_PPC_ADDR14_BRNTAKEN",
36 "R_PPC_REL24", "R_PPC_REL14", "R_PPC_REL14_BRTAKEN",
37 "R_PPC_REL14_BRNTAKEN", "R_PPC_GOT16", "R_PPC_GOT16_LO",
38 "R_PPC_GOT16_HI", "R_PPC_GOT16_HA", "R_PPC_PLTREL24",
39 "R_PPC_COPY", "R_PPC_GLOB_DAT", "R_PPC_JMP_SLOT", "R_PPC_RELATIVE",
40 "R_PPC_LOCAL24PC", "R_PPC_UADDR32", "R_PPC_UADDR16", "R_PPC_REL32",
41 "R_PPC_PLT32", "R_PPC_PLTREL32", "R_PPC_PLT16_LO", "R_PPC_PLT16_HI",
42 "R_PPC_PLT16_HA", "R_PPC_SDAREL16", "R_PPC_SECTOFF",
43 "R_PPC_SECTOFF_LO", "R_PPC_SECTOFF_HI", "R_PPC_SECTOFF_HA",
47 _dl_reltypes(int type)
52 if (type >= (int)(sizeof (_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) ||
53 NULL == (str = _dl_reltypes_tab[type]))
55 str =_dl_simple_ltoa( buf, (unsigned long)(type));
61 void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
66 _dl_dprintf(_dl_debug_file, "\n%s\n\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",
67 strtab + symtab[symtab_index].st_name,
68 symtab[symtab_index].st_value,
69 symtab[symtab_index].st_size,
70 symtab[symtab_index].st_info,
71 symtab[symtab_index].st_other,
72 symtab[symtab_index].st_shndx);
78 void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt)
84 symtab_index = ELF32_R_SYM(rpnt->r_info);
85 sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0";
88 _dl_dprintf(_dl_debug_file, "\n\t");
90 _dl_dprintf(_dl_debug_file, "\n%s\n\t", sym);
91 #ifdef ELF_USES_RELOCA
92 _dl_dprintf(_dl_debug_file, "%s\toffset=%x\taddend=%x",
93 _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
97 _dl_dprintf(_dl_debug_file, "%s\toffset=%x\n",
98 _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
105 extern int _dl_linux_resolve(void);
107 void _dl_init_got(unsigned long *plt,struct elf_resolve *tpnt)
109 unsigned long target_addr = (unsigned long)_dl_linux_resolve;
110 unsigned int n_plt_entries;
111 unsigned long *tramp;
112 unsigned long data_words;
113 unsigned int rel_offset_words;
115 //DPRINTF("init_got plt=%x, tpnt=%x\n", (unsigned long)plt,(unsigned long)tpnt);
117 n_plt_entries = tpnt->dynamic_info[DT_PLTRELSZ] / sizeof(ELF_RELOC);
118 //DPRINTF("n_plt_entries %d\n",n_plt_entries);
120 rel_offset_words = PLT_DATA_START_WORDS(n_plt_entries);
121 //DPRINTF("rel_offset_words %x\n",rel_offset_words);
122 data_words = (unsigned long)(plt + rel_offset_words);
123 //DPRINTF("data_words %x\n",data_words);
125 tpnt->data_words = data_words;
127 plt[PLT_LONGBRANCH_ENTRY_WORDS] = OPCODE_ADDIS_HI(11, 11, data_words);
128 plt[PLT_LONGBRANCH_ENTRY_WORDS+1] = OPCODE_LWZ(11,data_words,11);
130 plt[PLT_LONGBRANCH_ENTRY_WORDS+2] = OPCODE_MTCTR(11);
131 plt[PLT_LONGBRANCH_ENTRY_WORDS+3] = OPCODE_BCTR();
136 tramp = plt + PLT_TRAMPOLINE_ENTRY_WORDS;
137 tramp[0] = OPCODE_ADDIS_HI(11,11,-data_words);
138 tramp[1] = OPCODE_ADDI(11,11,-data_words);
139 tramp[2] = OPCODE_SLWI(12,11,1);
140 tramp[3] = OPCODE_ADD(11,12,11);
141 tramp[4] = OPCODE_LI(12,target_addr);
142 tramp[5] = OPCODE_ADDIS_HI(12,12,target_addr);
143 tramp[6] = OPCODE_MTCTR(12);
144 tramp[7] = OPCODE_LI(12,(unsigned long)tpnt);
145 tramp[8] = OPCODE_ADDIS_HI(12,12,(unsigned long)tpnt);
146 tramp[9] = OPCODE_BCTR();
151 /* instructions were modified */
159 PPC_ICBI(plt+4); /* glibc thinks this is not needed */
160 PPC_ICBI(plt+8); /* glibc thinks this is not needed */
161 PPC_ICBI(plt+12); /* glibc thinks this is not needed */
166 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
169 ELF_RELOC *this_reloc;
174 unsigned long insn_addr;
175 unsigned long *insns;
176 unsigned long new_addr;
180 rel_addr = (ELF_RELOC *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
182 this_reloc = (void *)rel_addr + reloc_entry;
183 reloc_type = ELF32_R_TYPE(this_reloc->r_info);
184 symtab_index = ELF32_R_SYM(this_reloc->r_info);
186 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
187 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
188 symname = strtab + symtab[symtab_index].st_name;
190 #if defined (__SUPPORT_LD_DEBUG__)
191 debug_sym(symtab,strtab,symtab_index);
192 debug_reloc(symtab,strtab,this_reloc);
195 if (reloc_type != R_PPC_JMP_SLOT) {
196 _dl_dprintf(2, "%s: Incorrect relocation type in jump relocation\n", _dl_progname);
200 /* Address of dump instruction to fix up */
201 insn_addr = (unsigned long) tpnt->loadaddr +
202 (unsigned long) this_reloc->r_offset;
204 #if defined (__SUPPORT_LD_DEBUG__)
205 if(_dl_debug_reloc && _dl_debug_detail)
206 _dl_dprintf(_dl_debug_file, "\n\tResolving symbol %s %x --> ", symname, insn_addr);
209 /* Get the address of the GOT entry */
210 new_addr = (unsigned long) _dl_find_hash(
211 strtab + symtab[symtab_index].st_name,
212 tpnt->symbol_scope, tpnt, resolver);
214 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
215 _dl_progname, symname);
219 #if defined (__SUPPORT_LD_DEBUG__)
220 if(_dl_debug_reloc && _dl_debug_detail)
221 _dl_dprintf(_dl_debug_file, "%x\n", new_addr);
224 insns = (unsigned long *)insn_addr;
225 delta = new_addr - insn_addr;
227 if(delta<<6>>6 == delta){
228 insns[0] = OPCODE_B(delta);
229 }else if (new_addr <= 0x01fffffc || new_addr >= 0xfe000000){
230 insns[0] = OPCODE_BA (new_addr);
232 /* Warning: we don't handle double-sized PLT entries */
233 unsigned long plt_addr;
234 unsigned long lbranch_addr;
238 plt_addr = (unsigned long)tpnt->dynamic_info[DT_PLTGOT] +
239 (unsigned long)tpnt->loadaddr;
240 lbranch_addr = plt_addr + PLT_LONGBRANCH_ENTRY_WORDS*4;
241 delta = lbranch_addr - insn_addr;
242 index = (insn_addr - plt_addr - PLT_INITIAL_ENTRY_WORDS*4)/8;
244 ptr = (unsigned long *)tpnt->data_words;
245 //DPRINTF("plt_addr=%x delta=%x index=%x ptr=%x\n", plt_addr, delta, index, ptr);
246 ptr[index] = new_addr;
247 /* icache sync is not necessary, since this will be a data load */
248 //PPC_DCBST(ptr+index);
250 //PPC_ICBI(ptr+index);
253 /* instructions were modified */
254 insns[1] = OPCODE_B(delta - 4);
255 PPC_DCBST(insn_addr+1);
257 PPC_ICBI(insn_addr+1);
263 /* instructions were modified */
264 PPC_DCBST(insn_addr);
273 _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
274 unsigned long rel_addr, unsigned long rel_size,
275 int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
276 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
284 /* Now parse the relocation information */
285 rpnt = (ELF_RELOC *)(intptr_t) (rel_addr + tpnt->loadaddr);
286 rel_size = rel_size / sizeof(ELF_RELOC);
288 symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
289 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
291 for (i = 0; i < rel_size; i++, rpnt++) {
294 symtab_index = ELF32_R_SYM(rpnt->r_info);
296 /* When the dynamic linker bootstrapped itself, it resolved some symbols.
297 Make sure we do not do them again */
298 if (!symtab_index && tpnt->libtype == program_interpreter)
300 if (symtab_index && tpnt->libtype == program_interpreter &&
301 _dl_symbol(strtab + symtab[symtab_index].st_name))
304 #if defined (__SUPPORT_LD_DEBUG__)
305 debug_sym(symtab,strtab,symtab_index);
306 debug_reloc(symtab,strtab,rpnt);
309 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
311 if (res==0) continue;
313 _dl_dprintf(2, "\n%s: ",_dl_progname);
316 _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
320 int reloc_type = ELF32_R_TYPE(rpnt->r_info);
321 #if defined (__SUPPORT_LD_DEBUG__)
322 _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
324 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
330 _dl_dprintf(2, "can't resolve symbol\n");
338 _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
339 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
342 unsigned long reloc_addr;
343 #if defined (__SUPPORT_LD_DEBUG__)
344 unsigned long old_val;
350 reloc_addr = (unsigned long)tpnt->loadaddr + (unsigned long) rpnt->r_offset;
351 reloc_type = ELF32_R_TYPE(rpnt->r_info);
353 #if defined (__SUPPORT_LD_DEBUG__)
354 old_val = reloc_addr;
357 switch (reloc_type) {
365 unsigned long *insns;
367 plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
369 delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2) - (reloc_addr+4);
371 index = (reloc_addr - (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
372 /sizeof(unsigned long);
374 //DPRINTF(" index %x delta %x\n",index,delta);
375 insns = (unsigned long *)reloc_addr;
376 insns[0] = OPCODE_LI(11,index*4);
377 insns[1] = OPCODE_B(delta);
382 _dl_dprintf(2, "%s: (LAZY) can't handle reloc type ",
384 #if defined (__SUPPORT_LD_DEBUG__)
385 _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
388 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
394 /* instructions were modified */
395 PPC_DCBST(reloc_addr);
396 PPC_DCBST(reloc_addr+1);
398 PPC_ICBI(reloc_addr);
399 PPC_ICBI(reloc_addr+1);
402 #if defined (__SUPPORT_LD_DEBUG__)
403 if(_dl_debug_reloc && _dl_debug_detail)
404 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x", old_val, reloc_addr);
411 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
412 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
417 unsigned long *reloc_addr;
418 unsigned long symbol_addr;
419 #if defined (__SUPPORT_LD_DEBUG__)
420 unsigned long old_val;
423 reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
424 reloc_type = ELF32_R_TYPE(rpnt->r_info);
425 symtab_index = ELF32_R_SYM(rpnt->r_info);
427 symname = strtab + symtab[symtab_index].st_name;
431 symbol_addr = (unsigned long) _dl_find_hash(symname, scope,
432 (reloc_type == R_386_JMP_SLOT ? tpnt : NULL), symbolrel);
435 * We want to allow undefined references to weak symbols - this might
436 * have been intentional. We should not be linking local symbols
437 * here, so all bases should be covered.
440 if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
441 #if defined (__SUPPORT_LD_DEBUG__)
442 _dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s'\n",
443 symname, tpnt->libname);
449 #if defined (__SUPPORT_LD_DEBUG__)
450 old_val = *reloc_addr;
452 switch (reloc_type) {
459 int delta = symbol_addr - (unsigned long)reloc_addr;
460 if(delta<<6>>6 != delta){
461 _dl_dprintf(2,"R_PPC_REL24: Reloc out of range\n");
464 *reloc_addr &= 0xfc000003;
465 *reloc_addr |= delta&0x03fffffc;
469 _dl_dprintf(2, "%s: symbol '%s' is type R_PPC_REL24\n\tCompile shared libraries with -fPIC!\n",
470 _dl_progname, symname);
474 *reloc_addr = (unsigned long)tpnt->loadaddr + (unsigned long)rpnt->r_addend;
477 *reloc_addr += symbol_addr;
479 case R_PPC_ADDR16_HA:
480 /* XXX is this correct? */
481 *(short *)reloc_addr += (symbol_addr+0x8000)>>16;
483 case R_PPC_ADDR16_HI:
484 *(short *)reloc_addr += symbol_addr>>16;
486 case R_PPC_ADDR16_LO:
487 *(short *)reloc_addr += symbol_addr;
491 unsigned long targ_addr = (unsigned long)*reloc_addr;
492 int delta = targ_addr - (unsigned long)reloc_addr;
493 if(delta<<6>>6 == delta){
494 *reloc_addr = OPCODE_B(delta);
495 }else if (targ_addr <= 0x01fffffc || targ_addr >= 0xfe000000){
496 *reloc_addr = OPCODE_BA (targ_addr);
502 plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
504 delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2)
505 - (unsigned long)(reloc_addr+1);
507 index = ((unsigned long)reloc_addr -
508 (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
509 /sizeof(unsigned long);
511 //DPRINTF(" index %x delta %x\n",index,delta);
512 reloc_addr[0] = OPCODE_LI(11,index*4);
513 reloc_addr[1] = OPCODE_B(delta);
515 /* instructions were modified */
516 PPC_DCBST(reloc_addr+1);
517 PPC_ICBI(reloc_addr+1);
523 *reloc_addr += symbol_addr;
531 _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
532 #if defined (__SUPPORT_LD_DEBUG__)
533 _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
536 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
542 /* instructions were modified */
543 PPC_DCBST(reloc_addr);
545 PPC_ICBI(reloc_addr);
548 #if defined (__SUPPORT_LD_DEBUG__)
549 if(_dl_debug_reloc && _dl_debug_detail)
550 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
557 /* This is done as a separate step, because there are cases where
558 information is first copied and later initialized. This results in
559 the wrong information being copied. Someone at Sun was complaining about
560 a bug in the handling of _COPY by SVr4, and this may in fact be what he
561 was talking about. Sigh. */
563 _dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope,
564 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
568 unsigned long *reloc_addr;
569 unsigned long symbol_addr;
573 reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
574 reloc_type = ELF32_R_TYPE(rpnt->r_info);
575 if (reloc_type != R_386_COPY)
577 symtab_index = ELF32_R_SYM(rpnt->r_info);
579 symname = strtab + symtab[symtab_index].st_name;
582 symbol_addr = (unsigned long) _dl_find_hash(symname, scope, NULL, copyrel);
583 if (!symbol_addr) goof++;
586 #if defined (__SUPPORT_LD_DEBUG__)
588 _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
589 symname, symtab[symtab_index].st_size,
590 symbol_addr, symtab[symtab_index].st_value);
592 _dl_memcpy((char *) symtab[symtab_index].st_value,
593 (char *) symbol_addr, symtab[symtab_index].st_size);
599 void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
600 unsigned long rel_addr, unsigned long rel_size, int type)
603 (void)_dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
606 int _dl_parse_relocation_information(struct elf_resolve *tpnt,
607 unsigned long rel_addr, unsigned long rel_size, int type)
610 return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
613 int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
614 unsigned long rel_size, int type)
617 return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy);