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 (unlikely(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(symname,
213 tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
214 if (unlikely(!finaladdr)) {
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);
226 } else if (finaladdr <= 0x01fffffc) {
227 *reloc_addr = OPCODE_BA (finaladdr);
229 /* Warning: we don't handle double-sized PLT entries */
230 Elf32_Word *plt, *data_words, index, offset;
232 plt = (Elf32_Word *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
233 offset = reloc_addr - plt;
234 index = (offset - PLT_INITIAL_ENTRY_WORDS)/2;
235 data_words = (Elf32_Word *)tpnt->data_words;
238 data_words[index] = finaladdr;
240 *reloc_addr = OPCODE_B ((PLT_LONGBRANCH_ENTRY_WORDS - (offset+1)) * 4);
243 /* instructions were modified */
244 PPC_DCBST(reloc_addr);
246 PPC_ICBI(reloc_addr);
253 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
254 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
259 Elf32_Addr *reloc_addr;
260 Elf32_Addr finaladdr;
262 unsigned long symbol_addr;
263 #if defined (__SUPPORT_LD_DEBUG__)
264 unsigned long old_val;
266 reloc_addr = (Elf32_Addr *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
267 reloc_type = ELF32_R_TYPE(rpnt->r_info);
268 if (reloc_type == R_PPC_RELATIVE) {
269 *reloc_addr = tpnt->loadaddr + rpnt->r_addend;
272 if (reloc_type == R_PPC_NONE)
274 symtab_index = ELF32_R_SYM(rpnt->r_info);
275 symname = strtab + symtab[symtab_index].st_name;
277 symbol_addr = (unsigned long) _dl_find_hash(symname, scope->dyn->symbol_scope,
278 elf_machine_type_class(reloc_type));
280 * We want to allow undefined references to weak symbols - this might
281 * have been intentional. We should not be linking local symbols
282 * here, so all bases should be covered.
284 if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
285 #if defined (__SUPPORT_LD_DEBUG__)
286 _dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s', rel type: %s\n",
287 symname, tpnt->libname, _dl_reltypes(reloc_type));
291 #if defined (__SUPPORT_LD_DEBUG__)
292 old_val = *reloc_addr;
294 finaladdr = (Elf32_Addr) (symbol_addr + rpnt->r_addend);
296 switch (reloc_type) {
299 *reloc_addr = finaladdr;
300 return 0; /* No code code modified */
304 Elf32_Sword delta = finaladdr - (Elf32_Word)reloc_addr;
306 if (delta<<6>>6 == delta) {
307 *reloc_addr = OPCODE_B(delta);
308 } else if (finaladdr <= 0x01fffffc) {
309 *reloc_addr = OPCODE_BA (finaladdr);
311 /* Warning: we don't handle double-sized PLT entries */
312 Elf32_Word *plt, *data_words, index, offset;
314 plt = (Elf32_Word *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
315 offset = reloc_addr - plt;
316 index = (offset - PLT_INITIAL_ENTRY_WORDS)/2;
317 data_words = (Elf32_Word *)tpnt->data_words;
319 data_words[index] = finaladdr;
320 reloc_addr[0] = OPCODE_LI(11,index*4);
321 reloc_addr[1] = OPCODE_B((PLT_LONGBRANCH_ENTRY_WORDS - (offset+1)) * 4);
323 /* instructions were modified */
324 PPC_DCBST(reloc_addr+1);
326 PPC_ICBI(reloc_addr+1);
332 #if defined (__SUPPORT_LD_DEBUG__)
334 _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
335 symname, symtab[symtab_index].st_size,
336 symbol_addr, symtab[symtab_index].st_value);
338 _dl_memcpy((char *) reloc_addr, (char *) finaladdr, symtab[symtab_index].st_size);
340 return 0; /* No code code modified */
342 case R_PPC_ADDR16_HA:
343 *(short *)reloc_addr = (finaladdr + 0x8000)>>16;
345 case R_PPC_ADDR16_HI:
346 *(short *)reloc_addr = finaladdr >> 16;
348 case R_PPC_ADDR16_LO:
349 *(short *)reloc_addr = finaladdr;
354 Elf32_Sword delta = finaladdr - (Elf32_Word)reloc_addr;
355 if(unlikely(delta<<6>>6 != delta)) {
356 _dl_dprintf(2, "%s: symbol '%s' R_PPC_REL24 is out of range.\n\t"
357 "Compile shared libraries with -fPIC!\n",
358 _dl_progname, symname);
361 *reloc_addr = (*reloc_addr & 0xfc000003) | (delta & 0x3fffffc);
365 _dl_dprintf(2,"R_PPC_REL24: Compile shared libraries with -fPIC!\n");
369 _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
370 #if defined (__SUPPORT_LD_DEBUG__)
371 _dl_dprintf(2, "%s ", _dl_reltypes(reloc_type));
374 _dl_dprintf(2, "'%s'\n", symname);
378 /* instructions were modified */
379 PPC_DCBST(reloc_addr);
381 PPC_ICBI(reloc_addr);
383 #if defined (__SUPPORT_LD_DEBUG__)
384 if(_dl_debug_reloc && _dl_debug_detail)
385 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
390 void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
391 unsigned long rel_addr, unsigned long rel_size, int type)
393 struct elf_resolve *tpnt = rpnt->dyn;
394 Elf32_Word *plt, offset, i, num_plt_entries, rel_offset_words;
397 num_plt_entries = rel_size / sizeof(ELF_RELOC);
399 /* When the dynamic linker bootstrapped itself, it resolved some symbols.
400 Make sure we do not do them again */
401 if (tpnt->libtype == program_interpreter)
403 rel_offset_words = PLT_DATA_START_WORDS(num_plt_entries);
404 plt = (Elf32_Word *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
406 /* Set up the lazy PLT entries. */
407 offset = PLT_INITIAL_ENTRY_WORDS;
409 /* Warning: we don't handle double-sized PLT entries */
410 while (i < num_plt_entries) {
411 plt[offset ] = OPCODE_LI(11, i * 4);
412 plt[offset+1] = OPCODE_B((PLT_TRAMPOLINE_ENTRY_WORDS + 2 - (offset+1)) * 4);
416 /* Now, we've modified code. We need to write the changes from
417 the data cache to a second-level unified cache, then make
418 sure that stale data in the instruction cache is removed.
419 (In a multiprocessor system, the effect is more complex.)
420 Most of the PLT shouldn't be in the instruction cache, but
421 there may be a little overlap at the start and the end.
423 Assumes that dcbst and icbi apply to lines of 16 bytes or
424 more. Current known line sizes are 16, 32, and 128 bytes. */
425 for (i = 0; i < rel_offset_words; i += 4)
427 PPC_DCBST (plt + rel_offset_words - 1);
430 PPC_ICBI (plt + rel_offset_words - 1);
435 _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
436 unsigned long rel_addr, unsigned long rel_size,
437 int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
438 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
446 /* When the dynamic linker bootstrapped itself, it resolved some symbols.
447 Make sure we do not do them again */
448 if (tpnt->libtype == program_interpreter)
451 /* Now parse the relocation information */
452 rpnt = (ELF_RELOC *)(intptr_t) (rel_addr + tpnt->loadaddr);
453 rel_size = rel_size / sizeof(ELF_RELOC);
455 symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
456 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
458 for (i = 0; i < rel_size; i++, rpnt++) {
461 symtab_index = ELF32_R_SYM(rpnt->r_info);
463 #if defined (__SUPPORT_LD_DEBUG__)
464 debug_sym(symtab,strtab,symtab_index);
465 debug_reloc(symtab,strtab,rpnt);
468 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
470 if (res==0) continue;
472 _dl_dprintf(2, "\n%s: ",_dl_progname);
475 _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
477 if (unlikely(res <0))
479 int reloc_type = ELF32_R_TYPE(rpnt->r_info);
480 #if defined (__SUPPORT_LD_DEBUG__)
481 _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
483 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
487 if (unlikely(res >0))
489 _dl_dprintf(2, "can't resolve symbol\n");
496 int _dl_parse_relocation_information(struct dyn_elf *rpnt,
497 unsigned long rel_addr, unsigned long rel_size, int type)
499 return _dl_parse(rpnt->dyn, rpnt, rel_addr, rel_size, _dl_do_reloc);
502 /* Should be a static inline instead, but that conflicts with ld_elf.h */
503 int _dl_parse_copy_information(struct dyn_elf *rpnt,
504 unsigned long rel_addr, unsigned long rel_size, int type)