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 rel_offset_words = PLT_DATA_START_WORDS(num_plt_entries);
400 plt = (Elf32_Word *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
402 /* Set up the lazy PLT entries. */
403 offset = PLT_INITIAL_ENTRY_WORDS;
405 /* Warning: we don't handle double-sized PLT entries */
406 while (i < num_plt_entries) {
407 plt[offset ] = OPCODE_LI(11, i * 4);
408 plt[offset+1] = OPCODE_B((PLT_TRAMPOLINE_ENTRY_WORDS + 2 - (offset+1)) * 4);
412 /* Now, we've modified code. We need to write the changes from
413 the data cache to a second-level unified cache, then make
414 sure that stale data in the instruction cache is removed.
415 (In a multiprocessor system, the effect is more complex.)
416 Most of the PLT shouldn't be in the instruction cache, but
417 there may be a little overlap at the start and the end.
419 Assumes that dcbst and icbi apply to lines of 16 bytes or
420 more. Current known line sizes are 16, 32, and 128 bytes. */
421 for (i = 0; i < rel_offset_words; i += 4)
423 PPC_DCBST (plt + rel_offset_words - 1);
426 PPC_ICBI (plt + rel_offset_words - 1);
431 _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
432 unsigned long rel_addr, unsigned long rel_size,
433 int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
434 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
442 /* Now parse the relocation information */
443 rpnt = (ELF_RELOC *)(intptr_t) (rel_addr + tpnt->loadaddr);
444 rel_size = rel_size / sizeof(ELF_RELOC);
446 symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
447 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
449 for (i = 0; i < rel_size; i++, rpnt++) {
452 symtab_index = ELF32_R_SYM(rpnt->r_info);
454 #if defined (__SUPPORT_LD_DEBUG__)
455 debug_sym(symtab,strtab,symtab_index);
456 debug_reloc(symtab,strtab,rpnt);
459 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
461 if (res==0) continue;
463 _dl_dprintf(2, "\n%s: ",_dl_progname);
466 _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
468 if (unlikely(res <0))
470 int reloc_type = ELF32_R_TYPE(rpnt->r_info);
471 #if defined (__SUPPORT_LD_DEBUG__)
472 _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
474 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
478 if (unlikely(res >0))
480 _dl_dprintf(2, "can't resolve symbol\n");
487 int _dl_parse_relocation_information(struct dyn_elf *rpnt,
488 unsigned long rel_addr, unsigned long rel_size, int type)
490 return _dl_parse(rpnt->dyn, rpnt, rel_addr, rel_size, _dl_do_reloc);
493 /* Should be a static inline instead, but that conflicts with ld_elf.h */
494 int _dl_parse_copy_information(struct dyn_elf *rpnt,
495 unsigned long rel_addr, unsigned long rel_size, int type)