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-2004 Erik Andersen
6 * Copyright (C) 2004 Joakim Tjernlund
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. The name of the above contributors may not be
16 * used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #if defined (__SUPPORT_LD_DEBUG__)
33 static const char *_dl_reltypes_tab[] =
34 { "R_PPC_NONE", "R_PPC_ADDR32", "R_PPC_ADDR24", "R_PPC_ADDR16",
35 "R_PPC_ADDR16_LO", "R_PPC_ADDR16_HI", "R_PPC_ADDR16_HA",
36 "R_PPC_ADDR14", "R_PPC_ADDR14_BRTAKEN", "R_PPC_ADDR14_BRNTAKEN",
37 "R_PPC_REL24", "R_PPC_REL14", "R_PPC_REL14_BRTAKEN",
38 "R_PPC_REL14_BRNTAKEN", "R_PPC_GOT16", "R_PPC_GOT16_LO",
39 "R_PPC_GOT16_HI", "R_PPC_GOT16_HA", "R_PPC_PLTREL24",
40 "R_PPC_COPY", "R_PPC_GLOB_DAT", "R_PPC_JMP_SLOT", "R_PPC_RELATIVE",
41 "R_PPC_LOCAL24PC", "R_PPC_UADDR32", "R_PPC_UADDR16", "R_PPC_REL32",
42 "R_PPC_PLT32", "R_PPC_PLTREL32", "R_PPC_PLT16_LO", "R_PPC_PLT16_HI",
43 "R_PPC_PLT16_HA", "R_PPC_SDAREL16", "R_PPC_SECTOFF",
44 "R_PPC_SECTOFF_LO", "R_PPC_SECTOFF_HI", "R_PPC_SECTOFF_HA",
48 _dl_reltypes(int type)
53 if (type >= (int)(sizeof (_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) ||
54 NULL == (str = _dl_reltypes_tab[type]))
56 str =_dl_simple_ltoa( buf, (unsigned long)(type));
62 void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
67 _dl_dprintf(_dl_debug_file, "\n%s\n\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",
68 strtab + symtab[symtab_index].st_name,
69 symtab[symtab_index].st_value,
70 symtab[symtab_index].st_size,
71 symtab[symtab_index].st_info,
72 symtab[symtab_index].st_other,
73 symtab[symtab_index].st_shndx);
79 void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt)
85 symtab_index = ELF32_R_SYM(rpnt->r_info);
86 sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0";
89 _dl_dprintf(_dl_debug_file, "\n\t");
91 _dl_dprintf(_dl_debug_file, "\n%s\n\t", sym);
92 #ifdef ELF_USES_RELOCA
93 _dl_dprintf(_dl_debug_file, "%s\toffset=%x\taddend=%x",
94 _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
98 _dl_dprintf(_dl_debug_file, "%s\toffset=%x\n",
99 _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
106 extern int _dl_linux_resolve(void);
108 void _dl_init_got(unsigned long *plt,struct elf_resolve *tpnt)
111 Elf32_Word num_plt_entries;
112 Elf32_Word data_words;
113 Elf32_Word rel_offset_words;
114 Elf32_Word dlrr = (Elf32_Word) _dl_linux_resolve;
116 num_plt_entries = tpnt->dynamic_info[DT_PLTRELSZ] / sizeof(ELF_RELOC);
117 rel_offset_words = PLT_DATA_START_WORDS(num_plt_entries);
118 data_words = (Elf32_Word) (plt + rel_offset_words);
119 tpnt->data_words = data_words;
121 plt[PLT_LONGBRANCH_ENTRY_WORDS] = OPCODE_ADDIS_HI(11, 11, data_words);
122 plt[PLT_LONGBRANCH_ENTRY_WORDS+1] = OPCODE_LWZ(11,data_words,11);
124 plt[PLT_LONGBRANCH_ENTRY_WORDS+2] = OPCODE_MTCTR(11);
125 plt[PLT_LONGBRANCH_ENTRY_WORDS+3] = OPCODE_BCTR();
129 tramp = (Elf32_Word *) (plt + PLT_TRAMPOLINE_ENTRY_WORDS);
131 /* For the long entries, subtract off data_words. */
132 tramp[0] = OPCODE_ADDIS_HI(11,11,-data_words);
133 tramp[1] = OPCODE_ADDI(11,11,-data_words);
135 /* Multiply index of entry by 3 (in r11). */
136 tramp[2] = OPCODE_SLWI(12,11,1);
137 tramp[3] = OPCODE_ADD(11,12,11);
138 if (dlrr <= 0x01fffffc || dlrr >= 0xfe000000) {
139 /* Load address of link map in r12. */
140 tramp[4] = OPCODE_LI (12, (Elf32_Word) tpnt);
141 tramp[5] = OPCODE_ADDIS_HI (12, 12, (Elf32_Word) tpnt);
143 /* Call _dl_linux_resolve . */
144 tramp[6] = OPCODE_BA (dlrr);
146 /* Get address of _dl_linux_resolve in CTR. */
147 tramp[4] = OPCODE_LI(12,dlrr);
148 tramp[5] = OPCODE_ADDIS_HI(12,12,dlrr);
149 tramp[6] = OPCODE_MTCTR(12);
151 /* Load address of link map in r12. */
152 tramp[7] = OPCODE_LI(12,(Elf32_Word) tpnt);
153 tramp[8] = OPCODE_ADDIS_HI(12,12,(Elf32_Word) tpnt);
155 /* Call _dl_linux_resolve. */
156 tramp[9] = OPCODE_BCTR();
172 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
174 ELF_RELOC *this_reloc;
180 Elf32_Addr *reloc_addr;
181 Elf32_Addr finaladdr;
184 rel_addr = (ELF_RELOC *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
186 this_reloc = (void *)rel_addr + reloc_entry;
187 symtab_index = ELF32_R_SYM(this_reloc->r_info);
189 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
190 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
191 symname = strtab + symtab[symtab_index].st_name;
193 #if defined (__SUPPORT_LD_DEBUG__)
194 debug_sym(symtab,strtab,symtab_index);
195 debug_reloc(symtab,strtab,this_reloc);
197 if (ELF32_R_TYPE(this_reloc->r_info) != R_PPC_JMP_SLOT) {
198 _dl_dprintf(2, "%s: Incorrect relocation type in jump relocation\n", _dl_progname);
203 /* Address of dump instruction to fix up */
204 reloc_addr = (Elf32_Addr *) (tpnt->loadaddr + this_reloc->r_offset);
206 #if defined (__SUPPORT_LD_DEBUG__)
207 if(_dl_debug_reloc && _dl_debug_detail)
208 _dl_dprintf(_dl_debug_file, "\n\tResolving symbol %s %x --> ", symname, (Elf32_Addr)reloc_addr);
211 /* Get the address of the GOT entry */
212 finaladdr = (Elf32_Addr) _dl_find_hash(strtab + symtab[symtab_index].st_name,
213 tpnt->symbol_scope, tpnt, resolver);
215 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _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", finaladdr);
223 delta = finaladdr - (Elf32_Word)reloc_addr;
224 if (delta<<6>>6 == delta) {
225 *reloc_addr = OPCODE_B(delta);
227 /* this will almost never be true */
228 } else if (finaladdr <= 0x01fffffc || finaladdr >= 0xfe000000) {
229 *reloc_addr = OPCODE_BA (finaladdr);
232 /* Warning: we don't handle double-sized PLT entries */
233 Elf32_Word *plt, *data_words, index, offset;
235 plt = (Elf32_Word *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
236 offset = reloc_addr - plt;
237 index = (offset - PLT_INITIAL_ENTRY_WORDS)/2;
238 data_words = (Elf32_Word *)tpnt->data_words;
241 data_words[index] = finaladdr;
243 *reloc_addr = OPCODE_B ((PLT_LONGBRANCH_ENTRY_WORDS - (offset+1)) * 4);
246 /* instructions were modified */
247 PPC_DCBST(reloc_addr);
249 PPC_ICBI(reloc_addr);
256 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
257 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
262 Elf32_Addr *reloc_addr;
263 Elf32_Addr finaladdr;
264 struct dyn_elf *sym_scope;
266 unsigned long symbol_addr;
267 #if defined (__SUPPORT_LD_DEBUG__)
268 unsigned long old_val;
270 reloc_addr = (Elf32_Addr *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
271 reloc_type = ELF32_R_TYPE(rpnt->r_info);
272 if (reloc_type == R_PPC_RELATIVE) {
273 *reloc_addr = tpnt->loadaddr + rpnt->r_addend;
276 if (reloc_type == R_PPC_NONE)
278 symtab_index = ELF32_R_SYM(rpnt->r_info);
279 symname = strtab + symtab[symtab_index].st_name;
282 sym_scope = scope->dyn->symbol_scope;
284 /* Funny, this works too and appears to be much faster. */
287 if (reloc_type == R_PPC_COPY) {
288 sym_scope = scope->next;
289 tpnt = NULL; /* To be or not to be ...*/
291 symbol_addr = (unsigned long) _dl_find_hash(symname, sym_scope,
292 (reloc_type == R_PPC_JMP_SLOT ? tpnt : NULL),
293 (reloc_type == R_PPC_COPY ? copyrel : symbolrel));
295 * We want to allow undefined references to weak symbols - this might
296 * have been intentional. We should not be linking local symbols
297 * here, so all bases should be covered.
299 if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
300 #if defined (__SUPPORT_LD_DEBUG__)
301 _dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s', rel type: %s\n",
302 symname, tpnt->libname, _dl_reltypes(reloc_type));
306 #if defined (__SUPPORT_LD_DEBUG__)
307 old_val = *reloc_addr;
309 finaladdr = (Elf32_Addr) (symbol_addr + rpnt->r_addend);
311 switch (reloc_type) {
314 *reloc_addr = finaladdr;
315 return 0; /* No code code modified */
319 Elf32_Sword delta = finaladdr - (Elf32_Word)reloc_addr;
321 if (delta<<6>>6 == delta) {
322 *reloc_addr = OPCODE_B(delta);
324 /* this will almost never be true */
325 } else if (finaladdr <= 0x01fffffc || finaladdr >= 0xfe000000) {
326 *reloc_addr = OPCODE_BA (finaladdr);
329 /* Warning: we don't handle double-sized PLT entries */
330 Elf32_Word *plt, *data_words, index, offset;
332 plt = (Elf32_Word *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
333 offset = reloc_addr - plt;
334 index = (offset - PLT_INITIAL_ENTRY_WORDS)/2;
335 data_words = (Elf32_Word *)tpnt->data_words;
337 data_words[index] = finaladdr;
338 reloc_addr[0] = OPCODE_LI(11,index*4);
339 reloc_addr[1] = OPCODE_B((PLT_LONGBRANCH_ENTRY_WORDS - (offset+1)) * 4);
341 /* instructions were modified */
342 PPC_DCBST(reloc_addr+1);
344 PPC_ICBI(reloc_addr+1);
350 #if defined (__SUPPORT_LD_DEBUG__)
352 _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
353 symname, symtab[symtab_index].st_size,
354 symbol_addr, symtab[symtab_index].st_value);
356 _dl_memcpy((char *) reloc_addr, (char *) finaladdr, symtab[symtab_index].st_size);
358 return 0; /* No code code modified */
360 case R_PPC_ADDR16_HA:
361 *(short *)reloc_addr = (finaladdr + 0x8000)>>16;
363 case R_PPC_ADDR16_HI:
364 *(short *)reloc_addr = finaladdr >> 16;
366 case R_PPC_ADDR16_LO:
367 *(short *)reloc_addr = finaladdr;
371 Elf32_Sword delta = finaladdr - (Elf32_Word)reloc_addr;
372 if(delta<<6>>6 != delta){
373 _dl_dprintf(2, "%s: symbol '%s' R_PPC_REL24 is out of range.\n\t"
374 "Compile shared libraries with -fPIC!\n",
375 _dl_progname, symname);
378 *reloc_addr = (*reloc_addr & 0xfc000003) | (delta & 0x3fffffc);
382 _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
383 #if defined (__SUPPORT_LD_DEBUG__)
384 _dl_dprintf(2, "%s ", _dl_reltypes(reloc_type));
387 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
391 /* instructions were modified */
392 PPC_DCBST(reloc_addr);
394 PPC_ICBI(reloc_addr);
396 #if defined (__SUPPORT_LD_DEBUG__)
397 if(_dl_debug_reloc && _dl_debug_detail)
398 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
403 void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
404 unsigned long rel_addr, unsigned long rel_size, int type)
406 struct elf_resolve *tpnt = rpnt->dyn;
407 Elf32_Word *plt, offset, i, num_plt_entries, rel_offset_words;
410 num_plt_entries = rel_size / sizeof(ELF_RELOC);
412 /* When the dynamic linker bootstrapped itself, it resolved some symbols.
413 Make sure we do not do them again */
414 if (tpnt->libtype == program_interpreter)
416 rel_offset_words = PLT_DATA_START_WORDS(num_plt_entries);
417 plt = (Elf32_Word *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
419 /* Set up the lazy PLT entries. */
420 offset = PLT_INITIAL_ENTRY_WORDS;
422 /* Warning: we don't handle double-sized PLT entries */
423 while (i < num_plt_entries) {
424 plt[offset ] = OPCODE_LI(11, i * 4);
425 plt[offset+1] = OPCODE_B((PLT_TRAMPOLINE_ENTRY_WORDS + 2 - (offset+1)) * 4);
429 /* Now, we've modified code. We need to write the changes from
430 the data cache to a second-level unified cache, then make
431 sure that stale data in the instruction cache is removed.
432 (In a multiprocessor system, the effect is more complex.)
433 Most of the PLT shouldn't be in the instruction cache, but
434 there may be a little overlap at the start and the end.
436 Assumes that dcbst and icbi apply to lines of 16 bytes or
437 more. Current known line sizes are 16, 32, and 128 bytes. */
438 for (i = 0; i < rel_offset_words; i += 4)
440 PPC_DCBST (plt + rel_offset_words - 1);
443 PPC_ICBI (plt + rel_offset_words - 1);
448 _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
449 unsigned long rel_addr, unsigned long rel_size,
450 int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
451 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
459 /* Now parse the relocation information */
460 rpnt = (ELF_RELOC *)(intptr_t) (rel_addr + tpnt->loadaddr);
461 rel_size = rel_size / sizeof(ELF_RELOC);
463 symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
464 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
466 for (i = 0; i < rel_size; i++, rpnt++) {
469 symtab_index = ELF32_R_SYM(rpnt->r_info);
471 /* When the dynamic linker bootstrapped itself, it resolved some symbols.
472 Make sure we do not do them again */
473 if (!symtab_index && tpnt->libtype == program_interpreter)
475 if (symtab_index && tpnt->libtype == program_interpreter &&
476 _dl_symbol(strtab + symtab[symtab_index].st_name))
479 #if defined (__SUPPORT_LD_DEBUG__)
480 debug_sym(symtab,strtab,symtab_index);
481 debug_reloc(symtab,strtab,rpnt);
484 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
486 if (res==0) continue;
488 _dl_dprintf(2, "\n%s: ",_dl_progname);
491 _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
495 int reloc_type = ELF32_R_TYPE(rpnt->r_info);
496 #if defined (__SUPPORT_LD_DEBUG__)
497 _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
499 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
505 _dl_dprintf(2, "can't resolve symbol\n");
512 int _dl_parse_relocation_information(struct dyn_elf *rpnt,
513 unsigned long rel_addr, unsigned long rel_size, int type)
515 return _dl_parse(rpnt->dyn, rpnt, rel_addr, rel_size, _dl_do_reloc);
518 /* Should be a static inline instead, but that conflicts with ld_elf.h */
519 int _dl_parse_copy_information(struct dyn_elf *rpnt,
520 unsigned long rel_addr, unsigned long rel_size, int type)