OSDN Git Service

eec78e305c774142698bb6ec9631ab4b56369120
[uclinux-h8/uClibc.git] / ldso / ldso / powerpc / elfinterp.c
1 /* vi: set sw=4 ts=4: */
2 /* powerpc shared library loader suppport
3  *
4  * Copyright (C) 2001-2002,  David A. Schleef
5  * Copyright (C) 2003, Erik Andersen
6  *
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
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.
17  *
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
28  * SUCH DAMAGE.
29  */
30
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",
44 };
45
46 static const char *
47 _dl_reltypes(int type)
48 {
49   static char buf[22];  
50   const char *str;
51   
52   if (type >= (int)(sizeof (_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) ||
53       NULL == (str = _dl_reltypes_tab[type]))
54   {
55     str =_dl_simple_ltoa( buf, (unsigned long)(type));
56   }
57   return str;
58 }
59
60 static 
61 void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
62 {
63   if(_dl_debug_symbols)
64   {
65     if(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);
73     }
74   }
75 }
76
77 static 
78 void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt)
79 {
80   if(_dl_debug_reloc)
81   {
82     int symtab_index;
83     const char *sym;
84     symtab_index = ELF32_R_SYM(rpnt->r_info);
85     sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0";
86     
87   if(_dl_debug_symbols)
88           _dl_dprintf(_dl_debug_file, "\n\t");
89   else
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)),
94                 rpnt->r_offset,
95                 rpnt->r_addend);
96 #else
97     _dl_dprintf(_dl_debug_file, "%s\toffset=%x\n",
98                 _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
99                 rpnt->r_offset);
100 #endif
101   }
102 }
103 #endif
104
105 extern int _dl_linux_resolve(void);
106
107 void _dl_init_got(unsigned long *plt,struct elf_resolve *tpnt)
108 {
109         Elf32_Word *tramp;
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;
114
115         num_plt_entries = tpnt->dynamic_info[DT_PLTRELSZ] / sizeof(ELF_RELOC);
116         rel_offset_words = PLT_DATA_START_WORDS(num_plt_entries);
117         data_words = (Elf32_Word) (plt + rel_offset_words);
118         tpnt->data_words = data_words;
119
120         plt[PLT_LONGBRANCH_ENTRY_WORDS] = OPCODE_ADDIS_HI(11, 11, data_words);
121         plt[PLT_LONGBRANCH_ENTRY_WORDS+1] = OPCODE_LWZ(11,data_words,11);
122
123         plt[PLT_LONGBRANCH_ENTRY_WORDS+2] = OPCODE_MTCTR(11);
124         plt[PLT_LONGBRANCH_ENTRY_WORDS+3] = OPCODE_BCTR();
125
126         /* [4] */
127         /* [5] */
128         tramp = (Elf32_Word *) (plt + PLT_TRAMPOLINE_ENTRY_WORDS);
129
130         /* For the long entries, subtract off data_words.  */
131         tramp[0] = OPCODE_ADDIS_HI(11,11,-data_words);
132         tramp[1] = OPCODE_ADDI(11,11,-data_words);
133
134         /* Multiply index of entry by 3 (in r11).  */
135         tramp[2] = OPCODE_SLWI(12,11,1);
136         tramp[3] = OPCODE_ADD(11,12,11);
137         if (dlrr <= 0x01fffffc || dlrr >= 0xfe000000) {
138                 /* Load address of link map in r12.  */
139                 tramp[4] = OPCODE_LI (12, (Elf32_Word) tpnt);
140                 tramp[5] = OPCODE_ADDIS_HI (12, 12, (Elf32_Word) tpnt);
141
142                 /* Call _dl_linux_resolve .  */
143                 tramp[6] = OPCODE_BA (dlrr);
144         } else {
145                 /* Get address of _dl_linux_resolve in CTR.  */
146                 tramp[4] = OPCODE_LI(12,dlrr);
147                 tramp[5] = OPCODE_ADDIS_HI(12,12,dlrr);
148                 tramp[6] = OPCODE_MTCTR(12);
149
150                 /* Load address of link map in r12.  */
151                 tramp[7] = OPCODE_LI(12,(Elf32_Word) tpnt);
152                 tramp[8] = OPCODE_ADDIS_HI(12,12,(Elf32_Word) tpnt);
153
154                 /* Call _dl_linux_resolve.  */
155                 tramp[9] = OPCODE_BCTR();
156         }
157         /* [16] unused */
158         /* [17] unused */
159
160         PPC_DCBST(plt);
161         PPC_DCBST(plt+4);
162         PPC_DCBST(plt+8);
163         PPC_DCBST(plt+12);
164         PPC_DCBST(plt+16-1);
165         PPC_SYNC;
166         PPC_ICBI(plt);
167         PPC_ICBI(plt+16-1);
168         PPC_ISYNC;
169 }
170
171 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
172 {
173         ELF_RELOC *this_reloc;
174         char *strtab;
175         Elf32_Sym *symtab;
176         ELF_RELOC *rel_addr;
177         int symtab_index;
178         char *symname;
179         Elf32_Addr *reloc_addr;
180         Elf32_Addr  finaladdr;
181         Elf32_Sword delta;
182
183         rel_addr = (ELF_RELOC *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
184
185         this_reloc = (void *)rel_addr + reloc_entry;
186         symtab_index = ELF32_R_SYM(this_reloc->r_info);
187
188         symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
189         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
190         symname      = strtab + symtab[symtab_index].st_name;
191
192 #if defined (__SUPPORT_LD_DEBUG__)
193         debug_sym(symtab,strtab,symtab_index);
194         debug_reloc(symtab,strtab,this_reloc);
195
196         if (ELF32_R_TYPE(this_reloc->r_info) != R_PPC_JMP_SLOT) {
197                 _dl_dprintf(2, "%s: Incorrect relocation type in jump relocation\n", _dl_progname);
198                 _dl_exit(1);
199         };
200 #endif
201
202         /* Address of dump instruction to fix up */
203         reloc_addr = (Elf32_Addr *) (tpnt->loadaddr + this_reloc->r_offset);
204
205 #if defined (__SUPPORT_LD_DEBUG__)
206         if(_dl_debug_reloc && _dl_debug_detail)
207                 _dl_dprintf(_dl_debug_file, "\n\tResolving symbol %s %x --> ", symname, (Elf32_Addr)reloc_addr);
208 #endif
209
210         /* Get the address of the GOT entry */
211         finaladdr = (Elf32_Addr) _dl_find_hash(strtab + symtab[symtab_index].st_name, 
212                                                 tpnt->symbol_scope, tpnt, resolver);
213         if (!finaladdr) {
214                 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
215                 _dl_exit(1);
216         };
217
218 #if defined (__SUPPORT_LD_DEBUG__)
219         if(_dl_debug_reloc && _dl_debug_detail)
220                 _dl_dprintf(_dl_debug_file, "%x\n", finaladdr);
221 #endif
222         delta = finaladdr - (Elf32_Word)reloc_addr;
223         if (delta<<6>>6 == delta) {
224                 *reloc_addr = OPCODE_B(delta);
225 #if 0
226         /* this will almost never be true */
227         } else if (finaladdr <= 0x01fffffc || finaladdr >= 0xfe000000) {
228                 *reloc_addr = OPCODE_BA (finaladdr);
229 #endif
230         } else {
231                 /* Warning: we don't handle double-sized PLT entries */
232                 Elf32_Word *plt, *data_words, index, offset;
233
234                 plt = (Elf32_Word *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
235                 offset = reloc_addr - plt;
236                 index = (offset - PLT_INITIAL_ENTRY_WORDS)/2;
237                 data_words = (Elf32_Word *)tpnt->data_words;
238                 reloc_addr += 1;
239
240                 data_words[index] = finaladdr;
241                 PPC_SYNC;
242                 *reloc_addr =  OPCODE_B ((PLT_LONGBRANCH_ENTRY_WORDS - (offset+1)) * 4);
243         }
244
245         /* instructions were modified */
246         PPC_DCBST(reloc_addr);
247         PPC_SYNC;
248         PPC_ICBI(reloc_addr);
249         PPC_ISYNC;
250
251         return finaladdr;
252 }
253
254 static int
255 _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
256           unsigned long rel_addr, unsigned long rel_size,
257           int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
258                             ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
259 {
260         unsigned int i;
261         char *strtab;
262         Elf32_Sym *symtab;
263         ELF_RELOC *rpnt;
264         int symtab_index;
265
266         /* Now parse the relocation information */
267         rpnt = (ELF_RELOC *)(intptr_t) (rel_addr + tpnt->loadaddr);
268         rel_size = rel_size / sizeof(ELF_RELOC);
269
270         symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
271         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
272
273           for (i = 0; i < rel_size; i++, rpnt++) {
274                 int res;
275             
276                 symtab_index = ELF32_R_SYM(rpnt->r_info);
277                 
278                 /* When the dynamic linker bootstrapped itself, it resolved some symbols.
279                    Make sure we do not do them again */
280                 if (!symtab_index && tpnt->libtype == program_interpreter)
281                         continue;
282                 if (symtab_index && tpnt->libtype == program_interpreter &&
283                     _dl_symbol(strtab + symtab[symtab_index].st_name))
284                         continue;
285
286 #if defined (__SUPPORT_LD_DEBUG__)
287                 debug_sym(symtab,strtab,symtab_index);
288                 debug_reloc(symtab,strtab,rpnt);
289 #endif
290
291                 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
292
293                 if (res==0) continue;
294
295                 _dl_dprintf(2, "\n%s: ",_dl_progname);
296                 
297                 if (symtab_index)
298                   _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
299                   
300                 if (res <0)
301                 {
302                         int reloc_type = ELF32_R_TYPE(rpnt->r_info);
303 #if defined (__SUPPORT_LD_DEBUG__)
304                         _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
305 #else
306                         _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
307 #endif                  
308                         _dl_exit(-res);
309                 }
310                 else if (res >0)
311                 {
312                         _dl_dprintf(2, "can't resolve symbol\n");
313                         return res;
314                 }
315           }
316           return 0;
317 }
318
319 static int
320 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
321               ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
322 {
323         int reloc_type;
324         int symtab_index;
325         char *symname;
326         Elf32_Addr *reloc_addr;
327         Elf32_Addr finaladdr;
328
329         unsigned long symbol_addr;
330 #if defined (__SUPPORT_LD_DEBUG__)
331         unsigned long old_val;
332 #endif
333         reloc_addr   = (Elf32_Addr *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
334         reloc_type   = ELF32_R_TYPE(rpnt->r_info);
335         if (reloc_type == R_PPC_RELATIVE) {
336                 *reloc_addr = tpnt->loadaddr + rpnt->r_addend;
337                 return 0;
338         }
339         if (reloc_type == R_PPC_NONE || reloc_type == R_PPC_COPY) /*  R_PPC_COPY is handled later */
340                 return 0;
341         symtab_index = ELF32_R_SYM(rpnt->r_info);
342         symname      = strtab + symtab[symtab_index].st_name;
343
344         symbol_addr = (unsigned long) _dl_find_hash(symname, scope, 
345                                                     (reloc_type == R_PPC_JMP_SLOT ? tpnt : NULL), symbolrel);
346         /*
347          * We want to allow undefined references to weak symbols - this might
348          * have been intentional.  We should not be linking local symbols
349          * here, so all bases should be covered.
350          */
351         if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
352 #if defined (__SUPPORT_LD_DEBUG__)
353                 _dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s', rel type: %s\n",
354                             symname, tpnt->libname, _dl_reltypes(reloc_type));
355 #endif
356                 return 0;
357         }
358 #if defined (__SUPPORT_LD_DEBUG__)
359         old_val = *reloc_addr;
360 #endif
361         finaladdr = (Elf32_Addr) (symbol_addr + rpnt->r_addend);
362
363         switch (reloc_type) {
364         case R_PPC_ADDR32:
365         case R_PPC_GLOB_DAT:
366                 *reloc_addr = finaladdr;
367                 return 0; /* No code code modified */
368                 break;
369         case R_PPC_JMP_SLOT:
370         {
371                 Elf32_Sword delta = finaladdr - (Elf32_Word)reloc_addr;
372                 
373                 if (delta<<6>>6 == delta) {
374                         *reloc_addr = OPCODE_B(delta);
375 #if 0
376                 /* this will almost never be true */
377                 } else if (finaladdr <= 0x01fffffc || finaladdr >= 0xfe000000) {
378                         *reloc_addr = OPCODE_BA (finaladdr);
379 #endif
380                 } else {
381                         /* Warning: we don't handle double-sized PLT entries */
382                         Elf32_Word *plt, *data_words, index, offset;
383
384                         plt = (Elf32_Word *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
385                         offset = reloc_addr - plt;
386                         index = (offset - PLT_INITIAL_ENTRY_WORDS)/2;
387                         data_words = (Elf32_Word *)tpnt->data_words;
388
389                         data_words[index] = finaladdr;
390                         reloc_addr[0] = OPCODE_LI(11,index*4);
391                         reloc_addr[1] = OPCODE_B((PLT_LONGBRANCH_ENTRY_WORDS - (offset+1)) * 4);
392
393                         /* instructions were modified */
394                         PPC_DCBST(reloc_addr+1);
395                         PPC_SYNC;
396                         PPC_ICBI(reloc_addr+1);
397                 }
398                 break;
399         }
400         case R_PPC_COPY:
401                 /* This does not work yet, R_PPC_COPY is handled later, see if statemet above */
402                 if (symbol_addr) {
403 #if defined (__SUPPORT_LD_DEBUG__)
404                         if(_dl_debug_move)
405                                 _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
406                                             symname, symtab[symtab_index].st_size,
407                                             symbol_addr, symtab[symtab_index].st_value);
408 #endif
409                         _dl_memcpy((char *) reloc_addr, (char *) finaladdr, symtab[symtab_index].st_size);
410                 }
411                 return 0; /* No code code modified */
412                 break;
413         case R_PPC_ADDR16_HA:
414                 *(short *)reloc_addr = (finaladdr + 0x8000)>>16;
415                 break;
416         case R_PPC_ADDR16_HI:
417                 *(short *)reloc_addr = finaladdr >> 16;
418                 break;
419         case R_PPC_ADDR16_LO:
420                 *(short *)reloc_addr = finaladdr;
421                 break;
422         case R_PPC_REL24:
423         {
424                 Elf32_Sword delta = finaladdr - (Elf32_Word)reloc_addr;
425                 if(delta<<6>>6 != delta){
426                         _dl_dprintf(2, "%s: symbol '%s' R_PPC_REL24 is out of range.\n\tCompile shared libraries with -fPIC!\n",
427                                     _dl_progname, symname);
428                         _dl_exit(1);
429                 }
430                 *reloc_addr = (*reloc_addr & 0xfc000003) | (delta & 0x3fffffc);
431                 break;
432         }
433         default:
434                 _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
435 #if defined (__SUPPORT_LD_DEBUG__)
436                 _dl_dprintf(2, "%s ", _dl_reltypes(reloc_type));
437 #endif
438                 if (symtab_index)
439                         _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
440                 return -1;
441         };
442
443         /* instructions were modified */
444         PPC_DCBST(reloc_addr);
445         PPC_SYNC;
446         PPC_ICBI(reloc_addr);
447         PPC_ISYNC;
448 #if defined (__SUPPORT_LD_DEBUG__)
449         if(_dl_debug_reloc && _dl_debug_detail)
450                 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
451 #endif
452         return 0;
453 }
454
455 /* This is done as a separate step, because there are cases where
456    information is first copied and later initialized.  This results in
457    the wrong information being copied.  Someone at Sun was complaining about
458    a bug in the handling of _COPY by SVr4, and this may in fact be what he
459    was talking about.  Sigh. */
460 static int
461 _dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope,
462              ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
463 {
464         int reloc_type;
465         int symtab_index;
466         unsigned long *reloc_addr;
467         unsigned long symbol_addr;
468         int goof = 0;
469         char *symname;
470           
471         reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
472         reloc_type = ELF32_R_TYPE(rpnt->r_info);
473         if (reloc_type != R_PPC_COPY) 
474                 return 0;
475         symtab_index = ELF32_R_SYM(rpnt->r_info);
476         symbol_addr = 0;
477         symname      = strtab + symtab[symtab_index].st_name;
478                 
479         if (symtab_index) {
480                 symbol_addr = (unsigned long) _dl_find_hash(symname, scope, NULL, copyrel);
481                 if (!symbol_addr) goof++;
482         }
483         if (!goof) {
484 #if defined (__SUPPORT_LD_DEBUG__)
485                 if(_dl_debug_move)
486                   _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
487                              symname, symtab[symtab_index].st_size,
488                              symbol_addr, symtab[symtab_index].st_value);
489 #endif
490                         _dl_memcpy((char *) reloc_addr,
491                                         (char *) (symbol_addr + (unsigned long)rpnt->r_addend), symtab[symtab_index].st_size);
492         }
493
494         return goof;
495 }
496
497 void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, 
498         unsigned long rel_addr, unsigned long rel_size, int type)
499 {
500         Elf32_Word *plt, offset, i,  num_plt_entries, rel_offset_words;
501
502         (void) type;
503         num_plt_entries = rel_size / sizeof(ELF_RELOC);
504
505         /* When the dynamic linker bootstrapped itself, it resolved some symbols.
506            Make sure we do not do them again */
507         if (tpnt->libtype == program_interpreter)
508                 return;
509         rel_offset_words = PLT_DATA_START_WORDS(num_plt_entries);
510         plt = (Elf32_Word *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
511
512         /* Set up the lazy PLT entries.  */
513         offset = PLT_INITIAL_ENTRY_WORDS;
514         i = 0;
515         /* Warning: we don't handle double-sized PLT entries */
516         while (i < num_plt_entries) {
517                 plt[offset  ] = OPCODE_LI(11, i * 4);
518                 plt[offset+1] = OPCODE_B((PLT_TRAMPOLINE_ENTRY_WORDS + 2 - (offset+1)) * 4);
519                 i++;
520                 offset += 2;
521         }
522         /* Now, we've modified code.  We need to write the changes from
523            the data cache to a second-level unified cache, then make
524            sure that stale data in the instruction cache is removed.
525            (In a multiprocessor system, the effect is more complex.)
526            Most of the PLT shouldn't be in the instruction cache, but
527            there may be a little overlap at the start and the end.
528            
529            Assumes that dcbst and icbi apply to lines of 16 bytes or
530            more.  Current known line sizes are 16, 32, and 128 bytes.  */
531         for (i = 0; i < rel_offset_words; i += 4)
532                 PPC_DCBST (plt + i);
533         PPC_DCBST (plt + rel_offset_words - 1);
534         PPC_SYNC;
535         PPC_ICBI (plt);
536         PPC_ICBI (plt + rel_offset_words - 1);
537         PPC_ISYNC;
538 }
539
540 int _dl_parse_relocation_information(struct elf_resolve *tpnt, 
541         unsigned long rel_addr, unsigned long rel_size, int type)
542 {
543         (void) type;
544         return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
545 }
546
547 int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, 
548         unsigned long rel_size, int type)
549 {
550         (void) type;
551         return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy);
552 }