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
34 extern int _dl_linux_resolve(void);
36 void _dl_init_got(unsigned long *plt,struct elf_resolve *tpnt)
39 Elf32_Word num_plt_entries;
40 Elf32_Word data_words;
41 Elf32_Word rel_offset_words;
42 Elf32_Word dlrr = (Elf32_Word) _dl_linux_resolve;
44 num_plt_entries = tpnt->dynamic_info[DT_PLTRELSZ] / sizeof(ELF_RELOC);
45 rel_offset_words = PLT_DATA_START_WORDS(num_plt_entries);
46 data_words = (Elf32_Word) (plt + rel_offset_words);
47 tpnt->data_words = data_words;
49 plt[PLT_LONGBRANCH_ENTRY_WORDS] = OPCODE_ADDIS_HI(11, 11, data_words);
50 plt[PLT_LONGBRANCH_ENTRY_WORDS+1] = OPCODE_LWZ(11,data_words,11);
52 plt[PLT_LONGBRANCH_ENTRY_WORDS+2] = OPCODE_MTCTR(11);
53 plt[PLT_LONGBRANCH_ENTRY_WORDS+3] = OPCODE_BCTR();
57 tramp = (Elf32_Word *) (plt + PLT_TRAMPOLINE_ENTRY_WORDS);
59 /* For the long entries, subtract off data_words. */
60 tramp[0] = OPCODE_ADDIS_HI(11,11,-data_words);
61 tramp[1] = OPCODE_ADDI(11,11,-data_words);
63 /* Multiply index of entry by 3 (in r11). */
64 tramp[2] = OPCODE_SLWI(12,11,1);
65 tramp[3] = OPCODE_ADD(11,12,11);
66 if (dlrr <= 0x01fffffc || dlrr >= 0xfe000000) {
67 /* Load address of link map in r12. */
68 tramp[4] = OPCODE_LI (12, (Elf32_Word) tpnt);
69 tramp[5] = OPCODE_ADDIS_HI (12, 12, (Elf32_Word) tpnt);
71 /* Call _dl_linux_resolve . */
72 tramp[6] = OPCODE_BA (dlrr);
74 /* Get address of _dl_linux_resolve in CTR. */
75 tramp[4] = OPCODE_LI(12,dlrr);
76 tramp[5] = OPCODE_ADDIS_HI(12,12,dlrr);
77 tramp[6] = OPCODE_MTCTR(12);
79 /* Load address of link map in r12. */
80 tramp[7] = OPCODE_LI(12,(Elf32_Word) tpnt);
81 tramp[8] = OPCODE_ADDIS_HI(12,12,(Elf32_Word) tpnt);
83 /* Call _dl_linux_resolve. */
84 tramp[9] = OPCODE_BCTR();
100 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
102 ELF_RELOC *this_reloc;
108 Elf32_Addr *reloc_addr;
109 Elf32_Addr finaladdr;
112 rel_addr = (ELF_RELOC *)tpnt->dynamic_info[DT_JMPREL];
114 this_reloc = (void *)rel_addr + reloc_entry;
115 symtab_index = ELF32_R_SYM(this_reloc->r_info);
117 symtab = (Elf32_Sym *)tpnt->dynamic_info[DT_SYMTAB];
118 strtab = (char *)tpnt->dynamic_info[DT_STRTAB];
119 symname = strtab + symtab[symtab_index].st_name;
121 debug_sym(symtab,strtab,symtab_index);
122 debug_reloc(symtab,strtab,this_reloc);
124 #if defined (__SUPPORT_LD_DEBUG__)
125 if (unlikely(ELF32_R_TYPE(this_reloc->r_info) != R_PPC_JMP_SLOT)) {
126 _dl_dprintf(2, "%s: Incorrect relocation type in jump relocation\n", _dl_progname);
131 /* Address of dump instruction to fix up */
132 reloc_addr = (Elf32_Addr *) (tpnt->loadaddr + this_reloc->r_offset);
134 #if defined (__SUPPORT_LD_DEBUG__)
135 if (_dl_debug_reloc && _dl_debug_detail)
136 _dl_dprintf(_dl_debug_file, "\n\tResolving symbol %s %x --> ", symname, (Elf32_Addr)reloc_addr);
139 /* Get the address of the GOT entry */
140 finaladdr = (Elf32_Addr) _dl_find_hash(symname,
141 tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT);
142 if (unlikely(!finaladdr)) {
143 _dl_dprintf(2, "%s: can't resolve symbol '%s' in lib '%s'.\n", _dl_progname, symname, tpnt->libname);
146 finaladdr += this_reloc->r_addend;
147 #if defined (__SUPPORT_LD_DEBUG__)
148 if (_dl_debug_reloc && _dl_debug_detail)
149 _dl_dprintf(_dl_debug_file, "%x\n", finaladdr);
151 delta = finaladdr - (Elf32_Word)reloc_addr;
152 if (delta<<6>>6 == delta) {
153 *reloc_addr = OPCODE_B(delta);
154 } else if (finaladdr <= 0x01fffffc) {
155 *reloc_addr = OPCODE_BA (finaladdr);
157 /* Warning: we don't handle double-sized PLT entries */
158 Elf32_Word *plt, *data_words, index, offset;
160 plt = (Elf32_Word *)tpnt->dynamic_info[DT_PLTGOT];
161 offset = reloc_addr - plt;
162 index = (offset - PLT_INITIAL_ENTRY_WORDS)/2;
163 data_words = (Elf32_Word *)tpnt->data_words;
166 data_words[index] = finaladdr;
168 *reloc_addr = OPCODE_B ((PLT_LONGBRANCH_ENTRY_WORDS - (offset+1)) * 4);
171 /* instructions were modified */
172 PPC_DCBST(reloc_addr);
174 PPC_ICBI(reloc_addr);
181 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
182 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
187 Elf32_Addr *reloc_addr;
188 Elf32_Addr finaladdr;
190 unsigned long symbol_addr;
191 #if defined (__SUPPORT_LD_DEBUG__)
192 unsigned long old_val;
194 reloc_addr = (Elf32_Addr *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
195 reloc_type = ELF32_R_TYPE(rpnt->r_info);
196 symbol_addr = tpnt->loadaddr; /* For R_PPC_RELATIVE */
197 symtab_index = ELF32_R_SYM(rpnt->r_info);
198 symname = strtab + symtab[symtab_index].st_name;
200 symbol_addr = (unsigned long) _dl_find_hash(symname, scope, tpnt,
201 elf_machine_type_class(reloc_type));
202 /* We want to allow undefined references to weak symbols - this might
203 * have been intentional. We should not be linking local symbols
204 * here, so all bases should be covered.
206 if (unlikely(!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK))
209 #if defined (__SUPPORT_LD_DEBUG__)
210 old_val = *reloc_addr;
212 finaladdr = (Elf32_Addr) (symbol_addr + rpnt->r_addend);
214 switch (reloc_type) {
218 *reloc_addr = finaladdr;
219 goto out_nocode; /* No code code modified */
222 Elf32_Sword delta = finaladdr - (Elf32_Word)reloc_addr;
223 if (delta<<6>>6 == delta) {
224 *reloc_addr = OPCODE_B(delta);
225 } else if (finaladdr <= 0x01fffffc) {
226 *reloc_addr = OPCODE_BA (finaladdr);
228 /* Warning: we don't handle double-sized PLT entries */
229 Elf32_Word *plt, *data_words, index, offset;
231 plt = (Elf32_Word *)tpnt->dynamic_info[DT_PLTGOT];
232 offset = reloc_addr - plt;
233 index = (offset - PLT_INITIAL_ENTRY_WORDS)/2;
234 data_words = (Elf32_Word *)tpnt->data_words;
236 data_words[index] = finaladdr;
237 reloc_addr[0] = OPCODE_LI(11,index*4);
238 reloc_addr[1] = OPCODE_B((PLT_LONGBRANCH_ENTRY_WORDS - (offset+1)) * 4);
240 /* instructions were modified */
241 PPC_DCBST(reloc_addr+1);
243 PPC_ICBI(reloc_addr+1);
248 #if defined (__SUPPORT_LD_DEBUG__)
250 _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
251 symname, symtab[symtab_index].st_size,
252 symbol_addr, reloc_addr);
254 _dl_memcpy((char *) reloc_addr, (char *) finaladdr, symtab[symtab_index].st_size);
255 goto out_nocode; /* No code code modified */
256 case R_PPC_ADDR16_HA:
257 finaladdr += 0x8000; /* fall through. */
258 case R_PPC_ADDR16_HI:
259 finaladdr >>= 16; /* fall through. */
260 case R_PPC_ADDR16_LO:
261 *(short *)reloc_addr = finaladdr;
266 Elf32_Sword delta = finaladdr - (Elf32_Word)reloc_addr;
267 if (unlikely(delta<<6>>6 != delta)) {
268 _dl_dprintf(2, "%s: symbol '%s' R_PPC_REL24 is out of range.\n\t"
269 "Compile shared libraries with -fPIC!\n",
270 _dl_progname, symname);
273 *reloc_addr = (*reloc_addr & 0xfc000003) | (delta & 0x3fffffc);
277 _dl_dprintf(2,"R_PPC_REL24: Compile shared libraries with -fPIC!\n");
281 goto out_nocode; /* No code code modified */
283 _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
284 #if defined (__SUPPORT_LD_DEBUG__)
285 _dl_dprintf(2, "%s ", _dl_reltypes(reloc_type));
288 _dl_dprintf(2, "'%s'\n", symname);
292 /* instructions were modified */
293 PPC_DCBST(reloc_addr);
295 PPC_ICBI(reloc_addr);
298 #if defined (__SUPPORT_LD_DEBUG__)
299 if (_dl_debug_reloc && _dl_debug_detail)
300 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
305 void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
306 unsigned long rel_addr, unsigned long rel_size)
308 struct elf_resolve *tpnt = rpnt->dyn;
309 Elf32_Word *plt, offset, i, num_plt_entries, rel_offset_words;
311 num_plt_entries = rel_size / sizeof(ELF_RELOC);
313 rel_offset_words = PLT_DATA_START_WORDS(num_plt_entries);
314 plt = (Elf32_Word *)tpnt->dynamic_info[DT_PLTGOT];
316 /* Set up the lazy PLT entries. */
317 offset = PLT_INITIAL_ENTRY_WORDS;
319 /* Warning: we don't handle double-sized PLT entries */
320 while (i < num_plt_entries) {
321 plt[offset ] = OPCODE_LI(11, i * 4);
322 plt[offset+1] = OPCODE_B((PLT_TRAMPOLINE_ENTRY_WORDS + 2 - (offset+1)) * 4);
326 /* Now, we've modified code. We need to write the changes from
327 the data cache to a second-level unified cache, then make
328 sure that stale data in the instruction cache is removed.
329 (In a multiprocessor system, the effect is more complex.)
330 Most of the PLT shouldn't be in the instruction cache, but
331 there may be a little overlap at the start and the end.
333 Assumes that dcbst and icbi apply to lines of 16 bytes or
334 more. Current known line sizes are 16, 32, and 128 bytes. */
335 for (i = 0; i < rel_offset_words; i += 4)
337 PPC_DCBST (plt + rel_offset_words - 1);
340 PPC_ICBI (plt + rel_offset_words - 1);
345 _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
346 unsigned long rel_addr, unsigned long rel_size,
347 int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
348 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
356 /* Now parse the relocation information */
357 rpnt = (ELF_RELOC *)(intptr_t)rel_addr;
358 rel_size = rel_size / sizeof(ELF_RELOC);
360 symtab = (Elf32_Sym *)(intptr_t)tpnt->dynamic_info[DT_SYMTAB];
361 strtab = (char *)tpnt->dynamic_info[DT_STRTAB];
363 for (i = 0; i < rel_size; i++, rpnt++) {
366 symtab_index = ELF32_R_SYM(rpnt->r_info);
368 debug_sym(symtab,strtab,symtab_index);
369 debug_reloc(symtab,strtab,rpnt);
371 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
373 if (res==0) continue;
375 _dl_dprintf(2, "\n%s: ",_dl_progname);
378 _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
380 if (unlikely(res <0))
382 int reloc_type = ELF32_R_TYPE(rpnt->r_info);
383 #if defined (__SUPPORT_LD_DEBUG__)
384 _dl_dprintf(2, "can't handle reloc type '%s' in lib '%s'\n", _dl_reltypes(reloc_type), tpnt->libname);
386 _dl_dprintf(2, "can't handle reloc type %x in lib '%s'\n", reloc_type, tpnt->libname);
390 if (unlikely(res >0))
392 _dl_dprintf(2, "can't resolve symbol in lib '%s'.\n", tpnt->libname);
399 int _dl_parse_relocation_information(struct dyn_elf *rpnt,
400 unsigned long rel_addr, unsigned long rel_size)
402 return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);