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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [uClibc/] [ldso/] [ldso/] [cris/] [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
/*
2
 * CRIS ELF shared library loader support.
3
 *
4
 * Program to load an elf binary on a linux system, and run it.
5
 * References to symbols in sharable libraries can be resolved
6
 * by either an ELF sharable library or a linux style of shared
7
 * library.
8
 *
9
 * Copyright (C) 2002, Axis Communications AB
10
 * All rights reserved
11
 *
12
 * Author: Tobias Anderberg, <tobiasa@axis.com>
13
 *
14
 * Redistribution and use in source and binary forms, with or without
15
 * modification, are permitted provided that the following conditions
16
 * are met:
17
 * 1. Redistributions of source code must retain the above copyright
18
 *    notice, this list of conditions and the following disclaimer.
19
 * 2. The name of the above contributors may not be
20
 *    used to endorse or promote products derived from this software
21
 *    without specific prior written permission.
22
 *
23
 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
24
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
27
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33
 * SUCH DAMAGE.
34
 */
35
 
36
/* Support for the LD_DEBUG variable. */
37
#if defined (__SUPPORT_LD_DEBUG__)
38
static const char *_dl_reltypes_tab[] = {
39
        [0]              "R_CRIS_NONE", "R_CRIS_8", "R_CRIS_16", "R_CRIS_32",
40
        [4]             "R_CRIS_8_PCREL", "R_CRIS_16_PCREL", "R_CRIS_32_PCREL", "R_CRIS_GNU_VTINHERIT",
41
        [8]             "R_CRIS_GNU_VTENTRY", "R_CRIS_COPY", "R_CRIS_GLOB_DAT", "R_CRIS_JUMP_SLOT",
42
        [16]    "R_CRIS_RELATIVE", "R_CRIS_16_GOT", "R_CRIS_32_GOT", "R_CRIS_16_GOTPLT",
43
        [32]    "R_CRIS_32_GOTPLT", "R_CRIS_32_GOTREL", "R_CRIS_32_PLT_GOTREL", "R_CRIS_32_PLT_PCREL",
44
 
45
};
46
 
47
 
48
static const char *
49
_dl_reltypes(int type)
50
{
51
        const char *str;
52
        static char buf[22];
53
 
54
        if (type >= (sizeof(_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) ||
55
                NULL == (str = _dl_reltypes_tab[type]))
56
                str = _dl_simple_ltoa(buf, (unsigned long) (type));
57
 
58
        return str;
59
}
60
 
61
static void
62
debug_sym(Elf32_Sym *symtab, char *strtab, int symtab_index)
63
{
64
        if (_dl_debug_symbols) {
65
                if (symtab_index) {
66
                        _dl_dprintf(_dl_debug_file,
67
                                "\n%s\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",
68
                                strtab + symtab[symtab_index].st_name,
69
                                symtab[symtab_index].st_value,
70
                                symtab[symtab_index].st_size,
71
                                symtab[symtab_index].st_info,
72
                                symtab[symtab_index].st_other,
73
                                symtab[symtab_index].st_shndx);
74
                }
75
        }
76
}
77
 
78
static void
79
debug_reloc(Elf32_Sym *symtab, char *strtab, ELF_RELOC *rpnt)
80
{
81
        if (_dl_debug_reloc) {
82
                int symtab_index;
83
                const char *sym;
84
 
85
                symtab_index = ELF32_R_SYM(rpnt->r_info);
86
                sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0";
87
 
88
                if (_dl_debug_symbols)
89
                        _dl_dprintf(_dl_debug_file, "\n\t");
90
                else
91
                        _dl_dprintf(_dl_debug_file, "\n%s\n\t", sym);
92
 
93
#ifdef ELF_USES_RELOCA
94
                _dl_dprintf(_dl_debug_file, "%s\toffset=%x\taddend=%x",
95
                        _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
96
                        rpnt->r_offset,
97
                        rpnt->r_addend);
98
#else
99
                _dl_dprintf(_dl_debug_file, "%s\toffset%x\n",
100
                        _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
101
                        rpnt->r_offset);
102
#endif
103
        }
104
}
105
#endif /* __SUPPORT_LD_DEBUG__ */
106
 
107
/* Defined in resolve.S. */
108
extern int _dl_linux_resolv(void);
109
 
110
unsigned long
111
_dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
112
{
113
        int reloc_type;
114
        int symtab_index;
115
        char *strtab;
116
        char *symname;
117
        char *new_addr;
118
        char *rel_addr;
119
        char **got_addr;
120
        Elf32_Sym *symtab;
121
        ELF_RELOC *this_reloc;
122
        unsigned long instr_addr;
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_CRIS_JUMP_SLOT) {
135
                _dl_dprintf(2, "%s: Incorrect relocation type for jump relocations.\n",
136
                        _dl_progname);
137
                _dl_exit(1);
138
        }
139
 
140
        /* Fetch the address of the jump instruction to fix up. */
141
        instr_addr = ((unsigned long) this_reloc->r_offset + (unsigned long) tpnt->loadaddr);
142
        got_addr = (char **) instr_addr;
143
 
144
        /* Fetch the address of the GOT entry. */
145
        new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, resolver);
146
 
147
        if (!new_addr) {
148
                new_addr = _dl_find_hash(symname, NULL, NULL, resolver);
149
 
150
                if (new_addr)
151
                        return (unsigned long) new_addr;
152
 
153
                _dl_dprintf(2, "%s: Can't resolv symbol '%s'\n", _dl_progname, symname);
154
                _dl_exit(1);
155
        }
156
 
157
#if defined (__SUPPORT_LD_DEBUG__)
158
        if (_dl_debug_bindings) {
159
                _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
160
 
161
                if (_dl_debug_detail)
162
                        _dl_dprintf(_dl_debug_file, "\tpatch %x ==> %x @ %x", *got_addr, new_addr, got_addr);
163
        }
164
#endif
165
 
166
        *got_addr = new_addr;
167
        return (unsigned long) new_addr;
168
}
169
 
170
static int
171
_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, unsigned long rel_addr,
172
        unsigned long rel_size, int (*reloc_fnc)(struct elf_resolve *tpnt, struct dyn_elf *scope,
173
                                    ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
174
{
175
        int symtab_index;
176
        int res;
177
        unsigned int i;
178
        char *strtab;
179
        Elf32_Sym *symtab;
180
        ELF_RELOC *rpnt;
181
 
182
        /* Parse the relocation information. */
183
        rpnt = (ELF_RELOC *) (intptr_t) (rel_addr + tpnt->loadaddr);
184
        rel_size /= sizeof(ELF_RELOC);
185
 
186
        symtab = (Elf32_Sym *) (intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
187
        strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
188
 
189
        for (i = 0; i < rel_size; i++, rpnt++) {
190
                symtab_index = ELF32_R_SYM(rpnt->r_info);
191
 
192
                /*
193
                 * Make sure the same symbols that the linker resolved when it
194
                 * bootstapped itself isn't resolved again.
195
                 */
196
                if (!symtab_index && tpnt->libtype == program_interpreter)
197
                        continue;
198
 
199
                if (symtab_index && tpnt->libtype == program_interpreter &&
200
                        _dl_symbol(strtab + symtab[symtab_index].st_name))
201
                        continue;
202
 
203
#if defined (__SUPPORT_LD_DEBUG__)
204
                debug_sym(symtab, strtab, symtab_index);
205
                debug_reloc(symtab, strtab, rpnt);
206
#endif
207
 
208
                /* Pass over to actual relocation function. */
209
                res = reloc_fnc(tpnt, scope, rpnt, symtab, strtab);
210
 
211
                if (res == 0)
212
                        continue;
213
 
214
                _dl_dprintf(2, "\n%s: ", _dl_progname);
215
 
216
                if (symtab_index)
217
                        _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
218
 
219
                if (res < 0) {
220
                        int reloc_type = ELF32_R_TYPE(rpnt->r_info);
221
 
222
#if defined (__SUPPORT_LD_DEBUG__)
223
                        _dl_dprintf(2, "can't handle relocation type '%s'\n", _dl_reltypes(reloc_type));
224
#else
225
                        _dl_dprintf(2, "can't handle relocation type %x\n", reloc_type);
226
#endif
227
                        _dl_exit(-res);
228
                }
229
                else if (res > 0) {
230
                        _dl_dprintf(2, "can't resolv symbol\n");
231
                        return res;
232
                }
233
        }
234
 
235
        return 0;
236
}
237
 
238
static int
239
_dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, ELF_RELOC *rpnt,
240
        Elf32_Sym *symtab, char *strtab)
241
{
242
        int reloc_type;
243
        int symtab_index;
244
        char *symname;
245
        unsigned long *reloc_addr;
246
        unsigned symbol_addr;
247
#if defined (__SUPPORT_LD_DEBUG__)
248
        unsigned long old_val;
249
#endif
250
 
251
        reloc_addr = (unsigned long *)(intptr_t)(tpnt->loadaddr + (unsigned long) rpnt->r_offset);
252
        reloc_type = ELF32_R_TYPE(rpnt->r_info);
253
        symtab_index = ELF32_R_SYM(rpnt->r_info);
254
        symbol_addr = 0;
255
        symname = strtab + symtab[symtab_index].st_name;
256
 
257
        if (symtab_index) {
258
                if (symtab[symtab_index].st_shndx != SHN_UNDEF &&
259
                        ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_LOCAL) {
260
                        symbol_addr = (unsigned long) tpnt->loadaddr;
261
                }
262
                else {
263
                        symbol_addr = (unsigned long) _dl_find_hash(symname, scope,
264
                                (reloc_type == R_CRIS_JUMP_SLOT ? tpnt : NULL), symbolrel);
265
                }
266
 
267
                if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
268
#if defined (__SUPPORT_LD_DEBUG__)
269
                        _dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s'\n",
270
                                symname, tpnt->libname);
271
#endif
272
                        return 0;
273
                }
274
 
275
                symbol_addr += rpnt->r_addend;
276
        }
277
 
278
#if defined (__SUPPORT_LD_DEBUG__)
279
        old_val = *reloc_addr;
280
#endif
281
 
282
        switch (reloc_type) {
283
                case R_CRIS_NONE:
284
                        break;
285
                case R_CRIS_GLOB_DAT:
286
                case R_CRIS_JUMP_SLOT:
287
                case R_CRIS_32:
288
                case R_CRIS_COPY:
289
                        *reloc_addr = symbol_addr;
290
                        break;
291
                case R_CRIS_RELATIVE:
292
                        *reloc_addr = (unsigned long) tpnt->loadaddr + rpnt->r_addend;
293
                        break;
294
                default:
295
                        return -1;      /* Call _dl_exit(1). */
296
        }
297
 
298
#if defined (__SUPPORT_LD_DEBUG__)
299
        if (_dl_debug_reloc && _dl_debug_detail)
300
                _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
301
#endif
302
 
303
        return 0;
304
}
305
 
306
static int
307
_dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, ELF_RELOC *rpnt,
308
        Elf32_Sym *symtab, char *strtab)
309
{
310
        int reloc_type;
311
        unsigned long *reloc_addr;
312
#if defined (__SUPPORT_LD_DEBUG__)
313
        unsigned long old_val;
314
#endif
315
 
316
        /* Don't care about these, just keep the compiler happy. */
317
        (void) scope;
318
        (void) symtab;
319
        (void) strtab;
320
 
321
        reloc_addr = (unsigned long *)(intptr_t)(tpnt->loadaddr + (unsigned long) rpnt->r_offset);
322
        reloc_type = ELF32_R_TYPE(rpnt->r_info);
323
 
324
#if defined (__SUPPORT_LD_DEBUG__)
325
        old_val = *reloc_addr;
326
#endif
327
 
328
        switch (reloc_type) {
329
                case R_CRIS_NONE:
330
                        break;
331
                case R_CRIS_JUMP_SLOT:
332
                        *reloc_addr += (unsigned long) tpnt->loadaddr;
333
                        break;
334
                default:
335
                        return -1;      /* Calls _dl_exit(1). */
336
        }
337
 
338
#if defined (__SUPPORT_LD_DEBUG__)
339
        if (_dl_debug_reloc && _dl_debug_detail)
340
                _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
341
#endif
342
 
343
        return 0;
344
}
345
 
346
static int
347
_dl_do_copy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, ELF_RELOC *rpnt,
348
        Elf32_Sym *symtab, char *strtab)
349
{
350
        int goof;
351
        int reloc_type;
352
        int symtab_index;
353
        char *symname;
354
        unsigned long *reloc_addr;
355
        unsigned long symbol_addr;
356
 
357
        reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
358
        reloc_type = ELF32_R_TYPE(rpnt->r_info);
359
 
360
        if (reloc_type != R_CRIS_COPY)
361
                return 0;
362
 
363
        symtab_index = ELF32_R_SYM(rpnt->r_info);
364
        symbol_addr = 0;
365
        symname = strtab + symtab[symtab_index].st_name;
366
        goof = 0;
367
 
368
        if (symtab_index) {
369
                symbol_addr = (unsigned long) _dl_find_hash(symname, scope, NULL, copyrel);
370
 
371
                if (!symbol_addr)
372
                        goof++;
373
        }
374
 
375
        if (!goof) {
376
#if defined (__SUPPORT_LD_DEBUG__)
377
                if (_dl_debug_move)
378
                        _dl_dprintf(_dl_debug_file, "\n%s move %x bytes from %x to %x",
379
                                symname, symtab[symtab_index].st_size, symbol_addr, symtab[symtab_index].st_value);
380
#endif
381
                        _dl_memcpy((char *) symtab[symtab_index].st_value,
382
                                (char *) symbol_addr, symtab[symtab_index].st_size);
383
        }
384
 
385
        return goof;
386
}
387
 
388
/* External interface to the generic part of the dynamic linker. */
389
 
390
int
391
_dl_parse_relocation_information(struct elf_resolve *tpnt, unsigned long rel_addr,
392
        unsigned long rel_size, int type)
393
{
394
        /* Keep the compiler happy. */
395
        (void) type;
396
        return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
397
}
398
void
399
_dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, unsigned long rel_addr,
400
        unsigned long rel_size, int type)
401
{
402
        /* Keep the compiler happy. */
403
        (void) type;
404
        _dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
405
}
406
 
407
int
408
_dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
409
        unsigned long rel_size, int type)
410
{
411
        /* Keep the compiler happy. */
412
        (void) type;
413
        return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy_reloc);
414
}

powered by: WebSVN 2.1.0

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