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, tpnt, ELF_RTYPE_CLASS_PLT);
214 if (unlikely(!finaladdr)) {
215 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
218 finaladdr += this_reloc->r_addend;
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 symbol_addr = tpnt->loadaddr; /* For R_PPC_RELATIVE */
269 symtab_index = ELF32_R_SYM(rpnt->r_info);
270 symname = strtab + symtab[symtab_index].st_name;
272 symbol_addr = (unsigned long) _dl_find_hash(symname, scope, tpnt,
273 elf_machine_type_class(reloc_type));
274 /* We want to allow undefined references to weak symbols - this might
275 * have been intentional. We should not be linking local symbols
276 * here, so all bases should be covered.
278 if (unlikely(!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK)) {
279 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
283 #if defined (__SUPPORT_LD_DEBUG__)
284 old_val = *reloc_addr;
286 finaladdr = (Elf32_Addr) (symbol_addr + rpnt->r_addend);
288 switch (reloc_type) {
292 *reloc_addr = finaladdr;
293 goto out_nocode; /* No code code modified */
296 Elf32_Sword delta = finaladdr - (Elf32_Word)reloc_addr;
297 if (delta<<6>>6 == delta) {
298 *reloc_addr = OPCODE_B(delta);
299 } else if (finaladdr <= 0x01fffffc) {
300 *reloc_addr = OPCODE_BA (finaladdr);
302 /* Warning: we don't handle double-sized PLT entries */
303 Elf32_Word *plt, *data_words, index, offset;
305 plt = (Elf32_Word *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
306 offset = reloc_addr - plt;
307 index = (offset - PLT_INITIAL_ENTRY_WORDS)/2;
308 data_words = (Elf32_Word *)tpnt->data_words;
310 data_words[index] = finaladdr;
311 reloc_addr[0] = OPCODE_LI(11,index*4);
312 reloc_addr[1] = OPCODE_B((PLT_LONGBRANCH_ENTRY_WORDS - (offset+1)) * 4);
314 /* instructions were modified */
315 PPC_DCBST(reloc_addr+1);
317 PPC_ICBI(reloc_addr+1);
322 #if defined (__SUPPORT_LD_DEBUG__)
324 _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
325 symname, symtab[symtab_index].st_size,
326 symbol_addr, reloc_addr);
328 _dl_memcpy((char *) reloc_addr, (char *) finaladdr, symtab[symtab_index].st_size);
329 goto out_nocode; /* No code code modified */
330 case R_PPC_ADDR16_HA:
331 finaladdr += 0x8000; /* fall through. */
332 case R_PPC_ADDR16_HI:
333 finaladdr >>= 16; /* fall through. */
334 case R_PPC_ADDR16_LO:
335 *(short *)reloc_addr = finaladdr;
340 Elf32_Sword delta = finaladdr - (Elf32_Word)reloc_addr;
341 if(unlikely(delta<<6>>6 != delta)) {
342 _dl_dprintf(2, "%s: symbol '%s' R_PPC_REL24 is out of range.\n\t"
343 "Compile shared libraries with -fPIC!\n",
344 _dl_progname, symname);
347 *reloc_addr = (*reloc_addr & 0xfc000003) | (delta & 0x3fffffc);
351 _dl_dprintf(2,"R_PPC_REL24: Compile shared libraries with -fPIC!\n");
355 goto out_nocode; /* No code code modified */
357 _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
358 #if defined (__SUPPORT_LD_DEBUG__)
359 _dl_dprintf(2, "%s ", _dl_reltypes(reloc_type));
362 _dl_dprintf(2, "'%s'\n", symname);
366 /* instructions were modified */
367 PPC_DCBST(reloc_addr);
369 PPC_ICBI(reloc_addr);
372 #if defined (__SUPPORT_LD_DEBUG__)
373 if(_dl_debug_reloc && _dl_debug_detail)
374 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
379 void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
380 unsigned long rel_addr, unsigned long rel_size)
382 struct elf_resolve *tpnt = rpnt->dyn;
383 Elf32_Word *plt, offset, i, num_plt_entries, rel_offset_words;
385 num_plt_entries = rel_size / sizeof(ELF_RELOC);
387 rel_offset_words = PLT_DATA_START_WORDS(num_plt_entries);
388 plt = (Elf32_Word *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
390 /* Set up the lazy PLT entries. */
391 offset = PLT_INITIAL_ENTRY_WORDS;
393 /* Warning: we don't handle double-sized PLT entries */
394 while (i < num_plt_entries) {
395 plt[offset ] = OPCODE_LI(11, i * 4);
396 plt[offset+1] = OPCODE_B((PLT_TRAMPOLINE_ENTRY_WORDS + 2 - (offset+1)) * 4);
400 /* Now, we've modified code. We need to write the changes from
401 the data cache to a second-level unified cache, then make
402 sure that stale data in the instruction cache is removed.
403 (In a multiprocessor system, the effect is more complex.)
404 Most of the PLT shouldn't be in the instruction cache, but
405 there may be a little overlap at the start and the end.
407 Assumes that dcbst and icbi apply to lines of 16 bytes or
408 more. Current known line sizes are 16, 32, and 128 bytes. */
409 for (i = 0; i < rel_offset_words; i += 4)
411 PPC_DCBST (plt + rel_offset_words - 1);
414 PPC_ICBI (plt + rel_offset_words - 1);
419 _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
420 unsigned long rel_addr, unsigned long rel_size,
421 int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
422 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
430 /* Now parse the relocation information */
431 rpnt = (ELF_RELOC *)(intptr_t) (rel_addr + tpnt->loadaddr);
432 rel_size = rel_size / sizeof(ELF_RELOC);
434 symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
435 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
437 for (i = 0; i < rel_size; i++, rpnt++) {
440 symtab_index = ELF32_R_SYM(rpnt->r_info);
442 #if defined (__SUPPORT_LD_DEBUG__)
443 debug_sym(symtab,strtab,symtab_index);
444 debug_reloc(symtab,strtab,rpnt);
447 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
449 if (res==0) continue;
451 _dl_dprintf(2, "\n%s: ",_dl_progname);
454 _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
456 if (unlikely(res <0))
458 int reloc_type = ELF32_R_TYPE(rpnt->r_info);
459 #if defined (__SUPPORT_LD_DEBUG__)
460 _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
462 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
466 if (unlikely(res >0))
468 _dl_dprintf(2, "can't resolve symbol\n");
475 int _dl_parse_relocation_information(struct dyn_elf *rpnt,
476 unsigned long rel_addr, unsigned long rel_size)
478 return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);