OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [uClibc/] [ldso/] [ldso/] [sh/] [elfinterp.c] - Blame information for rev 1771

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1325 phoenix
/* vi: set sw=4 ts=4: */
2
/* SuperH ELF shared library loader suppport
3
 *
4
 * Copyright (C) 2002, Stefan Allius <allius@atecom.com> and
5
 *                     Eddie C. Dost <ecd@atecom.com>
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
{
34
  [0]    "R_SH_NONE",    "R_SH_DIR32",   "R_SH_REL32",   "R_SH_DIR8WPN",
35
  [4]   "R_SH_IND12W",  "R_SH_DIR8WPL", "R_SH_DIR8WPZ", "R_SH_DIR8BP",
36
  [8]   "R_SH_DIR8W",   "R_SH_DIR8L",
37
 [25]   "R_SH_SWITCH16","R_SH_SWITCH32","R_SH_USES",
38
 [28]   "R_SH_COUNT",   "R_SH_ALIGN",   "R_SH_CODE",    "R_SH_DATA",
39
 [32]   "R_SH_LABEL",   "R_SH_SWITCH8", "R_SH_GNU_VTINHERIT","R_SH_GNU_VTENTRY",
40
[160]   "R_SH_GOT32",   "R_SH_PLT32",   "R_SH_COPY",    "R_SH_GLOB_DAT",
41
[164]   "R_SH_JMP_SLOT","R_SH_RELATIVE","R_SH_GOTOFF",  "R_SH_GOTPC",
42
};
43
 
44
static const char *
45
_dl_reltypes(int type)
46
{
47
  static char buf[22];
48
  const char *str;
49
 
50
  if (type >= (int)(sizeof (_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) ||
51
      NULL == (str = _dl_reltypes_tab[type]))
52
  {
53
    str =_dl_simple_ltoa( buf, (unsigned long)(type));
54
  }
55
  return str;
56
}
57
 
58
static
59
void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
60
{
61
  if(_dl_debug_symbols)
62
  {
63
    if(symtab_index){
64
      _dl_dprintf(_dl_debug_file, "\n%s\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",
65
                  strtab + symtab[symtab_index].st_name,
66
                  symtab[symtab_index].st_value,
67
                  symtab[symtab_index].st_size,
68
                  symtab[symtab_index].st_info,
69
                  symtab[symtab_index].st_other,
70
                  symtab[symtab_index].st_shndx);
71
    }
72
  }
73
}
74
 
75
static void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt)
76
{
77
  if(_dl_debug_reloc)
78
  {
79
    int symtab_index;
80
    const char *sym;
81
    symtab_index = ELF32_R_SYM(rpnt->r_info);
82
    sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0";
83
 
84
  if(_dl_debug_symbols)
85
          _dl_dprintf(_dl_debug_file, "\n\t");
86
  else
87
          _dl_dprintf(_dl_debug_file, "\n%s\n\t", sym);
88
 
89
#ifdef ELF_USES_RELOCA
90
    _dl_dprintf(_dl_debug_file, "%s\toffset=%x\taddend=%x",
91
                _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
92
                rpnt->r_offset,
93
                rpnt->r_addend);
94
#else
95
    _dl_dprintf(_dl_debug_file, "%s\toffset=%x\n",
96
                _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
97
                rpnt->r_offset);
98
#endif
99
  }
100
}
101
#endif
102
 
103
/* Program to load an ELF binary on a linux system, and run it.
104
   References to symbols in sharable libraries can be resolved by either
105
   an ELF sharable library or a linux style of shared library. */
106
 
107
/* Disclaimer:  I have never seen any AT&T source code for SVr4, nor have
108
   I ever taken any courses on internals.  This program was developed using
109
   information available through the book "UNIX SYSTEM V RELEASE 4,
110
   Programmers guide: Ansi C and Programming Support Tools", which did
111
   a more than adequate job of explaining everything required to get this
112
   working. */
113
 
114
extern int _dl_linux_resolve(void);
115
 
116
unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
117
{
118
        int reloc_type;
119
        ELF_RELOC *this_reloc;
120
        char *strtab;
121
        Elf32_Sym *symtab;
122
        int symtab_index;
123
        char *rel_addr;
124
        char *new_addr;
125
        char **got_addr;
126
        unsigned long instr_addr;
127
        char *symname;
128
 
129
        rel_addr = (char *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
130
 
131
        this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
132
        reloc_type = ELF32_R_TYPE(this_reloc->r_info);
133
        symtab_index = ELF32_R_SYM(this_reloc->r_info);
134
 
135
        symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
136
        strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
137
        symname = strtab + symtab[symtab_index].st_name;
138
 
139
        if (reloc_type != R_SH_JMP_SLOT) {
140
          _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n",
141
                       _dl_progname);
142
          _dl_exit(1);
143
        }
144
 
145
        /* Address of jump instruction to fix up */
146
        instr_addr = ((unsigned long) this_reloc->r_offset +
147
                        (unsigned long) tpnt->loadaddr);
148
        got_addr = (char **) instr_addr;
149
 
150
 
151
        /* Get the address of the GOT entry */
152
        new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, resolver);
153
        if (!new_addr) {
154
                new_addr = _dl_find_hash(symname, NULL, NULL, resolver);
155
                if (new_addr) {
156
                        return (unsigned long) new_addr;
157
                }
158
 
159
                _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
160
                _dl_exit(1);
161
        }
162
 
163
#if defined (__SUPPORT_LD_DEBUG__)
164
        if ((unsigned long) got_addr < 0x20000000)
165
        {
166
                if (_dl_debug_bindings)
167
                {
168
                        _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
169
                        if(_dl_debug_detail) _dl_dprintf(_dl_debug_file,
170
                                        "\n\tpatched %x ==> %x @ %x\n", *got_addr, new_addr, got_addr);
171
                }
172
        }
173
        if (!_dl_debug_nofixups) {
174
                *got_addr = new_addr;
175
        }
176
#else
177
        *got_addr = new_addr;
178
#endif
179
 
180
        return (unsigned long) new_addr;
181
}
182
 
183
 
184
static int
185
_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
186
          unsigned long rel_addr, unsigned long rel_size,
187
          int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
188
                            ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
189
{
190
        unsigned int i;
191
        char *strtab;
192
        Elf32_Sym *symtab;
193
        ELF_RELOC *rpnt;
194
        int symtab_index;
195
        /* Now parse the relocation information */
196
 
197
        rpnt = (ELF_RELOC *)(intptr_t) (rel_addr + tpnt->loadaddr);
198
        rel_size = rel_size / sizeof(ELF_RELOC);
199
 
200
        symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
201
        strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
202
 
203
          for (i = 0; i < rel_size; i++, rpnt++) {
204
                int res;
205
 
206
                symtab_index = ELF32_R_SYM(rpnt->r_info);
207
 
208
                /* When the dynamic linker bootstrapped itself, it resolved some symbols.
209
                   Make sure we do not do them again */
210
                if (!symtab_index && tpnt->libtype == program_interpreter)
211
                        continue;
212
                if (symtab_index && tpnt->libtype == program_interpreter &&
213
                    _dl_symbol(strtab + symtab[symtab_index].st_name))
214
                        continue;
215
 
216
#if defined (__SUPPORT_LD_DEBUG__)
217
                debug_sym(symtab,strtab,symtab_index);
218
                debug_reloc(symtab,strtab,rpnt);
219
#endif
220
 
221
                res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
222
 
223
                if (res==0) continue;
224
 
225
                _dl_dprintf(2, "\n%s: ",_dl_progname);
226
 
227
                if (symtab_index)
228
                  _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
229
 
230
                if (res <0)
231
                {
232
                        int reloc_type = ELF32_R_TYPE(rpnt->r_info);
233
#if defined (__SUPPORT_LD_DEBUG__)
234
                        _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
235
#else
236
                        _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
237
#endif                  
238
                        _dl_exit(-res);
239
                }
240
                else if (res >0)
241
                {
242
                        _dl_dprintf(2, "can't resolve symbol\n");
243
                        return res;
244
                }
245
          }
246
          return 0;
247
}
248
 
249
 
250
static int
251
_dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
252
              ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
253
{
254
        int reloc_type;
255
        int symtab_index;
256
        char *symname;
257
        unsigned long *reloc_addr;
258
        unsigned long symbol_addr;
259
#if defined (__SUPPORT_LD_DEBUG__)
260
        unsigned long old_val;
261
#endif
262
 
263
        reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
264
        reloc_type = ELF32_R_TYPE(rpnt->r_info);
265
        symtab_index = ELF32_R_SYM(rpnt->r_info);
266
        symbol_addr = 0;
267
        symname      = strtab + symtab[symtab_index].st_name;
268
 
269
        if (symtab_index) {
270
 
271
 
272
                symbol_addr = (unsigned long) _dl_find_hash(symname, scope,
273
                                (reloc_type == R_SH_JMP_SLOT ? tpnt : NULL), symbolrel);
274
 
275
                /*
276
                 * We want to allow undefined references to weak symbols - this might
277
                 * have been intentional.  We should not be linking local symbols
278
                 * here, so all bases should be covered.
279
                 */
280
                if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
281
#if defined (__SUPPORT_LD_DEBUG__)
282
                        _dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s'\n",
283
                                        symname, tpnt->libname);
284
#endif
285
                        return 0;
286
                }
287
        }
288
 
289
 
290
#if defined (__SUPPORT_LD_DEBUG__)
291
        old_val = *reloc_addr;
292
#endif
293
            switch (reloc_type) {
294
                case R_SH_NONE:
295
                        break;
296
                case R_SH_COPY:
297
                        /* handled later on */
298
                        break;
299
                case R_SH_DIR32:
300
                case R_SH_GLOB_DAT:
301
                case R_SH_JMP_SLOT:
302
                        *reloc_addr = symbol_addr + rpnt->r_addend;
303
                        break;
304
                case R_SH_REL32:
305
                        *reloc_addr = symbol_addr + rpnt->r_addend -
306
                                        (unsigned long) reloc_addr;
307
                        break;
308
                case R_SH_RELATIVE:
309
                        *reloc_addr = (unsigned long) tpnt->loadaddr + rpnt->r_addend;
310
                        break;
311
                default:
312
                        return -1; /*call _dl_exit(1) */
313
            }
314
#if defined (__SUPPORT_LD_DEBUG__)
315
            if(_dl_debug_reloc && _dl_debug_detail)
316
                _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
317
#endif
318
 
319
        return 0;
320
}
321
 
322
 
323
static int
324
_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
325
                   ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
326
{
327
        int reloc_type;
328
        unsigned long *reloc_addr;
329
#if defined (__SUPPORT_LD_DEBUG__)
330
        unsigned long old_val;
331
#endif
332
        (void)scope;
333
        (void)symtab;
334
        (void)strtab;
335
 
336
        reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
337
        reloc_type = ELF32_R_TYPE(rpnt->r_info);
338
 
339
#if defined (__SUPPORT_LD_DEBUG__)
340
        old_val = *reloc_addr;
341
#endif
342
            switch (reloc_type) {
343
              case R_SH_NONE:
344
                break;
345
              case R_SH_JMP_SLOT:
346
                *reloc_addr += (unsigned long) tpnt->loadaddr;
347
                break;
348
              default:
349
                return -1; /*call _dl_exit(1) */
350
            }
351
#if defined (__SUPPORT_LD_DEBUG__)
352
            if(_dl_debug_reloc && _dl_debug_detail)
353
                _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
354
#endif
355
        return 0;
356
 
357
}
358
 
359
/* This is done as a separate step, because there are cases where
360
   information is first copied and later initialized.  This results in
361
   the wrong information being copied.  Someone at Sun was complaining about
362
   a bug in the handling of _COPY by SVr4, and this may in fact be what he
363
   was talking about.  Sigh. */
364
 
365
/* No, there are cases where the SVr4 linker fails to emit COPY relocs
366
   at all */
367
static int
368
_dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope,
369
             ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
370
{
371
        int reloc_type;
372
        int symtab_index;
373
        unsigned long *reloc_addr;
374
        unsigned long symbol_addr;
375
        int goof = 0;
376
        char*symname;
377
 
378
        reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
379
        reloc_type = ELF32_R_TYPE(rpnt->r_info);
380
        if (reloc_type != R_SH_COPY)
381
            return 0;
382
        symtab_index = ELF32_R_SYM(rpnt->r_info);
383
        symbol_addr = 0;
384
        symname      = strtab + symtab[symtab_index].st_name;
385
 
386
        if (symtab_index) {
387
 
388
                symbol_addr = (unsigned long) _dl_find_hash(symname, scope, NULL, copyrel);
389
                if (!symbol_addr) goof++;
390
        }
391
        if (!goof) {
392
#if defined (__SUPPORT_LD_DEBUG__)
393
                if(_dl_debug_move)
394
                  _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
395
                             symname, symtab[symtab_index].st_size,
396
                             symbol_addr, symtab[symtab_index].st_value);
397
#endif
398
                _dl_memcpy((char *) symtab[symtab_index].st_value,
399
                        (char *) symbol_addr, symtab[symtab_index].st_size);
400
        }
401
 
402
        return goof;
403
}
404
 
405
 
406
void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
407
        unsigned long rel_addr, unsigned long rel_size, int type)
408
{
409
        (void) type;
410
        (void)_dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
411
}
412
 
413
int _dl_parse_relocation_information(struct elf_resolve *tpnt,
414
        unsigned long rel_addr, unsigned long rel_size, int type)
415
{
416
        (void) type;
417
        return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
418
}
419
 
420
int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
421
        unsigned long rel_size, int type)
422
{
423
        (void) type;
424
        return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy);
425
}
426
 
427
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.