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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [uClibc/] [ldso/] [ldso/] [arm/] [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
/* ARM ELF shared library loader suppport
3
 *
4
 * Copyright (C) 2001-2002, Erik Andersen
5
 *
6
 * All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. The name of the above contributors may not be
14
 *    used to endorse or promote products derived from this software
15
 *    without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29
 
30
#if defined (__SUPPORT_LD_DEBUG__)
31
static const char *_dl_reltypes_tab[] =
32
{
33
  [0]    "R_ARM_NONE",       "R_ARM_PC24",       "R_ARM_ABS32",          "R_ARM_REL32",
34
  [4]   "R_ARM_PC13",       "R_ARM_ABS16",      "R_ARM_ABS12",          "R_ARM_THM_ABS5",
35
  [8]   "R_ARM_ABS8",           "R_ARM_SBREL32","R_ARM_THM_PC22",       "R_ARM_THM_PC8",
36
  [12]  "R_ARM_AMP_VCALL9",     "R_ARM_SWI24",  "R_ARM_THM_SWI8",       "R_ARM_XPC25",
37
  [16]  "R_ARM_THM_XPC22",
38
  [20]  "R_ARM_COPY",           "R_ARM_GLOB_DAT","R_ARM_JUMP_SLOT",     "R_ARM_RELATIVE",
39
  [24]  "R_ARM_GOTOFF",         "R_ARM_GOTPC",   "R_ARM_GOT32",         "R_ARM_PLT32",
40
  [32]  "R_ARM_ALU_PCREL_7_0","R_ARM_ALU_PCREL_15_8","R_ARM_ALU_PCREL_23_15","R_ARM_LDR_SBREL_11_0",
41
  [36]  "R_ARM_ALU_SBREL_19_12","R_ARM_ALU_SBREL_27_20",
42
  [100] "R_ARM_GNU_VTENTRY","R_ARM_GNU_VTINHERIT","R_ARM_THM_PC11","R_ARM_THM_PC9",
43
  [249] "R_ARM_RXPC25", "R_ARM_RSBREL32", "R_ARM_THM_RPC22", "R_ARM_RREL32",
44
  [253] "R_ARM_RABS22", "R_ARM_RPC24", "R_ARM_RBASE",
45
};
46
 
47
static const char *
48
_dl_reltypes(int type)
49
{
50
  static char buf[22];
51
  const char *str;
52
 
53
  if (type >= (sizeof (_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) ||
54
      NULL == (str = _dl_reltypes_tab[type]))
55
  {
56
    str =_dl_simple_ltoa( buf, (unsigned long)(type));
57
  }
58
  return str;
59
}
60
 
61
static
62
void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
63
{
64
  if(_dl_debug_symbols)
65
  {
66
    if(symtab_index){
67
      _dl_dprintf(_dl_debug_file, "\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 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
#ifdef ELF_USES_RELOCA
88
    _dl_dprintf(_dl_debug_file, "\n%s\toffset=%x\taddend=%x %s",
89
                _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
90
                rpnt->r_offset,
91
                rpnt->r_addend,
92
                sym);
93
#else
94
    _dl_dprintf(_dl_debug_file, "\n%s\toffset=%x %s",
95
                _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
96
                rpnt->r_offset,
97
                sym);
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
        ELF_RELOC *rel_addr;
123
        int symtab_index;
124
        char *new_addr;
125
        char **got_addr;
126
        unsigned long instr_addr;
127
 
128
        rel_addr = (ELF_RELOC *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
129
 
130
        this_reloc = rel_addr + (reloc_entry >> 3);
131
        reloc_type = ELF32_R_TYPE(this_reloc->r_info);
132
        symtab_index = ELF32_R_SYM(this_reloc->r_info);
133
 
134
        symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
135
        strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
136
 
137
 
138
        if (reloc_type != R_ARM_JUMP_SLOT) {
139
                _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n",
140
                        _dl_progname);
141
                _dl_exit(1);
142
        };
143
 
144
        /* Address of jump instruction to fix up */
145
        instr_addr = ((unsigned long) this_reloc->r_offset +
146
                (unsigned long) tpnt->loadaddr);
147
        got_addr = (char **) instr_addr;
148
 
149
        /* Get the address of the GOT entry */
150
        new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name,
151
                tpnt->symbol_scope, tpnt, resolver);
152
        if (!new_addr) {
153
                _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
154
                        _dl_progname, strtab + symtab[symtab_index].st_name);
155
                _dl_exit(1);
156
        };
157
#if defined (__SUPPORT_LD_DEBUG__)
158
        if ((unsigned long) got_addr < 0x40000000)
159
        {
160
                if (_dl_debug_bindings)
161
                {
162
                        _dl_dprintf(_dl_debug_file, "\nresolve function: %s",
163
                                        strtab + symtab[symtab_index].st_name);
164
                        if(_dl_debug_detail) _dl_dprintf(_dl_debug_file,
165
                                        "\tpatch %x ==> %x @ %x", *got_addr, new_addr, got_addr);
166
                }
167
        }
168
        if (!_dl_debug_nofixups) {
169
                *got_addr = new_addr;
170
        }
171
#else
172
        *got_addr = new_addr;
173
#endif
174
 
175
        return (unsigned long) new_addr;
176
}
177
 
178
static int
179
_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
180
          unsigned long rel_addr, unsigned long rel_size,
181
          int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
182
                            ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
183
{
184
        int i;
185
        char *strtab;
186
        int goof = 0;
187
        Elf32_Sym *symtab;
188
        ELF_RELOC *rpnt;
189
        int symtab_index;
190
        /* Now parse the relocation information */
191
 
192
        rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
193
        rel_size = rel_size / sizeof(ELF_RELOC);
194
 
195
        symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
196
        strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
197
 
198
          for (i = 0; i < rel_size; i++, rpnt++) {
199
                int res;
200
 
201
                symtab_index = ELF32_R_SYM(rpnt->r_info);
202
 
203
                /* When the dynamic linker bootstrapped itself, it resolved some symbols.
204
                   Make sure we do not do them again */
205
                if (!symtab_index && tpnt->libtype == program_interpreter)
206
                        continue;
207
                if (symtab_index && tpnt->libtype == program_interpreter &&
208
                    _dl_symbol(strtab + symtab[symtab_index].st_name))
209
                        continue;
210
 
211
#if defined (__SUPPORT_LD_DEBUG__)
212
                debug_sym(symtab,strtab,symtab_index);
213
                debug_reloc(symtab,strtab,rpnt);
214
#endif
215
 
216
                res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
217
 
218
                if (res==0) continue;
219
 
220
                _dl_dprintf(2, "\n%s: ",_dl_progname);
221
 
222
                if (symtab_index)
223
                  _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
224
 
225
                if (res <0)
226
                {
227
                        int reloc_type = ELF32_R_TYPE(rpnt->r_info);
228
#if defined (__SUPPORT_LD_DEBUG__)
229
                        _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
230
#else
231
                        _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
232
#endif                  
233
                        _dl_exit(-res);
234
                }
235
                else if (res >0)
236
                {
237
                        _dl_dprintf(2, "can't resolve symbol\n");
238
                        goof += res;
239
                }
240
          }
241
          return goof;
242
}
243
 
244
static unsigned long
245
fix_bad_pc24 (unsigned long *const reloc_addr, unsigned long value)
246
{
247
  static void *fix_page;
248
  static unsigned int fix_offset;
249
  unsigned int *fix_address;
250
  if (! fix_page)
251
    {
252
      fix_page = _dl_mmap (NULL,  PAGE_SIZE   , PROT_READ | PROT_WRITE | PROT_EXEC,
253
                       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
254
      fix_offset = 0;
255
    }
256
 
257
  fix_address = (unsigned int *)(fix_page + fix_offset);
258
  fix_address[0] = 0xe51ff004;  /* ldr pc, [pc, #-4] */
259
  fix_address[1] = value;
260
 
261
  fix_offset += 8;
262
  if (fix_offset >= PAGE_SIZE)
263
    fix_page = NULL;
264
 
265
  return (unsigned long)fix_address;
266
}
267
 
268
static int
269
_dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
270
              ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
271
{
272
        int reloc_type;
273
        int symtab_index;
274
        unsigned long *reloc_addr;
275
        unsigned long symbol_addr;
276
        int goof = 0;
277
 
278
        reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
279
        reloc_type = ELF32_R_TYPE(rpnt->r_info);
280
        symtab_index = ELF32_R_SYM(rpnt->r_info);
281
        symbol_addr = 0;
282
 
283
        if (symtab_index) {
284
 
285
                symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name,
286
                                scope, (reloc_type == R_ARM_JUMP_SLOT ? tpnt : NULL), symbolrel);
287
 
288
                /*
289
                 * We want to allow undefined references to weak symbols - this might
290
                 * have been intentional.  We should not be linking local symbols
291
                 * here, so all bases should be covered.
292
                 */
293
                if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
294
                        goof++;
295
                }
296
        }
297
 
298
#if defined (__SUPPORT_LD_DEBUG__)
299
        {
300
                unsigned long old_val = *reloc_addr;
301
#endif
302
                switch (reloc_type) {
303
                        case R_ARM_NONE:
304
                                break;
305
                        case R_ARM_ABS32:
306
                                *reloc_addr += symbol_addr;
307
                                break;
308
                        case R_ARM_PC24:
309
                                {
310
                                        unsigned long addend;
311
                                        long newvalue, topbits;
312
 
313
                                        addend = *reloc_addr & 0x00ffffff;
314
                                        if (addend & 0x00800000) addend |= 0xff000000;
315
 
316
                                        newvalue = symbol_addr - (unsigned long)reloc_addr + (addend << 2);
317
                                        topbits = newvalue & 0xfe000000;
318
                                        if (topbits != 0xfe000000 && topbits != 0x00000000)
319
                                        {
320
                                                newvalue = fix_bad_pc24(reloc_addr, symbol_addr)
321
                                                        - (unsigned long)reloc_addr + (addend << 2);
322
                                                topbits = newvalue & 0xfe000000;
323
                                                if (topbits != 0xfe000000 && topbits != 0x00000000)
324
                                                {
325
                                                        _dl_dprintf(2,"symbol '%s': R_ARM_PC24 relocation out of range.",
326
                                                                symtab[symtab_index].st_name);
327
                                                        _dl_exit(1);
328
                                                }
329
                                        }
330
                                        newvalue >>= 2;
331
                                        symbol_addr = (*reloc_addr & 0xff000000) | (newvalue & 0x00ffffff);
332
                                        *reloc_addr = symbol_addr;
333
                                        break;
334
                                }
335
                        case R_ARM_GLOB_DAT:
336
                        case R_ARM_JUMP_SLOT:
337
                                *reloc_addr = symbol_addr;
338
                                break;
339
                        case R_ARM_RELATIVE:
340
                                *reloc_addr += (unsigned long) tpnt->loadaddr;
341
                                break;
342
                        case R_ARM_COPY:
343
#if 0                                                   
344
                                /* Do this later */
345
                                _dl_dprintf(2, "Doing copy for symbol ");
346
                                if (symtab_index) _dl_dprintf(2, strtab + symtab[symtab_index].st_name);
347
                                _dl_dprintf(2, "\n");
348
                                _dl_memcpy((void *) symtab[symtab_index].st_value,
349
                                                (void *) symbol_addr, symtab[symtab_index].st_size);
350
#endif
351
                                break;
352
                        default:
353
                                return -1; /*call _dl_exit(1) */
354
                }
355
#if defined (__SUPPORT_LD_DEBUG__)
356
                if(_dl_debug_reloc && _dl_debug_detail)
357
                        _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
358
        }
359
 
360
#endif
361
 
362
        return goof;
363
}
364
 
365
static int
366
_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
367
                   ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
368
{
369
        int reloc_type;
370
        unsigned long *reloc_addr;
371
 
372
        reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
373
        reloc_type = ELF32_R_TYPE(rpnt->r_info);
374
 
375
#if defined (__SUPPORT_LD_DEBUG__)
376
        {
377
                unsigned long old_val = *reloc_addr;
378
#endif
379
                switch (reloc_type) {
380
                        case R_ARM_NONE:
381
                                break;
382
                        case R_ARM_JUMP_SLOT:
383
                                *reloc_addr += (unsigned long) tpnt->loadaddr;
384
                                break;
385
                        default:
386
                                return -1; /*call _dl_exit(1) */
387
                }
388
#if defined (__SUPPORT_LD_DEBUG__)
389
                if(_dl_debug_reloc && _dl_debug_detail)
390
                        _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
391
        }
392
 
393
#endif
394
        return 0;
395
 
396
}
397
 
398
/* This is done as a separate step, because there are cases where
399
   information is first copied and later initialized.  This results in
400
   the wrong information being copied.  Someone at Sun was complaining about
401
   a bug in the handling of _COPY by SVr4, and this may in fact be what he
402
   was talking about.  Sigh. */
403
 
404
/* No, there are cases where the SVr4 linker fails to emit COPY relocs
405
   at all */
406
static int
407
_dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope,
408
             ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
409
{
410
        int reloc_type;
411
        int symtab_index;
412
        unsigned long *reloc_addr;
413
        unsigned long symbol_addr;
414
        int goof = 0;
415
 
416
        reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
417
        reloc_type = ELF32_R_TYPE(rpnt->r_info);
418
        if (reloc_type != R_ARM_COPY)
419
                return 0;
420
        symtab_index = ELF32_R_SYM(rpnt->r_info);
421
        symbol_addr = 0;
422
 
423
        if (symtab_index) {
424
 
425
                symbol_addr = (unsigned long) _dl_find_hash(strtab +
426
                        symtab[symtab_index].st_name, scope,
427
                        NULL, copyrel);
428
                if (!symbol_addr) goof++;
429
        }
430
        if (!goof) {
431
#if defined (__SUPPORT_LD_DEBUG__)
432
                if(_dl_debug_move)
433
                  _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
434
                             strtab + symtab[symtab_index].st_name,
435
                             symtab[symtab_index].st_size,
436
                             symbol_addr, symtab[symtab_index].st_value);
437
#endif
438
                _dl_memcpy((char *) symtab[symtab_index].st_value,
439
                        (char *) symbol_addr, symtab[symtab_index].st_size);
440
        }
441
 
442
        return goof;
443
}
444
 
445
void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
446
        unsigned long rel_addr, unsigned long rel_size, int type)
447
{
448
  (void)_dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
449
}
450
 
451
int _dl_parse_relocation_information(struct elf_resolve *tpnt,
452
        unsigned long rel_addr, unsigned long rel_size, int type)
453
{
454
  return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
455
}
456
 
457
int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
458
        unsigned long rel_size, int type)
459
{
460
  return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy);
461
}
462
 

powered by: WebSVN 2.1.0

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