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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1325 phoenix
/* vi: set sw=8 ts=8: */
2
/*
3
 * ldso/ldso/sh64/elfinterp.c
4
 *
5
 * SuperH (sh64) ELF shared library loader suppport
6
 *
7
 * Copyright (C) 2003  Paul Mundt <lethal@linux-sh.org>
8
 *
9
 * All rights reserved.
10
 *
11
 * Redistribution and use in source and binary forms, with or without
12
 * modification, are permitted provided that the following conditions
13
 * are met:
14
 * 1. Redistributions of source code must retain the above copyright
15
 *    notice, this list of conditions and the following disclaimer.
16
 * 2. The name of the above contributors may not be
17
 *    used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
 
33
#ifdef __SUPPORT_LD_DEBUG__
34
static const char *_dl_reltypes_tab[] = {
35
        /* SHcompact relocs */
36
          [0] =  "R_SH_NONE",            "R_SH_DIR32",
37
                "R_SH_REL32",           "R_SH_DIR8WPN",
38
          [4] = "R_SH_IND12W",          "R_SH_DIR8WPL",
39
                "R_SH_DIR8WPZ",         "R_SH_DIR8BP",
40
          [8] = "R_SH_DIR8W",           "R_SH_DIR8L",
41
         [25] = "R_SH_SWITCH16",        "R_SH_SWITCH32",
42
                "R_SH_USES",            "R_SH_COUNT",
43
         [29] = "R_SH_ALIGN",           "R_SH_CODE",
44
                "R_SH_DATA",            "R_SH_LABEL",
45
         [33] = "R_SH_SWITCH8",         "R_SH_GNU_VTINHERIT",
46
                "R_SH_GNU_VTENTRY",
47
        [160] = "R_SH_GOT32",           "R_SH_PLT32",
48
                "R_SH_COPY",            "R_SH_GLOB_DAT",
49
        [164] = "R_SH_JMP_SLOT",        "R_SH_RELATIVE",
50
                "R_SH_GOTOFF",          "R_SH_GOTPC",
51
 
52
        /* SHmedia relocs */
53
         [45] = "R_SH_DIR5U",           "R_SH_DIR6U",
54
                "R_SH_DIR6S",           "R_SH_DIR10S",
55
         [49] = "R_SH_DIR10SW",         "R_SH_DIR10SL",
56
                "R_SH_DIR10SQ",
57
        [169] = "R_SH_GOT_LOW16",       "R_SH_GOT_MEDLOW16",
58
                "R_SH_GOT_MEDHI16",     "R_SH_GOT_HI16",
59
        [173] = "R_SH_GOTPLT_LOW16",    "R_SH_GOTPLT_MEDLOW16",
60
                "R_SH_GOTPLT_MEDHI16",  "R_SH_GOTPLT_HI16",
61
        [177] = "R_SH_PLT_LOW16",       "R_SH_PLT_MEDLOW16",
62
                "R_SH_PLT_MEDHI16",     "R_SH_PLT_HI16",
63
        [181] = "R_SH_GOTOFF_LOW16",    "R_SH_GOTOFF_MEDLOW16",
64
                "R_SH_GOTOFF_MEDHI16",  "R_SH_GOTOFF_HI16",
65
        [185] = "R_SH_GOTPC_LOW16",     "R_SH_GOTPC_MEDLOW16",
66
                "R_SH_GOTPC_MEDHI16",   "R_SH_GOTPC_HI16",
67
        [189] = "R_SH_GOT10BY4",        "R_SH_GOTPLT10BY4",
68
                "R_SH_GOT10BY8",        "R_SH_GOTPLT10BY8",
69
        [193] = "R_SH_COPY64",          "R_SH_GLOB_DAT64",
70
                "R_SH_JMP_SLOT64",      "R_SH_RELATIVE64",
71
        [197] = "R_SH_RELATIVE_LOW16",  "R_SH_RELATIVE_MEDLOW16",
72
                "R_SH_RELATIVE_MEDHI16","R_SH_RELATIVE_HI16",
73
        [242] = "R_SH_SHMEDIA_CODE",    "R_SH_PT_16",
74
                "R_SH_IMMS16",          "R_SH_IMMU16",
75
        [246] = "R_SH_IMM_LOW16",       "R_SH_IMM_LOW16_PCREL",
76
                "R_SH_IMM_MEDLOW16",    "R_SH_IMM_MEDLOW16_PCREL",
77
        [250] = "R_SH_IMM_MEDHI16",     "R_SH_IMM_MEDHI16_PCREL",
78
                "R_SH_IMM_HI16",        "R_SH_IMM_HI16_PCREL",
79
        [254] = "R_SH_64",              "R_SH_64_PCREL",
80
};
81
 
82
static const char *_dl_reltypes(int type)
83
{
84
        static char buf[22];
85
        const char *str;
86
        int tabsize;
87
 
88
        tabsize = sizeof(_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0]);
89
        str     = _dl_reltypes_tab[type];
90
 
91
        if (type >= tabsize || str == NULL)
92
                str =_dl_simple_ltoa(buf, (unsigned long)(type));
93
 
94
        return str;
95
}
96
 
97
static void debug_sym(Elf32_Sym *symtab, char *strtab, int symtab_index)
98
{
99
        if (!_dl_debug_symbols || !symtab_index)
100
                return;
101
 
102
        _dl_dprintf(_dl_debug_file,
103
                "\n%s\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",
104
                strtab + symtab[symtab_index].st_name,
105
                symtab[symtab_index].st_value,
106
                symtab[symtab_index].st_size,
107
                symtab[symtab_index].st_info,
108
                symtab[symtab_index].st_other,
109
                symtab[symtab_index].st_shndx);
110
}
111
 
112
static void debug_reloc(Elf32_Sym *symtab, char *strtab, ELF_RELOC *rpnt)
113
{
114
        if (!_dl_debug_reloc)
115
                return;
116
 
117
        if (_dl_debug_symbols) {
118
                _dl_dprintf(_dl_debug_file, "\n\t");
119
        } else {
120
                int symtab_index;
121
                const char *sym;
122
 
123
                symtab_index = ELF32_R_SYM(rpnt->r_info);
124
                sym = symtab_index ? strtab + symtab[symtab_index].st_name
125
                                   : "sym=0x0";
126
 
127
                _dl_dprintf(_dl_debug_file, "\n%s\n\t", sym);
128
        }
129
 
130
        _dl_dprintf(_dl_debug_file, "%s\toffset=%x",
131
                    _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
132
                    rpnt->r_offset);
133
 
134
#ifdef ELF_USES_RELOCA
135
        _dl_dprintf(_dl_debug_file, "\taddend=%x", rpnt->r_addend);
136
#endif
137
 
138
        _dl_dprintf(_dl_debug_file, "\n");
139
 
140
}
141
#endif /* __SUPPORT_LD_DEBUG__ */
142
 
143
/* Program to load an ELF binary on a linux system, and run it.
144
   References to symbols in sharable libraries can be resolved by either
145
   an ELF sharable library or a linux style of shared library. */
146
 
147
/* Disclaimer:  I have never seen any AT&T source code for SVr4, nor have
148
   I ever taken any courses on internals.  This program was developed using
149
   information available through the book "UNIX SYSTEM V RELEASE 4,
150
   Programmers guide: Ansi C and Programming Support Tools", which did
151
   a more than adequate job of explaining everything required to get this
152
   working. */
153
 
154
extern int _dl_linux_resolve(void);
155
 
156
unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
157
{
158
        int reloc_type;
159
        ELF_RELOC *this_reloc;
160
        char *strtab;
161
        Elf32_Sym *symtab;
162
        int symtab_index;
163
        char *rel_addr;
164
        char *new_addr;
165
        char **got_addr;
166
        unsigned long instr_addr;
167
        char *symname;
168
 
169
        rel_addr = (char *)(tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
170
 
171
        this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
172
        reloc_type = ELF32_R_TYPE(this_reloc->r_info);
173
        symtab_index = ELF32_R_SYM(this_reloc->r_info);
174
 
175
        symtab = (Elf32_Sym *)(intptr_t)
176
                (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
177
        strtab = (char *)(tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
178
        symname = strtab + symtab[symtab_index].st_name;
179
 
180
        if (reloc_type != R_SH_JMP_SLOT) {
181
                _dl_dprintf(2, "%s: Incorrect relocation type in jump reloc\n",
182
                            _dl_progname);
183
                _dl_exit(1);
184
        }
185
 
186
        /* Address of jump instruction to fix up */
187
        instr_addr = ((unsigned long)this_reloc->r_offset +
188
                        (unsigned long)tpnt->loadaddr);
189
        got_addr = (char **)instr_addr;
190
 
191
 
192
        /* Get the address of the GOT entry */
193
        new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, resolver);
194
        if (!new_addr) {
195
                new_addr = _dl_find_hash(symname, NULL, NULL, resolver);
196
 
197
                if (new_addr)
198
                        return (unsigned long)new_addr;
199
 
200
                _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
201
                            _dl_progname, symname);
202
                _dl_exit(1);
203
        }
204
 
205
#ifdef __SUPPORT_LD_DEBUG__
206
        if ((unsigned long)got_addr < 0x20000000) {
207
                if (_dl_debug_bindings) {
208
                        _dl_dprintf(_dl_debug_file, "\nresolve function: %s",
209
                                    symname);
210
 
211
                        if (_dl_debug_detail)
212
                                _dl_dprintf(_dl_debug_file,
213
                                            "\n\tpatched %x ==> %x @ %x\n",
214
                                            *got_addr, new_addr, got_addr);
215
                }
216
        }
217
 
218
        if (!_dl_debug_nofixups)
219
                *got_addr = new_addr;
220
#else
221
        *got_addr = new_addr;
222
#endif
223
 
224
        return (unsigned long)new_addr;
225
}
226
 
227
static int _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
228
                     unsigned long rel_addr, unsigned long rel_size,
229
                     int (*reloc_fnc)(struct elf_resolve *tpnt,
230
                                      struct dyn_elf *scope,
231
                                      ELF_RELOC *rpnt, Elf32_Sym *symtab,
232
                                      char *strtab))
233
{
234
        unsigned int i;
235
        char *strtab;
236
        Elf32_Sym *symtab;
237
        ELF_RELOC *rpnt;
238
        int symtab_index;
239
 
240
        /* Now parse the relocation information */
241
        rpnt = (ELF_RELOC *)(intptr_t)(rel_addr + tpnt->loadaddr);
242
        rel_size = rel_size / sizeof(ELF_RELOC);
243
 
244
        symtab = (Elf32_Sym *)(intptr_t)
245
                (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
246
        strtab = (char *)(tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
247
 
248
        for (i = 0; i < rel_size; i++, rpnt++) {
249
                int res;
250
 
251
                symtab_index = ELF32_R_SYM(rpnt->r_info);
252
 
253
                /* When the dynamic linker bootstrapped itself, it resolved
254
                   some symbols. Make sure we do not do them again */
255
                if (!symtab_index && tpnt->libtype == program_interpreter)
256
                        continue;
257
                if (symtab_index && tpnt->libtype == program_interpreter &&
258
                    _dl_symbol(strtab + symtab[symtab_index].st_name))
259
                        continue;
260
 
261
#ifdef __SUPPORT_LD_DEBUG__
262
                debug_sym(symtab,strtab,symtab_index);
263
                debug_reloc(symtab,strtab,rpnt);
264
#endif
265
 
266
                res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
267
                if (res == 0)
268
                        continue;
269
 
270
                _dl_dprintf(2, "\n%s: ",_dl_progname);
271
 
272
                if (symtab_index)
273
                        _dl_dprintf(2, "symbol '%s': ",
274
                                strtab + symtab[symtab_index].st_name);
275
 
276
                if (res < 0) {
277
                        int reloc_type = ELF32_R_TYPE(rpnt->r_info);
278
 
279
                        _dl_dprintf(2, "can't handle reloc type "
280
#ifdef __SUPPORT_LD_DEBUG__
281
                                        "%s\n", _dl_reltypes(reloc_type)
282
#else
283
                                        "%x\n", reloc_type
284
#endif                  
285
                        );
286
 
287
                        _dl_exit(-res);
288
                } else if (res > 0) {
289
                        _dl_dprintf(2, "can't resolve symbol\n");
290
 
291
                        return res;
292
                }
293
        }
294
 
295
        return 0;
296
}
297
 
298
static int _dl_do_reloc(struct elf_resolve *tpnt,struct dyn_elf *scope,
299
                        ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
300
{
301
        int reloc_type;
302
        int symtab_index, lsb;
303
        char *symname;
304
        unsigned long *reloc_addr;
305
        unsigned long symbol_addr;
306
#ifdef __SUPPORT_LD_DEBUG__
307
        unsigned long old_val;
308
#endif
309
 
310
        reloc_type   = ELF32_R_TYPE(rpnt->r_info);
311
        symtab_index = ELF32_R_SYM(rpnt->r_info);
312
        symbol_addr  = 0;
313
        lsb          = symtab[symtab_index].st_other & 4;
314
        symname      = strtab + symtab[symtab_index].st_name;
315
        reloc_addr   = (unsigned long *)(intptr_t)
316
                (tpnt->loadaddr + (unsigned long)rpnt->r_offset);
317
 
318
        if (symtab_index) {
319
                int stb;
320
 
321
                symbol_addr = (unsigned long)_dl_find_hash(symname, scope,
322
                                (reloc_type == R_SH_JMP_SLOT ? tpnt : NULL),
323
                                 symbolrel);
324
 
325
                /*
326
                 * We want to allow undefined references to weak symbols - this
327
                 * might have been intentional. We should not be linking local
328
                 * symbols here, so all bases should be covered.
329
                 */
330
                stb = ELF32_ST_BIND(symtab[symtab_index].st_info);
331
 
332
                if (stb == STB_GLOBAL && !symbol_addr) {
333
#ifdef __SUPPORT_LD_DEBUG__
334
                        _dl_dprintf(2, "\tglobal symbol '%s' "
335
                                    "already defined in '%s'\n",
336
                                    symname, tpnt->libname);
337
#endif
338
                        return 0;
339
                }
340
        }
341
 
342
#ifdef __SUPPORT_LD_DEBUG__
343
        old_val = *reloc_addr;
344
#endif
345
 
346
        switch (reloc_type) {
347
        case R_SH_NONE:
348
                break;
349
        case R_SH_COPY:
350
                /* handled later on */
351
                break;
352
        case R_SH_DIR32:
353
        case R_SH_GLOB_DAT:
354
        case R_SH_JMP_SLOT:
355
                *reloc_addr = (symbol_addr + rpnt->r_addend) | lsb;
356
                break;
357
        case R_SH_REL32:
358
                *reloc_addr = symbol_addr + rpnt->r_addend -
359
                        (unsigned long)reloc_addr;
360
                break;
361
        case R_SH_RELATIVE:
362
                *reloc_addr = (unsigned long)tpnt->loadaddr + rpnt->r_addend;
363
                break;
364
        case R_SH_RELATIVE_LOW16:
365
        case R_SH_RELATIVE_MEDLOW16:
366
            {
367
                unsigned long word, value;
368
 
369
                word = (unsigned long)reloc_addr & ~0x3fffc00;
370
                value = (unsigned long)tpnt->loadaddr + rpnt->r_addend;
371
 
372
                if (reloc_type == R_SH_RELATIVE_MEDLOW16)
373
                        value >>= 16;
374
 
375
                word |= (value & 0xffff) << 10;
376
                *reloc_addr = word;
377
 
378
                break;
379
            }
380
        case R_SH_IMM_LOW16:
381
        case R_SH_IMM_MEDLOW16:
382
            {
383
                unsigned long word, value;
384
 
385
                word = (unsigned long)reloc_addr & ~0x3fffc00;
386
                value = (symbol_addr + rpnt->r_addend) | lsb;
387
 
388
                if (reloc_type == R_SH_IMM_MEDLOW16)
389
                        value >>= 16;
390
 
391
                word |= (value & 0xffff) << 10;
392
                *reloc_addr = word;
393
 
394
                break;
395
            }
396
        case R_SH_IMM_LOW16_PCREL:
397
        case R_SH_IMM_MEDLOW16_PCREL:
398
            {
399
                unsigned long word, value;
400
 
401
                word = (unsigned long)reloc_addr & ~0x3fffc00;
402
                value = symbol_addr + rpnt->r_addend -
403
                        (unsigned long)reloc_addr;
404
 
405
                if (reloc_type == R_SH_IMM_MEDLOW16_PCREL)
406
                        value >>= 16;
407
 
408
                word |= (value & 0xffff) << 10;
409
                *reloc_addr = word;
410
 
411
                break;
412
            }
413
        default:
414
                return -1; /*call _dl_exit(1) */
415
        }
416
 
417
#ifdef __SUPPORT_LD_DEBUG__
418
        if (_dl_debug_reloc && _dl_debug_detail)
419
                _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x",
420
                            old_val, *reloc_addr, reloc_addr);
421
#endif
422
 
423
        return 0;
424
}
425
 
426
static int _dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
427
                             ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
428
{
429
        int reloc_type, symtab_index, lsb;
430
        unsigned long *reloc_addr;
431
#ifdef __SUPPORT_LD_DEBUG__
432
        unsigned long old_val;
433
#endif
434
 
435
        reloc_type   = ELF32_R_TYPE(rpnt->r_info);
436
        symtab_index = ELF32_R_SYM(rpnt->r_info);
437
        lsb          = symtab[symtab_index].st_other & 4;
438
        reloc_addr   = (unsigned long *)(intptr_t)
439
                (tpnt->loadaddr + (unsigned long)rpnt->r_offset);
440
 
441
#ifdef __SUPPORT_LD_DEBUG__
442
        old_val = *reloc_addr;
443
#endif
444
 
445
        switch (reloc_type) {
446
        case R_SH_NONE:
447
                break;
448
        case R_SH_JMP_SLOT:
449
                *reloc_addr += (unsigned long)tpnt->loadaddr | lsb;
450
                break;
451
        default:
452
                return -1; /*call _dl_exit(1) */
453
        }
454
 
455
#ifdef __SUPPORT_LD_DEBUG__
456
        if (_dl_debug_reloc && _dl_debug_detail)
457
                _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x",
458
                            old_val, *reloc_addr, reloc_addr);
459
#endif
460
 
461
        return 0;
462
}
463
 
464
/* This is done as a separate step, because there are cases where
465
   information is first copied and later initialized.  This results in
466
   the wrong information being copied.  Someone at Sun was complaining about
467
   a bug in the handling of _COPY by SVr4, and this may in fact be what he
468
   was talking about.  Sigh. */
469
 
470
/* No, there are cases where the SVr4 linker fails to emit COPY relocs
471
   at all */
472
static int _dl_do_copy(struct elf_resolve *tpnt, struct dyn_elf *scope,
473
                       ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
474
{
475
        int reloc_type;
476
        int symtab_index;
477
        unsigned long *reloc_addr;
478
        unsigned long symbol_addr;
479
        char *symname;
480
        int goof = 0;
481
 
482
        reloc_addr = (unsigned long *)(intptr_t)
483
                (tpnt->loadaddr + (unsigned long)rpnt->r_offset);
484
        reloc_type = ELF32_R_TYPE(rpnt->r_info);
485
 
486
        if (reloc_type != R_SH_COPY)
487
                return 0;
488
 
489
        symtab_index = ELF32_R_SYM(rpnt->r_info);
490
        symbol_addr  = 0;
491
        symname      = strtab + symtab[symtab_index].st_name;
492
 
493
        if (symtab_index) {
494
                symbol_addr = (unsigned long)
495
                        _dl_find_hash(symname, scope, NULL, copyrel);
496
 
497
                if (!symbol_addr)
498
                        goof++;
499
        }
500
 
501
        if (!goof) {
502
#ifdef __SUPPORT_LD_DEBUG__
503
                if (_dl_debug_move)
504
                        _dl_dprintf(_dl_debug_file,
505
                                    "\n%s move %x bytes from %x to %x",
506
                                    symname, symtab[symtab_index].st_size,
507
                                    symbol_addr, symtab[symtab_index].st_value);
508
#endif
509
 
510
                _dl_memcpy((char *)symtab[symtab_index].st_value,
511
                           (char *)symbol_addr, symtab[symtab_index].st_size);
512
        }
513
 
514
        return goof;
515
}
516
 
517
void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
518
                unsigned long rel_addr, unsigned long rel_size, int type)
519
{
520
        _dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
521
}
522
 
523
int _dl_parse_relocation_information(struct elf_resolve *tpnt,
524
                unsigned long rel_addr, unsigned long rel_size, int type)
525
{
526
        return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr,
527
                         rel_size, _dl_do_reloc);
528
}
529
 
530
int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
531
    unsigned long rel_size, int type)
532
{
533
        return _dl_parse(xpnt->dyn, xpnt->next, rel_addr,
534
                         rel_size, _dl_do_copy);
535
}
536
 

powered by: WebSVN 2.1.0

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