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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1325 phoenix
/* vi: set sw=4 ts=4: */
2
/* i386 ELF shared library loader suppport
3
 *
4
 * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
5
 *                              David Engel, Hongjiu Lu and Mitch D'Souza
6
 * Copyright (C) 2001-2002, Erik Andersen
7
 *
8
 * All rights reserved.
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. The name of the above contributors may not be
16
 *    used to endorse or promote products derived from this software
17
 *    without specific prior written permission.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
20
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
23
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
 * SUCH DAMAGE.
30
 */
31
 
32
#if defined (__SUPPORT_LD_DEBUG__)
33
static const char *_dl_reltypes_tab[] =
34
{
35
  [0]    "R_386_NONE",       "R_386_32",     "R_386_PC32",       "R_386_GOT32",
36
  [4]   "R_386_PLT32",      "R_386_COPY",   "R_386_GLOB_DAT",   "R_386_JMP_SLOT",
37
  [8]   "R_386_RELATIVE",   "R_386_GOTOFF", "R_386_GOTPC",
38
};
39
 
40
static const char *
41
_dl_reltypes(int type)
42
{
43
  static char buf[22];
44
  const char *str;
45
 
46
  if (type >= (int)(sizeof (_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) ||
47
      NULL == (str = _dl_reltypes_tab[type]))
48
  {
49
    str =_dl_simple_ltoa( buf, (unsigned long)(type));
50
  }
51
  return str;
52
}
53
 
54
static
55
void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
56
{
57
  if(_dl_debug_symbols)
58
  {
59
    if(symtab_index){
60
      _dl_dprintf(_dl_debug_file, "\n%s\n\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",
61
                  strtab + symtab[symtab_index].st_name,
62
                  symtab[symtab_index].st_value,
63
                  symtab[symtab_index].st_size,
64
                  symtab[symtab_index].st_info,
65
                  symtab[symtab_index].st_other,
66
                  symtab[symtab_index].st_shndx);
67
    }
68
  }
69
}
70
 
71
static void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt)
72
{
73
  if(_dl_debug_reloc)
74
  {
75
    int symtab_index;
76
    const char *sym;
77
    symtab_index = ELF32_R_SYM(rpnt->r_info);
78
    sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0";
79
 
80
  if(_dl_debug_symbols)
81
          _dl_dprintf(_dl_debug_file, "\n\t");
82
  else
83
          _dl_dprintf(_dl_debug_file, "\n%s\n\t", sym);
84
#ifdef ELF_USES_RELOCA
85
    _dl_dprintf(_dl_debug_file, "%s\toffset=%x\taddend=%x",
86
                _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
87
                rpnt->r_offset,
88
                rpnt->r_addend);
89
#else
90
    _dl_dprintf(_dl_debug_file, "%s\toffset=%x\n",
91
                _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
92
                rpnt->r_offset);
93
#endif
94
  }
95
}
96
#endif
97
 
98
/* Program to load an ELF binary on a linux system, and run it.
99
   References to symbols in sharable libraries can be resolved by either
100
   an ELF sharable library or a linux style of shared library. */
101
 
102
/* Disclaimer:  I have never seen any AT&T source code for SVr4, nor have
103
   I ever taken any courses on internals.  This program was developed using
104
   information available through the book "UNIX SYSTEM V RELEASE 4,
105
   Programmers guide: Ansi C and Programming Support Tools", which did
106
   a more than adequate job of explaining everything required to get this
107
   working. */
108
 
109
extern int _dl_linux_resolve(void);
110
 
111
unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
112
{
113
        int reloc_type;
114
        ELF_RELOC *this_reloc;
115
        char *strtab;
116
        Elf32_Sym *symtab;
117
        int symtab_index;
118
        char *rel_addr;
119
        char *new_addr;
120
        char **got_addr;
121
        unsigned long instr_addr;
122
        char *symname;
123
 
124
        rel_addr = (char *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
125
 
126
        this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
127
        reloc_type = ELF32_R_TYPE(this_reloc->r_info);
128
        symtab_index = ELF32_R_SYM(this_reloc->r_info);
129
 
130
        symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
131
        strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
132
        symname= strtab + symtab[symtab_index].st_name;
133
 
134
        if (reloc_type != R_386_JMP_SLOT) {
135
                _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n",
136
                                _dl_progname);
137
                _dl_exit(1);
138
        }
139
 
140
        /* Address of jump instruction to fix up */
141
        instr_addr = ((unsigned long) this_reloc->r_offset +
142
                        (unsigned long) tpnt->loadaddr);
143
        got_addr = (char **) instr_addr;
144
 
145
        /* Get the address of the GOT entry */
146
        new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, resolver);
147
        if (!new_addr) {
148
                new_addr = _dl_find_hash(symname, NULL, NULL, resolver);
149
                if (new_addr) {
150
                        return (unsigned long) new_addr;
151
                }
152
                _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
153
                _dl_exit(1);
154
        }
155
 
156
#if defined (__SUPPORT_LD_DEBUG__)
157
        if ((unsigned long) got_addr < 0x40000000)
158
        {
159
                if (_dl_debug_bindings)
160
                {
161
                        _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
162
                        if(_dl_debug_detail) _dl_dprintf(_dl_debug_file,
163
                                        "\n\tpatched %x ==> %x @ %x\n", *got_addr, new_addr, got_addr);
164
                }
165
        }
166
        if (!_dl_debug_nofixups) {
167
                *got_addr = new_addr;
168
        }
169
#else
170
        *got_addr = new_addr;
171
#endif
172
 
173
        return (unsigned long) new_addr;
174
}
175
 
176
static int
177
_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
178
          unsigned long rel_addr, unsigned long rel_size,
179
          int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
180
                            ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
181
{
182
        unsigned int i;
183
        char *strtab;
184
        Elf32_Sym *symtab;
185
        ELF_RELOC *rpnt;
186
        int symtab_index;
187
 
188
        /* Now parse the relocation information */
189
        rpnt = (ELF_RELOC *)(intptr_t) (rel_addr + tpnt->loadaddr);
190
        rel_size = rel_size / sizeof(ELF_RELOC);
191
 
192
        symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
193
        strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
194
 
195
          for (i = 0; i < rel_size; i++, rpnt++) {
196
                int res;
197
 
198
                symtab_index = ELF32_R_SYM(rpnt->r_info);
199
 
200
                /* When the dynamic linker bootstrapped itself, it resolved some symbols.
201
                   Make sure we do not do them again */
202
                if (!symtab_index && tpnt->libtype == program_interpreter)
203
                        continue;
204
                if (symtab_index && tpnt->libtype == program_interpreter &&
205
                    _dl_symbol(strtab + symtab[symtab_index].st_name))
206
                        continue;
207
 
208
#if defined (__SUPPORT_LD_DEBUG__)
209
                debug_sym(symtab,strtab,symtab_index);
210
                debug_reloc(symtab,strtab,rpnt);
211
#endif
212
 
213
                res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
214
 
215
                if (res==0) continue;
216
 
217
                _dl_dprintf(2, "\n%s: ",_dl_progname);
218
 
219
                if (symtab_index)
220
                  _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
221
 
222
                if (res <0)
223
                {
224
                        int reloc_type = ELF32_R_TYPE(rpnt->r_info);
225
#if defined (__SUPPORT_LD_DEBUG__)
226
                        _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
227
#else
228
                        _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
229
#endif                  
230
                        _dl_exit(-res);
231
                }
232
                else if (res >0)
233
                {
234
                        _dl_dprintf(2, "can't resolve symbol\n");
235
                        return res;
236
                }
237
          }
238
          return 0;
239
}
240
 
241
 
242
static int
243
_dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
244
              ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
245
{
246
        int reloc_type;
247
        int symtab_index;
248
        char *symname;
249
        unsigned long *reloc_addr;
250
        unsigned long symbol_addr;
251
#if defined (__SUPPORT_LD_DEBUG__)
252
        unsigned long old_val;
253
#endif
254
 
255
        reloc_addr   = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
256
        reloc_type   = ELF32_R_TYPE(rpnt->r_info);
257
        symtab_index = ELF32_R_SYM(rpnt->r_info);
258
        symbol_addr  = 0;
259
        symname      = strtab + symtab[symtab_index].st_name;
260
 
261
        if (symtab_index) {
262
 
263
                symbol_addr = (unsigned long) _dl_find_hash(symname, scope,
264
                                (reloc_type == R_386_JMP_SLOT ? tpnt : NULL), symbolrel);
265
 
266
                /*
267
                 * We want to allow undefined references to weak symbols - this might
268
                 * have been intentional.  We should not be linking local symbols
269
                 * here, so all bases should be covered.
270
                 */
271
 
272
                if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
273
#if defined (__SUPPORT_LD_DEBUG__)
274
                        _dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s'\n",
275
                                        symname, tpnt->libname);
276
#endif
277
                        return 0;
278
                }
279
        }
280
 
281
#if defined (__SUPPORT_LD_DEBUG__)
282
        old_val = *reloc_addr;
283
#endif
284
                switch (reloc_type) {
285
                        case R_386_NONE:
286
                                break;
287
                        case R_386_32:
288
                                *reloc_addr += symbol_addr;
289
                                break;
290
                        case R_386_PC32:
291
                                *reloc_addr += symbol_addr - (unsigned long) reloc_addr;
292
                                break;
293
                        case R_386_GLOB_DAT:
294
                        case R_386_JMP_SLOT:
295
                                *reloc_addr = symbol_addr;
296
                                break;
297
                        case R_386_RELATIVE:
298
                                *reloc_addr += (unsigned long) tpnt->loadaddr;
299
                                break;
300
                        case R_386_COPY:
301
                                /* handled later on */
302
                                break;
303
                        default:
304
                                return -1; /*call _dl_exit(1) */
305
                }
306
#if defined (__SUPPORT_LD_DEBUG__)
307
        if(_dl_debug_reloc && _dl_debug_detail)
308
                _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
309
#endif
310
 
311
        return 0;
312
}
313
 
314
static int
315
_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
316
                   ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
317
{
318
        int reloc_type;
319
        unsigned long *reloc_addr;
320
#if defined (__SUPPORT_LD_DEBUG__)
321
        unsigned long old_val;
322
#endif
323
        (void)scope;
324
        (void)symtab;
325
        (void)strtab;
326
 
327
        reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
328
        reloc_type = ELF32_R_TYPE(rpnt->r_info);
329
 
330
#if defined (__SUPPORT_LD_DEBUG__)
331
        old_val = *reloc_addr;
332
#endif
333
                switch (reloc_type) {
334
                        case R_386_NONE:
335
                                break;
336
                        case R_386_JMP_SLOT:
337
                                *reloc_addr += (unsigned long) tpnt->loadaddr;
338
                                break;
339
                        default:
340
                                return -1; /*call _dl_exit(1) */
341
                }
342
#if defined (__SUPPORT_LD_DEBUG__)
343
        if(_dl_debug_reloc && _dl_debug_detail)
344
                _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
345
#endif
346
        return 0;
347
 
348
}
349
 
350
/* This is done as a separate step, because there are cases where
351
   information is first copied and later initialized.  This results in
352
   the wrong information being copied.  Someone at Sun was complaining about
353
   a bug in the handling of _COPY by SVr4, and this may in fact be what he
354
   was talking about.  Sigh. */
355
 
356
/* No, there are cases where the SVr4 linker fails to emit COPY relocs
357
   at all */
358
static int
359
_dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope,
360
             ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
361
{
362
        int reloc_type;
363
        int symtab_index;
364
        unsigned long *reloc_addr;
365
        unsigned long symbol_addr;
366
        int goof = 0;
367
        char *symname;
368
 
369
        reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
370
        reloc_type = ELF32_R_TYPE(rpnt->r_info);
371
        if (reloc_type != R_386_COPY)
372
                return 0;
373
        symtab_index = ELF32_R_SYM(rpnt->r_info);
374
        symbol_addr = 0;
375
        symname      = strtab + symtab[symtab_index].st_name;
376
 
377
        if (symtab_index) {
378
                symbol_addr = (unsigned long) _dl_find_hash(symname, scope, NULL, copyrel);
379
                if (!symbol_addr) goof++;
380
        }
381
        if (!goof) {
382
#if defined (__SUPPORT_LD_DEBUG__)
383
                if(_dl_debug_move)
384
                  _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
385
                             symname, symtab[symtab_index].st_size,
386
                             symbol_addr, symtab[symtab_index].st_value);
387
#endif
388
                _dl_memcpy((char *) symtab[symtab_index].st_value,
389
                        (char *) symbol_addr, symtab[symtab_index].st_size);
390
        }
391
 
392
        return goof;
393
}
394
 
395
void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
396
        unsigned long rel_addr, unsigned long rel_size, int type)
397
{
398
        (void) type;
399
        (void)_dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
400
}
401
 
402
int _dl_parse_relocation_information(struct elf_resolve *tpnt,
403
        unsigned long rel_addr, unsigned long rel_size, int type)
404
{
405
        (void) type;
406
        return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
407
}
408
 
409
int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
410
        unsigned long rel_size, int type)
411
{
412
        (void) type;
413
        return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy);
414
}
415
 

powered by: WebSVN 2.1.0

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