OSDN Git Service

Joakim Tjernlund writes:
[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         unsigned long target_addr = (unsigned long)_dl_linux_resolve;
110         unsigned int n_plt_entries;
111         unsigned long *tramp;
112         unsigned long data_words;
113         unsigned int rel_offset_words;
114
115         //DPRINTF("init_got plt=%x, tpnt=%x\n", (unsigned long)plt,(unsigned long)tpnt);
116
117         n_plt_entries = tpnt->dynamic_info[DT_PLTRELSZ] / sizeof(ELF_RELOC);
118         //DPRINTF("n_plt_entries %d\n",n_plt_entries);
119
120         rel_offset_words = PLT_DATA_START_WORDS(n_plt_entries);
121         //DPRINTF("rel_offset_words %x\n",rel_offset_words);
122         data_words = (unsigned long)(plt + rel_offset_words);
123         //DPRINTF("data_words %x\n",data_words);
124
125         tpnt->data_words = data_words;
126
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);
129
130         plt[PLT_LONGBRANCH_ENTRY_WORDS+2] = OPCODE_MTCTR(11);
131         plt[PLT_LONGBRANCH_ENTRY_WORDS+3] = OPCODE_BCTR();
132
133         /* [4] */
134         /* [5] */
135
136         tramp = plt + PLT_TRAMPOLINE_ENTRY_WORDS;
137         tramp[0] = OPCODE_ADDIS_HI(11,11,-data_words);
138         tramp[1] = OPCODE_ADDI(11,11,-data_words);
139         tramp[2] = OPCODE_SLWI(12,11,1);
140         tramp[3] = OPCODE_ADD(11,12,11);
141         tramp[4] = OPCODE_LI(12,target_addr);
142         tramp[5] = OPCODE_ADDIS_HI(12,12,target_addr);
143         tramp[6] = OPCODE_MTCTR(12);
144         tramp[7] = OPCODE_LI(12,(unsigned long)tpnt);
145         tramp[8] = OPCODE_ADDIS_HI(12,12,(unsigned long)tpnt);
146         tramp[9] = OPCODE_BCTR();
147
148         /* [16] unused */
149         /* [17] unused */
150
151         /* instructions were modified */
152         PPC_DCBST(plt);
153         PPC_DCBST(plt+4);
154         PPC_DCBST(plt+8);
155         PPC_DCBST(plt+12);
156         PPC_DCBST(plt+16-1);
157         PPC_SYNC;
158         PPC_ICBI(plt);
159         PPC_ICBI(plt+4); /* glibc thinks this is not needed */
160         PPC_ICBI(plt+8); /* glibc thinks this is not needed */
161         PPC_ICBI(plt+12); /* glibc thinks this is not needed */
162         PPC_ICBI(plt+16-1);
163         PPC_ISYNC;
164 }
165
166 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
167 {
168         int reloc_type;
169         ELF_RELOC *this_reloc;
170         char *strtab;
171         Elf32_Sym *symtab;
172         ELF_RELOC *rel_addr;
173         int symtab_index;
174         unsigned long insn_addr;
175         unsigned long *insns;
176         unsigned long new_addr;
177         char *symname;
178         int delta;
179
180         rel_addr = (ELF_RELOC *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
181
182         this_reloc = (void *)rel_addr + reloc_entry;
183         reloc_type = ELF32_R_TYPE(this_reloc->r_info);
184         symtab_index = ELF32_R_SYM(this_reloc->r_info);
185
186         symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
187         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
188         symname      = strtab + symtab[symtab_index].st_name;
189
190 #if defined (__SUPPORT_LD_DEBUG__)
191         debug_sym(symtab,strtab,symtab_index);
192         debug_reloc(symtab,strtab,this_reloc);
193 #endif
194
195         if (reloc_type != R_PPC_JMP_SLOT) {
196                 _dl_dprintf(2, "%s: Incorrect relocation type in jump relocation\n", _dl_progname);
197                 _dl_exit(1);
198         };
199
200         /* Address of dump instruction to fix up */
201         insn_addr = (unsigned long) tpnt->loadaddr +
202                 (unsigned long) this_reloc->r_offset;
203
204 #if defined (__SUPPORT_LD_DEBUG__)
205         if(_dl_debug_reloc && _dl_debug_detail)
206                 _dl_dprintf(_dl_debug_file, "\n\tResolving symbol %s %x --> ", symname, insn_addr);
207 #endif
208
209         /* Get the address of the GOT entry */
210         new_addr = (unsigned long) _dl_find_hash(
211                 strtab + symtab[symtab_index].st_name, 
212                 tpnt->symbol_scope, tpnt, resolver);
213         if (!new_addr) {
214                 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", 
215                         _dl_progname, symname);
216                 _dl_exit(1);
217         };
218
219 #if defined (__SUPPORT_LD_DEBUG__)
220         if(_dl_debug_reloc && _dl_debug_detail)
221                 _dl_dprintf(_dl_debug_file, "%x\n", new_addr);
222 #endif
223
224         insns = (unsigned long *)insn_addr;
225         delta = new_addr - insn_addr;
226
227         if(delta<<6>>6 == delta){
228                 insns[0] = OPCODE_B(delta);
229         }else if (new_addr <= 0x01fffffc || new_addr >= 0xfe000000){
230                 insns[0] = OPCODE_BA (new_addr);
231         }else{
232                 /* Warning: we don't handle double-sized PLT entries */
233                 unsigned long plt_addr;
234                 unsigned long *ptr;
235                 int index;
236
237                 plt_addr = (unsigned long)tpnt->dynamic_info[DT_PLTGOT] + 
238                         (unsigned long)tpnt->loadaddr;
239
240                 delta = PLT_LONGBRANCH_ENTRY_WORDS*4 - (insn_addr-plt_addr+4);
241
242                 index = (insn_addr - plt_addr - PLT_INITIAL_ENTRY_WORDS*4)/8;
243
244                 ptr = (unsigned long *)tpnt->data_words;
245                 //DPRINTF("plt_addr=%x delta=%x index=%x ptr=%x\n", plt_addr, delta, index, ptr);
246                 insns += 1;
247
248                 ptr[index] = new_addr;
249                 PPC_SYNC;
250                 /* icache sync is not necessary, since this will be a data load */
251                 //PPC_DCBST(ptr+index);
252                 //PPC_SYNC;
253                 //PPC_ICBI(ptr+index);
254                 //PPC_ISYNC;
255
256                 insns[0] = OPCODE_B(delta - 4);
257
258         }
259
260         /* instructions were modified */
261         PPC_DCBST(insns);
262         PPC_SYNC;
263         PPC_ICBI(insns);
264         PPC_ISYNC;
265
266         return new_addr;
267 }
268
269 static int
270 _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
271           unsigned long rel_addr, unsigned long rel_size,
272           int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
273                             ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
274 {
275         unsigned int i;
276         char *strtab;
277         Elf32_Sym *symtab;
278         ELF_RELOC *rpnt;
279         int symtab_index;
280
281         /* Now parse the relocation information */
282         rpnt = (ELF_RELOC *)(intptr_t) (rel_addr + tpnt->loadaddr);
283         rel_size = rel_size / sizeof(ELF_RELOC);
284
285         symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
286         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
287
288           for (i = 0; i < rel_size; i++, rpnt++) {
289                 int res;
290             
291                 symtab_index = ELF32_R_SYM(rpnt->r_info);
292                 
293                 /* When the dynamic linker bootstrapped itself, it resolved some symbols.
294                    Make sure we do not do them again */
295                 if (!symtab_index && tpnt->libtype == program_interpreter)
296                         continue;
297                 if (symtab_index && tpnt->libtype == program_interpreter &&
298                     _dl_symbol(strtab + symtab[symtab_index].st_name))
299                         continue;
300
301 #if defined (__SUPPORT_LD_DEBUG__)
302                 debug_sym(symtab,strtab,symtab_index);
303                 debug_reloc(symtab,strtab,rpnt);
304 #endif
305
306                 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
307
308                 if (res==0) continue;
309
310                 _dl_dprintf(2, "\n%s: ",_dl_progname);
311                 
312                 if (symtab_index)
313                   _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
314                   
315                 if (res <0)
316                 {
317                         int reloc_type = ELF32_R_TYPE(rpnt->r_info);
318 #if defined (__SUPPORT_LD_DEBUG__)
319                         _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
320 #else
321                         _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
322 #endif                  
323                         _dl_exit(-res);
324                 }
325                 else if (res >0)
326                 {
327                         _dl_dprintf(2, "can't resolve symbol\n");
328                         return res;
329                 }
330           }
331           return 0;
332 }
333
334 static int
335 _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
336                    ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
337 {
338         int reloc_type;
339         unsigned long reloc_addr;
340 #if defined (__SUPPORT_LD_DEBUG__)
341         unsigned long old_val;
342 #endif
343         (void)scope;
344         (void)symtab;
345         (void)strtab;
346
347         reloc_addr = (unsigned long)tpnt->loadaddr + (unsigned long) rpnt->r_offset;
348         reloc_type = ELF32_R_TYPE(rpnt->r_info);
349
350 #if defined (__SUPPORT_LD_DEBUG__)
351         old_val = reloc_addr;
352 #endif
353
354         switch (reloc_type) {
355                 case R_PPC_NONE:
356                         return 0;
357                         break;
358                 case R_PPC_JMP_SLOT:
359                         {
360                                 int index, delta;
361                                 unsigned long *plt;
362                                 unsigned long *insns;
363
364                                 plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
365
366                                 delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2) - (reloc_addr+4);
367
368                                 index = (reloc_addr - (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS)) 
369                                                 /sizeof(unsigned long);
370                                 index /= 2;
371                                 //DPRINTF("        index %x delta %x\n",index,delta);
372                                 insns = (unsigned long *)reloc_addr;
373                                 insns[0] = OPCODE_LI(11,index*4);
374                                 insns[1] = OPCODE_B(delta);
375                                 break;
376                         }
377                 default:
378 #if 0
379                         _dl_dprintf(2, "%s: (LAZY) can't handle reloc type ", 
380                                         _dl_progname);
381 #if defined (__SUPPORT_LD_DEBUG__)
382                         _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
383 #endif
384                         if (symtab_index)
385                                 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
386 #endif
387                         //_dl_exit(1);
388                         return -1;
389         };
390
391         /* instructions were modified */
392         PPC_DCBST(reloc_addr);
393         PPC_DCBST(reloc_addr+4);
394         PPC_SYNC;
395         PPC_ICBI(reloc_addr);
396         PPC_ICBI(reloc_addr+4);
397         PPC_ISYNC;
398
399 #if defined (__SUPPORT_LD_DEBUG__)
400         if(_dl_debug_reloc && _dl_debug_detail)
401                 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x", old_val, reloc_addr);
402 #endif
403         return 0;
404
405 }
406
407 static int
408 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
409               ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
410 {
411         int reloc_type;
412         int symtab_index;
413         char *symname;
414         unsigned long *reloc_addr;
415         unsigned long symbol_addr;
416 #if defined (__SUPPORT_LD_DEBUG__)
417         unsigned long old_val;
418 #endif
419
420         reloc_addr   = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
421         reloc_type   = ELF32_R_TYPE(rpnt->r_info);
422         symtab_index = ELF32_R_SYM(rpnt->r_info);
423         symbol_addr  = 0;
424         symname      = strtab + symtab[symtab_index].st_name;
425
426         if (symtab_index) {
427
428                 symbol_addr = (unsigned long) _dl_find_hash(symname, scope, 
429                                 (reloc_type == R_PPC_JMP_SLOT ? tpnt : NULL), symbolrel);
430
431                 /*
432                  * We want to allow undefined references to weak symbols - this might
433                  * have been intentional.  We should not be linking local symbols
434                  * here, so all bases should be covered.
435                  */
436
437                 if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
438 #if defined (__SUPPORT_LD_DEBUG__)
439                         _dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s'\n",
440                                         symname, tpnt->libname);
441 #endif
442                         return 0;
443                 }
444         }
445
446 #if defined (__SUPPORT_LD_DEBUG__)
447         old_val = *reloc_addr;
448 #endif
449                 switch (reloc_type) {
450                         case R_PPC_NONE:
451                                 return 0;
452                                 break;
453                         case R_PPC_REL24:
454 #if 0
455                                 {
456                                         int delta = symbol_addr - (unsigned long)reloc_addr;
457                                         if(delta<<6>>6 != delta){
458                                                 _dl_dprintf(2,"R_PPC_REL24: Reloc out of range\n");
459                                                 _dl_exit(1);
460                                         }
461                                         *reloc_addr &= 0xfc000003;
462                                         *reloc_addr |= delta&0x03fffffc;
463                                 }
464                                 break;
465 #else
466                                 _dl_dprintf(2, "%s: symbol '%s' is type R_PPC_REL24\n\tCompile shared libraries with -fPIC!\n",
467                                                 _dl_progname, symname);
468                                 _dl_exit(1);
469 #endif
470                         case R_PPC_RELATIVE:
471                                 *reloc_addr = (unsigned long)tpnt->loadaddr + (unsigned long)rpnt->r_addend;
472                                 break;
473                         case R_PPC_ADDR32:
474                                 *reloc_addr += symbol_addr;
475                                 break;
476                         case R_PPC_ADDR16_HA:
477                                 /* XXX is this correct? */
478                                 *(short *)reloc_addr += (symbol_addr+0x8000)>>16;
479                                 break;
480                         case R_PPC_ADDR16_HI:
481                                 *(short *)reloc_addr += symbol_addr>>16;
482                                 break;
483                         case R_PPC_ADDR16_LO:
484                                 *(short *)reloc_addr += symbol_addr;
485                                 break;
486                         case R_PPC_JMP_SLOT:
487                                 {
488                                         unsigned long targ_addr = (unsigned long)*reloc_addr;
489                                         int delta = targ_addr - (unsigned long)reloc_addr;
490                                         if(delta<<6>>6 == delta){
491                                                 *reloc_addr = OPCODE_B(delta);
492                                         }else if (targ_addr <= 0x01fffffc || targ_addr >= 0xfe000000){
493                                                 *reloc_addr = OPCODE_BA (targ_addr);
494                                         }else{
495                                                 {
496                                                         int delta;
497                                                         int index;
498                                                         unsigned long *plt, *ptr;
499                                                         plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
500
501                                                         delta = (unsigned long)(plt+PLT_LONGBRANCH_ENTRY_WORDS)
502                                                                 - (unsigned long)(reloc_addr+1);
503
504                                                         index = ((unsigned long)reloc_addr -
505                                                                         (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
506                                                                 /sizeof(unsigned long);
507                                                         index /= 2;
508                                                         //DPRINTF("        index %x delta %x\n",index,delta);
509                                                         ptr = (unsigned long *)tpnt->data_words;
510                                                         ptr[index] = targ_addr;
511                                                         reloc_addr[0] = OPCODE_LI(11,index*4);
512                                                         reloc_addr[1] = OPCODE_B(delta);
513
514                                                         /* instructions were modified */
515                                                         PPC_DCBST(reloc_addr+1);
516                                                         PPC_SYNC;
517                                                         PPC_ICBI(reloc_addr+1);
518                                                 }
519                                         }
520                                         break;
521                                 }
522                         case R_PPC_GLOB_DAT:
523                                 *reloc_addr += symbol_addr;
524                                 break;
525                         case R_PPC_COPY:
526                                 // handled later
527                                 return 0;
528                                 break;
529                         default:
530 #if 0
531                                 _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
532 #if defined (__SUPPORT_LD_DEBUG__)
533                                 _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
534 #endif
535                                 if (symtab_index)
536                                         _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
537 #endif
538                                 //_dl_exit(1);
539                                 return -1;
540                 };
541
542                 /* instructions were modified */
543                 PPC_DCBST(reloc_addr);
544                 PPC_SYNC;
545                 PPC_ICBI(reloc_addr);
546                 PPC_ISYNC;
547
548 #if defined (__SUPPORT_LD_DEBUG__)
549         if(_dl_debug_reloc && _dl_debug_detail)
550                 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
551 #endif
552
553         return 0;
554 }
555
556
557 /* This is done as a separate step, because there are cases where
558    information is first copied and later initialized.  This results in
559    the wrong information being copied.  Someone at Sun was complaining about
560    a bug in the handling of _COPY by SVr4, and this may in fact be what he
561    was talking about.  Sigh. */
562 static int
563 _dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope,
564              ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
565 {
566         int reloc_type;
567         int symtab_index;
568         unsigned long *reloc_addr;
569         unsigned long symbol_addr;
570         int goof = 0;
571         char *symname;
572           
573         reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
574         reloc_type = ELF32_R_TYPE(rpnt->r_info);
575         if (reloc_type != R_PPC_COPY) 
576                 return 0;
577         symtab_index = ELF32_R_SYM(rpnt->r_info);
578         symbol_addr = 0;
579         symname      = strtab + symtab[symtab_index].st_name;
580                 
581         if (symtab_index) {
582                 symbol_addr = (unsigned long) _dl_find_hash(symname, scope, NULL, copyrel);
583                 if (!symbol_addr) goof++;
584         }
585         if (!goof) {
586 #if defined (__SUPPORT_LD_DEBUG__)
587                 if(_dl_debug_move)
588                   _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
589                              symname, symtab[symtab_index].st_size,
590                              symbol_addr, symtab[symtab_index].st_value);
591 #endif
592                 _dl_memcpy((char *) symtab[symtab_index].st_value, 
593                         (char *) symbol_addr, symtab[symtab_index].st_size);
594         }
595
596         return goof;
597 }
598
599 void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, 
600         unsigned long rel_addr, unsigned long rel_size, int type)
601 {
602         (void) type;
603         (void)_dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
604 }
605
606 int _dl_parse_relocation_information(struct elf_resolve *tpnt, 
607         unsigned long rel_addr, unsigned long rel_size, int type)
608 {
609         (void) type;
610         return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
611 }
612
613 int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, 
614         unsigned long rel_size, int type)
615 {
616         (void) type;
617         return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy);
618 }
619
620