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, Erik Andersen
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. The name of the above contributors may not be
15 * used to endorse or promote products derived from this software
16 * without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #if defined (__SUPPORT_LD_DEBUG__)
32 static const char *_dl_reltypes_tab[] =
33 { "R_PPC_NONE", "R_PPC_ADDR32", "R_PPC_ADDR24", "R_PPC_ADDR16",
34 "R_PPC_ADDR16_LO", "R_PPC_ADDR16_HI", "R_PPC_ADDR16_HA",
35 "R_PPC_ADDR14", "R_PPC_ADDR14_BRTAKEN", "R_PPC_ADDR14_BRNTAKEN",
36 "R_PPC_REL24", "R_PPC_REL14", "R_PPC_REL14_BRTAKEN",
37 "R_PPC_REL14_BRNTAKEN", "R_PPC_GOT16", "R_PPC_GOT16_LO",
38 "R_PPC_GOT16_HI", "R_PPC_GOT16_HA", "R_PPC_PLTREL24",
39 "R_PPC_COPY", "R_PPC_GLOB_DAT", "R_PPC_JMP_SLOT", "R_PPC_RELATIVE",
40 "R_PPC_LOCAL24PC", "R_PPC_UADDR32", "R_PPC_UADDR16", "R_PPC_REL32",
41 "R_PPC_PLT32", "R_PPC_PLTREL32", "R_PPC_PLT16_LO", "R_PPC_PLT16_HI",
42 "R_PPC_PLT16_HA", "R_PPC_SDAREL16", "R_PPC_SECTOFF",
43 "R_PPC_SECTOFF_LO", "R_PPC_SECTOFF_HI", "R_PPC_SECTOFF_HA",
47 _dl_reltypes(int type)
52 if (type >= (int)(sizeof (_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) ||
53 NULL == (str = _dl_reltypes_tab[type]))
55 str =_dl_simple_ltoa( buf, (unsigned long)(type));
61 void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
66 _dl_dprintf(_dl_debug_file, "\n%s\n\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",
67 strtab + symtab[symtab_index].st_name,
68 symtab[symtab_index].st_value,
69 symtab[symtab_index].st_size,
70 symtab[symtab_index].st_info,
71 symtab[symtab_index].st_other,
72 symtab[symtab_index].st_shndx);
78 void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt)
84 symtab_index = ELF32_R_SYM(rpnt->r_info);
85 sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0";
88 _dl_dprintf(_dl_debug_file, "\n\t");
90 _dl_dprintf(_dl_debug_file, "\n%s\n\t", sym);
91 #ifdef ELF_USES_RELOCA
92 _dl_dprintf(_dl_debug_file, "%s\toffset=%x\taddend=%x",
93 _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
97 _dl_dprintf(_dl_debug_file, "%s\toffset=%x\n",
98 _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
105 extern int _dl_linux_resolve(void);
107 void _dl_init_got(unsigned long *plt,struct elf_resolve *tpnt)
110 Elf32_Word num_plt_entries;
111 Elf32_Word data_words;
112 Elf32_Word rel_offset_words;
113 Elf32_Word dlrr = (Elf32_Word) _dl_linux_resolve;
115 //DPRINTF("init_got plt=%x, tpnt=%x\n", (unsigned long)plt,(unsigned long)tpnt);
117 num_plt_entries = tpnt->dynamic_info[DT_PLTRELSZ] / sizeof(ELF_RELOC);
118 //DPRINTF("n_plt_entries %d\n",n_plt_entries);
120 rel_offset_words = PLT_DATA_START_WORDS(num_plt_entries);
121 //DPRINTF("rel_offset_words %x\n",rel_offset_words);
122 data_words = (Elf32_Word) (plt + rel_offset_words);
123 //DPRINTF("data_words %x\n",data_words);
125 tpnt->data_words = data_words;
127 plt[PLT_LONGBRANCH_ENTRY_WORDS] = OPCODE_ADDIS_HI(11, 11, data_words);
128 plt[PLT_LONGBRANCH_ENTRY_WORDS+1] = OPCODE_LWZ(11,data_words,11);
130 plt[PLT_LONGBRANCH_ENTRY_WORDS+2] = OPCODE_MTCTR(11);
131 plt[PLT_LONGBRANCH_ENTRY_WORDS+3] = OPCODE_BCTR();
135 tramp = (Elf32_Word *) (plt + PLT_TRAMPOLINE_ENTRY_WORDS);
137 /* For the long entries, subtract off data_words. */
138 tramp[0] = OPCODE_ADDIS_HI(11,11,-data_words);
139 tramp[1] = OPCODE_ADDI(11,11,-data_words);
141 /* Multiply index of entry by 3 (in r11). */
142 tramp[2] = OPCODE_SLWI(12,11,1);
143 tramp[3] = OPCODE_ADD(11,12,11);
144 if (dlrr <= 0x01fffffc || dlrr >= 0xfe000000) {
145 /* Load address of link map in r12. */
146 tramp[4] = OPCODE_LI (12, (Elf32_Word) tpnt);
147 tramp[5] = OPCODE_ADDIS_HI (12, 12, (Elf32_Word) tpnt);
149 /* Call _dl_runtime_resolve. */
150 tramp[6] = OPCODE_BA (dlrr);
152 /* Get address of _dl_runtime_resolve in CTR. */
153 tramp[4] = OPCODE_LI(12,dlrr);
154 tramp[5] = OPCODE_ADDIS_HI(12,12,dlrr);
155 tramp[6] = OPCODE_MTCTR(12);
157 /* Load address of link map in r12. */
158 tramp[7] = OPCODE_LI(12,(Elf32_Word) tpnt);
159 tramp[8] = OPCODE_ADDIS_HI(12,12,(Elf32_Word) tpnt);
161 /* Call _dl_runtime_resolve. */
162 tramp[9] = OPCODE_BCTR();
178 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
180 ELF_RELOC *this_reloc;
186 Elf32_Addr *reloc_addr;
187 Elf32_Addr finaladdr;
190 rel_addr = (ELF_RELOC *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
192 this_reloc = (void *)rel_addr + reloc_entry;
193 symtab_index = ELF32_R_SYM(this_reloc->r_info);
195 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
196 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
197 symname = strtab + symtab[symtab_index].st_name;
199 #if defined (__SUPPORT_LD_DEBUG__)
200 debug_sym(symtab,strtab,symtab_index);
201 debug_reloc(symtab,strtab,this_reloc);
203 if (ELF32_R_TYPE(this_reloc->r_info) != R_PPC_JMP_SLOT) {
204 _dl_dprintf(2, "%s: Incorrect relocation type in jump relocation\n", _dl_progname);
209 /* Address of dump instruction to fix up */
210 reloc_addr = (Elf32_Addr *) (tpnt->loadaddr + this_reloc->r_offset);
212 #if defined (__SUPPORT_LD_DEBUG__)
213 if(_dl_debug_reloc && _dl_debug_detail)
214 _dl_dprintf(_dl_debug_file, "\n\tResolving symbol %s %x --> ", symname, (Elf32_Addr)reloc_addr);
217 /* Get the address of the GOT entry */
218 finaladdr = (Elf32_Addr) _dl_find_hash(strtab + symtab[symtab_index].st_name,
219 tpnt->symbol_scope, tpnt, resolver);
221 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
225 #if defined (__SUPPORT_LD_DEBUG__)
226 if(_dl_debug_reloc && _dl_debug_detail)
227 _dl_dprintf(_dl_debug_file, "%x\n", finaladdr);
229 delta = finaladdr - (Elf32_Word)reloc_addr;
230 if (delta<<6>>6 == delta) {
231 *reloc_addr = OPCODE_B(delta);
232 } else if (finaladdr <= 0x01fffffc || finaladdr >= 0xfe000000) {
233 *reloc_addr = OPCODE_BA (finaladdr);
235 /* Warning: we don't handle double-sized PLT entries */
236 Elf32_Word *plt, *data_words, index, offset;
238 plt = (Elf32_Word *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
239 offset = reloc_addr - plt;
240 index = (offset - PLT_INITIAL_ENTRY_WORDS)/2;
241 data_words = (Elf32_Word *)tpnt->data_words;
244 data_words[index] = finaladdr;
246 *reloc_addr = OPCODE_B ((PLT_LONGBRANCH_ENTRY_WORDS - (offset+1)) * 4);
249 /* instructions were modified */
250 PPC_DCBST(reloc_addr);
252 PPC_ICBI(reloc_addr);
259 _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
260 unsigned long rel_addr, unsigned long rel_size,
261 int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
262 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
270 /* Now parse the relocation information */
271 rpnt = (ELF_RELOC *)(intptr_t) (rel_addr + tpnt->loadaddr);
272 rel_size = rel_size / sizeof(ELF_RELOC);
274 symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
275 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
277 for (i = 0; i < rel_size; i++, rpnt++) {
280 symtab_index = ELF32_R_SYM(rpnt->r_info);
282 /* When the dynamic linker bootstrapped itself, it resolved some symbols.
283 Make sure we do not do them again */
284 if (!symtab_index && tpnt->libtype == program_interpreter)
286 if (symtab_index && tpnt->libtype == program_interpreter &&
287 _dl_symbol(strtab + symtab[symtab_index].st_name))
290 #if defined (__SUPPORT_LD_DEBUG__)
291 debug_sym(symtab,strtab,symtab_index);
292 debug_reloc(symtab,strtab,rpnt);
295 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
297 if (res==0) continue;
299 _dl_dprintf(2, "\n%s: ",_dl_progname);
302 _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
306 int reloc_type = ELF32_R_TYPE(rpnt->r_info);
307 #if defined (__SUPPORT_LD_DEBUG__)
308 _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
310 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
316 _dl_dprintf(2, "can't resolve symbol\n");
324 _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
325 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
327 Elf32_Addr *reloc_addr;
328 Elf32_Word *plt, index, offset;
334 reloc_addr = (Elf32_Addr *)(tpnt->loadaddr + rpnt->r_offset);
335 #if defined (__SUPPORT_LD_DEBUG__)
336 if (ELF32_R_TYPE(rpnt->r_info) != R_PPC_JMP_SLOT) {
337 _dl_dprintf(2, "Reloc type != R_PPC_JMP_SLOT. Type is 0x%x\n", ELF32_R_TYPE(rpnt->r_info));
341 plt = (Elf32_Word *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
342 offset = reloc_addr - plt;
343 index = (offset - PLT_INITIAL_ENTRY_WORDS)/2;
344 reloc_addr[0] = OPCODE_LI(11,index*4);
345 reloc_addr[1] = OPCODE_B((PLT_TRAMPOLINE_ENTRY_WORDS + 2 - (offset+1)) * 4);
347 /* instructions were modified */
348 PPC_DCBST(reloc_addr);
349 PPC_DCBST(reloc_addr+1);
351 PPC_ICBI(reloc_addr);
352 PPC_ICBI(reloc_addr+1);
355 #if defined (__SUPPORT_LD_DEBUG__)
356 if(_dl_debug_reloc && _dl_debug_detail)
357 _dl_dprintf(_dl_debug_file, "\tpatched: %x", reloc_addr);
363 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
364 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
369 Elf32_Addr *reloc_addr;
370 Elf32_Addr finaladdr;
372 unsigned long symbol_addr;
373 #if defined (__SUPPORT_LD_DEBUG__)
374 unsigned long old_val;
376 reloc_addr = (Elf32_Addr *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
377 reloc_type = ELF32_R_TYPE(rpnt->r_info);
378 if (reloc_type == R_PPC_RELATIVE) {
379 *reloc_addr = tpnt->loadaddr + rpnt->r_addend;
382 if (reloc_type == R_PPC_NONE || reloc_type == R_PPC_COPY) /* R_PPC_COPY is handled later */
384 symtab_index = ELF32_R_SYM(rpnt->r_info);
385 symname = strtab + symtab[symtab_index].st_name;
387 symbol_addr = (unsigned long) _dl_find_hash(symname, scope,
388 (reloc_type == R_PPC_JMP_SLOT ? tpnt : NULL), symbolrel);
390 * We want to allow undefined references to weak symbols - this might
391 * have been intentional. We should not be linking local symbols
392 * here, so all bases should be covered.
394 if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
395 #if defined (__SUPPORT_LD_DEBUG__)
396 _dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s', rel type: %s\n",
397 symname, tpnt->libname, _dl_reltypes(reloc_type));
401 #if defined (__SUPPORT_LD_DEBUG__)
402 old_val = *reloc_addr;
404 finaladdr = (Elf32_Addr) (symbol_addr + rpnt->r_addend);
406 switch (reloc_type) {
409 *reloc_addr = finaladdr;
410 return 0; /* No code code modified */
414 Elf32_Sword delta = finaladdr - (Elf32_Word)reloc_addr;
416 if (delta<<6>>6 == delta) {
417 *reloc_addr = OPCODE_B(delta);
418 } else if (finaladdr <= 0x01fffffc || finaladdr >= 0xfe000000) {
419 *reloc_addr = OPCODE_BA (finaladdr);
421 /* Warning: we don't handle double-sized PLT entries */
422 Elf32_Word *plt, *data_words, index, offset;
424 plt = (Elf32_Word *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
425 offset = reloc_addr - plt;
426 index = (offset - PLT_INITIAL_ENTRY_WORDS)/2;
427 data_words = (Elf32_Word *)tpnt->data_words;
429 data_words[index] = finaladdr;
430 reloc_addr[0] = OPCODE_LI(11,index*4);
431 reloc_addr[1] = OPCODE_B((PLT_LONGBRANCH_ENTRY_WORDS - (offset+1)) * 4);
433 /* instructions were modified */
434 PPC_DCBST(reloc_addr+1);
436 PPC_ICBI(reloc_addr+1);
441 /* This does not work yet, R_PPC_COPY is handled later, see if statemet above */
443 #if defined (__SUPPORT_LD_DEBUG__)
445 _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
446 symname, symtab[symtab_index].st_size,
447 symbol_addr, symtab[symtab_index].st_value);
449 _dl_memcpy((char *) reloc_addr, (char *) finaladdr, symtab[symtab_index].st_size);
451 return 0; /* No code code modified */
453 case R_PPC_ADDR16_HA:
454 *(short *)reloc_addr = (finaladdr + 0x8000)>>16;
456 case R_PPC_ADDR16_HI:
457 *(short *)reloc_addr = finaladdr >> 16;
459 case R_PPC_ADDR16_LO:
460 *(short *)reloc_addr = finaladdr;
464 Elf32_Sword delta = finaladdr - (Elf32_Word)reloc_addr;
465 if(delta<<6>>6 != delta){
466 _dl_dprintf(2, "%s: symbol '%s' R_PPC_REL24 is out of range.\n\tCompile shared libraries with -fPIC!\n",
467 _dl_progname, symname);
470 *reloc_addr = (*reloc_addr & 0xfc000003) | (delta & 0x3fffffc);
474 _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
475 #if defined (__SUPPORT_LD_DEBUG__)
476 _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
479 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
483 /* instructions were modified */
484 PPC_DCBST(reloc_addr);
486 PPC_ICBI(reloc_addr);
488 #if defined (__SUPPORT_LD_DEBUG__)
489 if(_dl_debug_reloc && _dl_debug_detail)
490 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
495 /* This is done as a separate step, because there are cases where
496 information is first copied and later initialized. This results in
497 the wrong information being copied. Someone at Sun was complaining about
498 a bug in the handling of _COPY by SVr4, and this may in fact be what he
499 was talking about. Sigh. */
501 _dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope,
502 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
506 unsigned long *reloc_addr;
507 unsigned long symbol_addr;
511 reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
512 reloc_type = ELF32_R_TYPE(rpnt->r_info);
513 if (reloc_type != R_PPC_COPY)
515 symtab_index = ELF32_R_SYM(rpnt->r_info);
517 symname = strtab + symtab[symtab_index].st_name;
520 symbol_addr = (unsigned long) _dl_find_hash(symname, scope, NULL, copyrel);
521 if (!symbol_addr) goof++;
524 #if defined (__SUPPORT_LD_DEBUG__)
526 _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
527 symname, symtab[symtab_index].st_size,
528 symbol_addr, symtab[symtab_index].st_value);
530 _dl_memcpy((char *) reloc_addr,
531 (char *) (symbol_addr + (unsigned long)rpnt->r_addend), symtab[symtab_index].st_size);
537 void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
538 unsigned long rel_addr, unsigned long rel_size, int type)
541 (void)_dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
544 int _dl_parse_relocation_information(struct elf_resolve *tpnt,
545 unsigned long rel_addr, unsigned long rel_size, int type)
548 return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
551 int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
552 unsigned long rel_size, int type)
555 return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy);