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         char *symname;
175         unsigned long insn_addr;
176         unsigned long *insns;
177         unsigned long new_addr;
178         unsigned long 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);
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;
361                                 unsigned long delta;
362                                 unsigned long *plt;
363                                 unsigned long *insns;
364
365                                 plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
366
367                                 delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2) - (reloc_addr+4);
368
369                                 index = (reloc_addr - (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS)) 
370                                                 /sizeof(unsigned long);
371                                 index /= 2;
372                                 //DPRINTF("        index %x delta %x\n",index,delta);
373                                 insns = (unsigned long *)reloc_addr;
374                                 insns[0] = OPCODE_LI(11,index*4);
375                                 insns[1] = OPCODE_B(delta);
376                                 break;
377                         }
378                 default:
379 #if 0
380                         _dl_dprintf(2, "%s: (LAZY) can't handle reloc type ", 
381                                         _dl_progname);
382 #if defined (__SUPPORT_LD_DEBUG__)
383                         _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
384 #endif
385                         if (symtab_index)
386                                 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
387 #endif
388                         //_dl_exit(1);
389                         return -1;
390         };
391
392         /* instructions were modified */
393         PPC_DCBST(reloc_addr);
394         PPC_DCBST(reloc_addr+4);
395         PPC_SYNC;
396         PPC_ICBI(reloc_addr);
397         PPC_ICBI(reloc_addr+4);
398         PPC_ISYNC;
399
400 #if defined (__SUPPORT_LD_DEBUG__)
401         if(_dl_debug_reloc && _dl_debug_detail)
402                 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x", old_val, reloc_addr);
403 #endif
404         return 0;
405
406 }
407
408 static int
409 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
410               ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
411 {
412         int reloc_type;
413         int symtab_index;
414         char *symname;
415         unsigned long *reloc_addr;
416         unsigned long symbol_addr;
417 #if defined (__SUPPORT_LD_DEBUG__)
418         unsigned long old_val;
419 #endif
420
421         reloc_addr   = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
422         reloc_type   = ELF32_R_TYPE(rpnt->r_info);
423         symtab_index = ELF32_R_SYM(rpnt->r_info);
424         symbol_addr  = 0;
425         symname      = strtab + symtab[symtab_index].st_name;
426
427         if (symtab_index) {
428
429                 symbol_addr = (unsigned long) _dl_find_hash(symname, scope, 
430                                 (reloc_type == R_PPC_JMP_SLOT ? tpnt : NULL), symbolrel);
431
432                 /*
433                  * We want to allow undefined references to weak symbols - this might
434                  * have been intentional.  We should not be linking local symbols
435                  * here, so all bases should be covered.
436                  */
437
438                 if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
439 #if defined (__SUPPORT_LD_DEBUG__)
440                         _dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s'\n",
441                                         symname, tpnt->libname);
442 #endif
443                         return 0;
444                 }
445         }
446
447 #if defined (__SUPPORT_LD_DEBUG__)
448         old_val = *reloc_addr;
449 #endif
450                 switch (reloc_type) {
451                         case R_PPC_NONE:
452                                 return 0;
453                                 break;
454                         case R_PPC_REL24:
455 #if 0
456                                 {
457                                         unsigned long delta = symbol_addr - (unsigned long)reloc_addr;
458                                         if(delta<<6>>6 != delta){
459                                                 _dl_dprintf(2,"R_PPC_REL24: Reloc out of range\n");
460                                                 _dl_exit(1);
461                                         }
462                                         *reloc_addr &= 0xfc000003;
463                                         *reloc_addr |= delta&0x03fffffc;
464                                 }
465                                 break;
466 #else
467                                 _dl_dprintf(2, "%s: symbol '%s' is type R_PPC_REL24\n\tCompile shared libraries with -fPIC!\n",
468                                                 _dl_progname, symname);
469                                 _dl_exit(1);
470 #endif
471                         case R_PPC_RELATIVE:
472                                 *reloc_addr = (unsigned long)tpnt->loadaddr + (unsigned long)rpnt->r_addend;
473                                 break;
474                         case R_PPC_ADDR32:
475                                 *reloc_addr += symbol_addr;
476                                 break;
477                         case R_PPC_ADDR16_HA:
478                                 /* XXX is this correct? */
479                                 *(short *)reloc_addr += (symbol_addr+0x8000)>>16;
480                                 break;
481                         case R_PPC_ADDR16_HI:
482                                 *(short *)reloc_addr += symbol_addr>>16;
483                                 break;
484                         case R_PPC_ADDR16_LO:
485                                 *(short *)reloc_addr += symbol_addr;
486                                 break;
487                         case R_PPC_JMP_SLOT:
488                                 {
489                                         unsigned long targ_addr = (unsigned long)*reloc_addr;
490                                         unsigned long delta = targ_addr - (unsigned long)reloc_addr;
491                                         if(delta<<6>>6 == delta){
492                                                 *reloc_addr = OPCODE_B(delta);
493                                         }else if (targ_addr <= 0x01fffffc || targ_addr >= 0xfe000000){
494                                                 *reloc_addr = OPCODE_BA (targ_addr);
495                                         }else{
496                                                 {
497                                                         int index;
498                                                         unsigned long delta2;
499                                                         unsigned long *plt, *ptr;
500                                                         plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
501
502                                                         delta2 = (unsigned long)(plt+PLT_LONGBRANCH_ENTRY_WORDS)
503                                                                 - (unsigned long)(reloc_addr+1);
504
505                                                         index = ((unsigned long)reloc_addr -
506                                                                         (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
507                                                                 /sizeof(unsigned long);
508                                                         index /= 2;
509                                                         //DPRINTF("        index %x delta %x\n",index,delta2);
510                                                         ptr = (unsigned long *)tpnt->data_words;
511                                                         ptr[index] = targ_addr;
512                                                         reloc_addr[0] = OPCODE_LI(11,index*4);
513                                                         reloc_addr[1] = OPCODE_B(delta2);
514
515                                                         /* instructions were modified */
516                                                         PPC_DCBST(reloc_addr+1);
517                                                         PPC_SYNC;
518                                                         PPC_ICBI(reloc_addr+1);
519                                                 }
520                                         }
521                                         break;
522                                 }
523                         case R_PPC_GLOB_DAT:
524                                 *reloc_addr += symbol_addr;
525                                 break;
526                         case R_PPC_COPY:
527                                 // handled later
528                                 return 0;
529                                 break;
530                         default:
531 #if 0
532                                 _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
533 #if defined (__SUPPORT_LD_DEBUG__)
534                                 _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
535 #endif
536                                 if (symtab_index)
537                                         _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
538 #endif
539                                 //_dl_exit(1);
540                                 return -1;
541                 };
542
543                 /* instructions were modified */
544                 PPC_DCBST(reloc_addr);
545                 PPC_SYNC;
546                 PPC_ICBI(reloc_addr);
547                 PPC_ISYNC;
548
549 #if defined (__SUPPORT_LD_DEBUG__)
550         if(_dl_debug_reloc && _dl_debug_detail)
551                 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
552 #endif
553
554         return 0;
555 }
556
557
558 /* This is done as a separate step, because there are cases where
559    information is first copied and later initialized.  This results in
560    the wrong information being copied.  Someone at Sun was complaining about
561    a bug in the handling of _COPY by SVr4, and this may in fact be what he
562    was talking about.  Sigh. */
563 static int
564 _dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope,
565              ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
566 {
567         int reloc_type;
568         int symtab_index;
569         unsigned long *reloc_addr;
570         unsigned long symbol_addr;
571         int goof = 0;
572         char *symname;
573           
574         reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
575         reloc_type = ELF32_R_TYPE(rpnt->r_info);
576         if (reloc_type != R_PPC_COPY) 
577                 return 0;
578         symtab_index = ELF32_R_SYM(rpnt->r_info);
579         symbol_addr = 0;
580         symname      = strtab + symtab[symtab_index].st_name;
581                 
582         if (symtab_index) {
583                 symbol_addr = (unsigned long) _dl_find_hash(symname, scope, NULL, copyrel);
584                 if (!symbol_addr) goof++;
585         }
586         if (!goof) {
587 #if defined (__SUPPORT_LD_DEBUG__)
588                 if(_dl_debug_move)
589                   _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
590                              symname, symtab[symtab_index].st_size,
591                              symbol_addr, symtab[symtab_index].st_value);
592 #endif
593                         _dl_memcpy((char *) reloc_addr,
594                                         (char *) symbol_addr, symtab[symtab_index].st_size);
595         }
596
597         return goof;
598 }
599
600 void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, 
601         unsigned long rel_addr, unsigned long rel_size, int type)
602 {
603         (void) type;
604         (void)_dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
605 }
606
607 int _dl_parse_relocation_information(struct elf_resolve *tpnt, 
608         unsigned long rel_addr, unsigned long rel_size, int type)
609 {
610         (void) type;
611         return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
612 }
613
614 int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, 
615         unsigned long rel_size, int type)
616 {
617         (void) type;
618         return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy);
619 }
620
621