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 lbranch_addr;
235                 unsigned long *ptr;
236                 int index;
237
238                 plt_addr = (unsigned long)tpnt->dynamic_info[DT_PLTGOT] + 
239                         (unsigned long)tpnt->loadaddr;
240                 lbranch_addr = plt_addr + PLT_LONGBRANCH_ENTRY_WORDS*4;
241                 delta = lbranch_addr - insn_addr;
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                 ptr[index] = new_addr;
247                 /* icache sync is not necessary, since this will be a data load */
248                 //PPC_DCBST(ptr+index);
249                 //PPC_SYNC;
250                 //PPC_ICBI(ptr+index);
251                 //PPC_ISYNC;
252
253                 /* instructions were modified */
254                 insns[1] = OPCODE_B(delta - 4);
255                 PPC_DCBST(insn_addr+1);
256                 PPC_SYNC;
257                 PPC_ICBI(insn_addr+1);
258                 PPC_ISYNC;
259                 
260                 return new_addr;
261         }
262
263         /* instructions were modified */
264         PPC_DCBST(insn_addr);
265         PPC_SYNC;
266         PPC_ICBI(insn_addr);
267         PPC_ISYNC;
268
269         return new_addr;
270 }
271
272 static int
273 _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
274           unsigned long rel_addr, unsigned long rel_size,
275           int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
276                             ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
277 {
278         unsigned int i;
279         char *strtab;
280         Elf32_Sym *symtab;
281         ELF_RELOC *rpnt;
282         int symtab_index;
283
284         /* Now parse the relocation information */
285         rpnt = (ELF_RELOC *)(intptr_t) (rel_addr + tpnt->loadaddr);
286         rel_size = rel_size / sizeof(ELF_RELOC);
287
288         symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
289         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
290
291           for (i = 0; i < rel_size; i++, rpnt++) {
292                 int res;
293             
294                 symtab_index = ELF32_R_SYM(rpnt->r_info);
295                 
296                 /* When the dynamic linker bootstrapped itself, it resolved some symbols.
297                    Make sure we do not do them again */
298                 if (!symtab_index && tpnt->libtype == program_interpreter)
299                         continue;
300                 if (symtab_index && tpnt->libtype == program_interpreter &&
301                     _dl_symbol(strtab + symtab[symtab_index].st_name))
302                         continue;
303
304 #if defined (__SUPPORT_LD_DEBUG__)
305                 debug_sym(symtab,strtab,symtab_index);
306                 debug_reloc(symtab,strtab,rpnt);
307 #endif
308
309                 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
310
311                 if (res==0) continue;
312
313                 _dl_dprintf(2, "\n%s: ",_dl_progname);
314                 
315                 if (symtab_index)
316                   _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
317                   
318                 if (res <0)
319                 {
320                         int reloc_type = ELF32_R_TYPE(rpnt->r_info);
321 #if defined (__SUPPORT_LD_DEBUG__)
322                         _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
323 #else
324                         _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
325 #endif                  
326                         _dl_exit(-res);
327                 }
328                 else if (res >0)
329                 {
330                         _dl_dprintf(2, "can't resolve symbol\n");
331                         return res;
332                 }
333           }
334           return 0;
335 }
336
337 static int
338 _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
339                    ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
340 {
341         int reloc_type;
342         unsigned long reloc_addr;
343 #if defined (__SUPPORT_LD_DEBUG__)
344         unsigned long old_val;
345 #endif
346         (void)scope;
347         (void)symtab;
348         (void)strtab;
349
350         reloc_addr = (unsigned long)tpnt->loadaddr + (unsigned long) rpnt->r_offset;
351         reloc_type = ELF32_R_TYPE(rpnt->r_info);
352
353 #if defined (__SUPPORT_LD_DEBUG__)
354         old_val = reloc_addr;
355 #endif
356
357         switch (reloc_type) {
358                 case R_PPC_NONE:
359                         return 0;
360                         break;
361                 case R_PPC_JMP_SLOT:
362                         {
363                                 int index, delta;
364                                 unsigned long *plt;
365                                 unsigned long *insns;
366
367                                 plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
368
369                                 delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2) - (reloc_addr+4);
370
371                                 index = (reloc_addr - (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS)) 
372                                                 /sizeof(unsigned long);
373                                 index /= 2;
374                                 //DPRINTF("        index %x delta %x\n",index,delta);
375                                 insns = (unsigned long *)reloc_addr;
376                                 insns[0] = OPCODE_LI(11,index*4);
377                                 insns[1] = OPCODE_B(delta);
378                                 break;
379                         }
380                 default:
381 #if 0
382                         _dl_dprintf(2, "%s: (LAZY) can't handle reloc type ", 
383                                         _dl_progname);
384 #if defined (__SUPPORT_LD_DEBUG__)
385                         _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
386 #endif
387                         if (symtab_index)
388                                 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
389 #endif
390                         //_dl_exit(1);
391                         return -1;
392         };
393
394         /* instructions were modified */
395         PPC_DCBST(reloc_addr);
396         PPC_DCBST(reloc_addr+1);
397         PPC_SYNC;
398         PPC_ICBI(reloc_addr);
399         PPC_ICBI(reloc_addr+1);
400         PPC_ISYNC;
401
402 #if defined (__SUPPORT_LD_DEBUG__)
403         if(_dl_debug_reloc && _dl_debug_detail)
404                 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x", old_val, reloc_addr);
405 #endif
406         return 0;
407
408 }
409
410 static int
411 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
412               ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
413 {
414         int reloc_type;
415         int symtab_index;
416         char *symname;
417         unsigned long *reloc_addr;
418         unsigned long symbol_addr;
419 #if defined (__SUPPORT_LD_DEBUG__)
420         unsigned long old_val;
421 #endif
422
423         reloc_addr   = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
424         reloc_type   = ELF32_R_TYPE(rpnt->r_info);
425         symtab_index = ELF32_R_SYM(rpnt->r_info);
426         symbol_addr  = 0;
427         symname      = strtab + symtab[symtab_index].st_name;
428
429         if (symtab_index) {
430
431                 symbol_addr = (unsigned long) _dl_find_hash(symname, scope, 
432                                 (reloc_type == R_386_JMP_SLOT ? tpnt : NULL), symbolrel);
433
434                 /*
435                  * We want to allow undefined references to weak symbols - this might
436                  * have been intentional.  We should not be linking local symbols
437                  * here, so all bases should be covered.
438                  */
439
440                 if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
441 #if defined (__SUPPORT_LD_DEBUG__)
442                         _dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s'\n",
443                                         symname, tpnt->libname);
444 #endif
445                         return 0;
446                 }
447         }
448
449 #if defined (__SUPPORT_LD_DEBUG__)
450         old_val = *reloc_addr;
451 #endif
452                 switch (reloc_type) {
453                         case R_PPC_NONE:
454                                 return 0;
455                                 break;
456                         case R_PPC_REL24:
457 #if 0
458                                 {
459                                         int delta = symbol_addr - (unsigned long)reloc_addr;
460                                         if(delta<<6>>6 != delta){
461                                                 _dl_dprintf(2,"R_PPC_REL24: Reloc out of range\n");
462                                                 _dl_exit(1);
463                                         }
464                                         *reloc_addr &= 0xfc000003;
465                                         *reloc_addr |= delta&0x03fffffc;
466                                 }
467                                 break;
468 #else
469                                 _dl_dprintf(2, "%s: symbol '%s' is type R_PPC_REL24\n\tCompile shared libraries with -fPIC!\n",
470                                                 _dl_progname, symname);
471                                 _dl_exit(1);
472 #endif
473                         case R_PPC_RELATIVE:
474                                 *reloc_addr = (unsigned long)tpnt->loadaddr + (unsigned long)rpnt->r_addend;
475                                 break;
476                         case R_PPC_ADDR32:
477                                 *reloc_addr += symbol_addr;
478                                 break;
479                         case R_PPC_ADDR16_HA:
480                                 /* XXX is this correct? */
481                                 *(short *)reloc_addr += (symbol_addr+0x8000)>>16;
482                                 break;
483                         case R_PPC_ADDR16_HI:
484                                 *(short *)reloc_addr += symbol_addr>>16;
485                                 break;
486                         case R_PPC_ADDR16_LO:
487                                 *(short *)reloc_addr += symbol_addr;
488                                 break;
489                         case R_PPC_JMP_SLOT:
490                                 {
491                                         unsigned long targ_addr = (unsigned long)*reloc_addr;
492                                         int delta = targ_addr - (unsigned long)reloc_addr;
493                                         if(delta<<6>>6 == delta){
494                                                 *reloc_addr = OPCODE_B(delta);
495                                         }else if (targ_addr <= 0x01fffffc || targ_addr >= 0xfe000000){
496                                                 *reloc_addr = OPCODE_BA (targ_addr);
497                                         }else{
498                                                 {
499                                                         int delta;
500                                                         int index;
501                                                         unsigned long *plt;
502                                                         plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
503
504                                                         delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2)
505                                                                 - (unsigned long)(reloc_addr+1);
506
507                                                         index = ((unsigned long)reloc_addr -
508                                                                         (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
509                                                                 /sizeof(unsigned long);
510                                                         index /= 2;
511                                                         //DPRINTF("        index %x delta %x\n",index,delta);
512                                                         reloc_addr[0] = OPCODE_LI(11,index*4);
513                                                         reloc_addr[1] = OPCODE_B(delta);
514
515                                                         /* instructions were modified */
516                                                         PPC_DCBST(reloc_addr+1);
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_386_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