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;
175 unsigned long insn_addr;
176 unsigned long *insns;
177 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;
237 plt_addr = (unsigned long)tpnt->dynamic_info[DT_PLTGOT] +
238 (unsigned long)tpnt->loadaddr;
240 delta = PLT_LONGBRANCH_ENTRY_WORDS*4 - (insn_addr-plt_addr+4);
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);
248 ptr[index] = new_addr;
250 /* icache sync is not necessary, since this will be a data load */
251 //PPC_DCBST(ptr+index);
253 //PPC_ICBI(ptr+index);
256 insns[0] = OPCODE_B(delta);
260 /* instructions were modified */
270 _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
271 unsigned long rel_addr, unsigned long rel_size,
272 int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
273 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
281 /* Now parse the relocation information */
282 rpnt = (ELF_RELOC *)(intptr_t) (rel_addr + tpnt->loadaddr);
283 rel_size = rel_size / sizeof(ELF_RELOC);
285 symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
286 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
288 for (i = 0; i < rel_size; i++, rpnt++) {
291 symtab_index = ELF32_R_SYM(rpnt->r_info);
293 /* When the dynamic linker bootstrapped itself, it resolved some symbols.
294 Make sure we do not do them again */
295 if (!symtab_index && tpnt->libtype == program_interpreter)
297 if (symtab_index && tpnt->libtype == program_interpreter &&
298 _dl_symbol(strtab + symtab[symtab_index].st_name))
301 #if defined (__SUPPORT_LD_DEBUG__)
302 debug_sym(symtab,strtab,symtab_index);
303 debug_reloc(symtab,strtab,rpnt);
306 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
308 if (res==0) continue;
310 _dl_dprintf(2, "\n%s: ",_dl_progname);
313 _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
317 int reloc_type = ELF32_R_TYPE(rpnt->r_info);
318 #if defined (__SUPPORT_LD_DEBUG__)
319 _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
321 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
327 _dl_dprintf(2, "can't resolve symbol\n");
335 _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
336 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
339 unsigned long reloc_addr;
340 #if defined (__SUPPORT_LD_DEBUG__)
341 unsigned long old_val;
347 reloc_addr = (unsigned long)tpnt->loadaddr + (unsigned long) rpnt->r_offset;
348 reloc_type = ELF32_R_TYPE(rpnt->r_info);
350 #if defined (__SUPPORT_LD_DEBUG__)
351 old_val = reloc_addr;
354 switch (reloc_type) {
363 unsigned long *insns;
365 plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
367 delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2) - (reloc_addr+4);
369 index = (reloc_addr - (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
370 /sizeof(unsigned long);
372 //DPRINTF(" index %x delta %x\n",index,delta);
373 insns = (unsigned long *)reloc_addr;
374 insns[0] = OPCODE_LI(11,index*4);
375 insns[1] = OPCODE_B(delta);
380 _dl_dprintf(2, "%s: (LAZY) can't handle reloc type ",
382 #if defined (__SUPPORT_LD_DEBUG__)
383 _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
386 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
392 /* instructions were modified */
393 PPC_DCBST(reloc_addr);
394 PPC_DCBST(reloc_addr+4);
396 PPC_ICBI(reloc_addr);
397 PPC_ICBI(reloc_addr+4);
400 #if defined (__SUPPORT_LD_DEBUG__)
401 if(_dl_debug_reloc && _dl_debug_detail)
402 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x", old_val, reloc_addr);
409 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
410 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
415 unsigned long *reloc_addr;
416 unsigned long symbol_addr;
417 #if defined (__SUPPORT_LD_DEBUG__)
418 unsigned long old_val;
421 reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
422 reloc_type = ELF32_R_TYPE(rpnt->r_info);
423 symtab_index = ELF32_R_SYM(rpnt->r_info);
425 symname = strtab + symtab[symtab_index].st_name;
429 symbol_addr = (unsigned long) _dl_find_hash(symname, scope,
430 (reloc_type == R_PPC_JMP_SLOT ? tpnt : NULL), symbolrel);
433 * We want to allow undefined references to weak symbols - this might
434 * have been intentional. We should not be linking local symbols
435 * here, so all bases should be covered.
438 if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
439 #if defined (__SUPPORT_LD_DEBUG__)
440 _dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s'\n",
441 symname, tpnt->libname);
447 #if defined (__SUPPORT_LD_DEBUG__)
448 old_val = *reloc_addr;
450 switch (reloc_type) {
457 unsigned long delta = symbol_addr - (unsigned long)reloc_addr;
458 if(delta<<6>>6 != delta){
459 _dl_dprintf(2,"R_PPC_REL24: Reloc out of range\n");
462 *reloc_addr &= 0xfc000003;
463 *reloc_addr |= delta&0x03fffffc;
467 _dl_dprintf(2, "%s: symbol '%s' is type R_PPC_REL24\n\tCompile shared libraries with -fPIC!\n",
468 _dl_progname, symname);
472 *reloc_addr = (unsigned long)tpnt->loadaddr + (unsigned long)rpnt->r_addend;
475 *reloc_addr += symbol_addr;
477 case R_PPC_ADDR16_HA:
478 /* XXX is this correct? */
479 *(short *)reloc_addr += (symbol_addr+0x8000)>>16;
481 case R_PPC_ADDR16_HI:
482 *(short *)reloc_addr += symbol_addr>>16;
484 case R_PPC_ADDR16_LO:
485 *(short *)reloc_addr += symbol_addr;
489 unsigned long targ_addr = (unsigned long)*reloc_addr;
490 unsigned long delta = targ_addr - (unsigned long)reloc_addr;
491 if(delta<<6>>6 == delta){
492 *reloc_addr = OPCODE_B(delta);
493 }else if (targ_addr <= 0x01fffffc || targ_addr >= 0xfe000000){
494 *reloc_addr = OPCODE_BA (targ_addr);
498 unsigned long delta2;
499 unsigned long *plt, *ptr;
500 plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
502 delta2 = (unsigned long)(plt+PLT_LONGBRANCH_ENTRY_WORDS)
503 - (unsigned long)(reloc_addr+1);
505 index = ((unsigned long)reloc_addr -
506 (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
507 /sizeof(unsigned long);
509 //DPRINTF(" index %x delta %x\n",index,delta2);
510 ptr = (unsigned long *)tpnt->data_words;
511 ptr[index] = targ_addr;
512 reloc_addr[0] = OPCODE_LI(11,index*4);
513 reloc_addr[1] = OPCODE_B(delta2);
515 /* instructions were modified */
516 PPC_DCBST(reloc_addr+1);
518 PPC_ICBI(reloc_addr+1);
524 *reloc_addr += symbol_addr;
532 _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
533 #if defined (__SUPPORT_LD_DEBUG__)
534 _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
537 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
543 /* instructions were modified */
544 PPC_DCBST(reloc_addr);
546 PPC_ICBI(reloc_addr);
549 #if defined (__SUPPORT_LD_DEBUG__)
550 if(_dl_debug_reloc && _dl_debug_detail)
551 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
558 /* This is done as a separate step, because there are cases where
559 information is first copied and later initialized. This results in
560 the wrong information being copied. Someone at Sun was complaining about
561 a bug in the handling of _COPY by SVr4, and this may in fact be what he
562 was talking about. Sigh. */
564 _dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope,
565 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
569 unsigned long *reloc_addr;
570 unsigned long symbol_addr;
574 reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
575 reloc_type = ELF32_R_TYPE(rpnt->r_info);
576 if (reloc_type != R_PPC_COPY)
578 symtab_index = ELF32_R_SYM(rpnt->r_info);
580 symname = strtab + symtab[symtab_index].st_name;
583 symbol_addr = (unsigned long) _dl_find_hash(symname, scope, NULL, copyrel);
584 if (!symbol_addr) goof++;
587 #if defined (__SUPPORT_LD_DEBUG__)
589 _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
590 symname, symtab[symtab_index].st_size,
591 symbol_addr, symtab[symtab_index].st_value);
593 _dl_memcpy((char *) reloc_addr,
594 (char *) symbol_addr, symtab[symtab_index].st_size);
600 void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
601 unsigned long rel_addr, unsigned long rel_size, int type)
604 (void)_dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
607 int _dl_parse_relocation_information(struct elf_resolve *tpnt,
608 unsigned long rel_addr, unsigned long rel_size, int type)
611 return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
614 int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
615 unsigned long rel_size, int type)
618 return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy);