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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [uClibc/] [ldso/] [ldso/] [mips/] [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
/* mips/mipsel ELF shared library loader suppport
3
 *
4
   Copyright (C) 2002, Steven J. Hill (sjhill@realitydiluted.com)
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_MIPS_NONE",  "R_MIPS_16",    "R_MIPS_32",
34
                [3]             "R_MIPS_REL32", "R_MIPS_26",    "R_MIPS_HI16",
35
                [6]             "R_MIPS_LO16",  "R_MIPS_GPREL16",       "R_MIPS_LITERAL",
36
                [9]             "R_MIPS_GOT16", "R_MIPS_PC16",  "R_MIPS_CALL16",
37
                [12]    "R_MIPS_GPREL32",
38
                [16]    "R_MIPS_SHIFT5",        "R_MIPS_SHIFT6",        "R_MIPS_64",
39
                [19]    "R_MIPS_GOT_DISP",      "R_MIPS_GOT_PAGE",      "R_MIPS_GOT_OFST",
40
                [22]    "R_MIPS_GOT_HI16",      "R_MIPS_GOT_LO16",      "R_MIPS_SUB",
41
                [25]    "R_MIPS_INSERT_A",      "R_MIPS_INSERT_B",      "R_MIPS_DELETE",
42
                [28]    "R_MIPS_HIGHER",        "R_MIPS_HIGHEST",       "R_MIPS_CALL_HI16",
43
                [31]    "R_MIPS_CALL_LO16",     "R_MIPS_SCN_DISP",      "R_MIPS_REL16",
44
                [34]    "R_MIPS_ADD_IMMEDIATE", "R_MIPS_PJUMP", "R_MIPS_RELGOT",
45
                [37]    "R_MIPS_JALR",
46
};
47
 
48
static const char *
49
_dl_reltypes(int type)
50
{
51
  static char buf[22];
52
  const char *str;
53
 
54
  if (type >= (int)(sizeof (_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) ||
55
      NULL == (str = _dl_reltypes_tab[type]))
56
  {
57
    str =_dl_simple_ltoa( buf, (unsigned long)(type));
58
  }
59
  return str;
60
}
61
 
62
static
63
void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
64
{
65
  if(_dl_debug_symbols)
66
  {
67
    if(symtab_index){
68
      _dl_dprintf(_dl_debug_file, "\n%s\n\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",
69
                  strtab + symtab[symtab_index].st_name,
70
                  symtab[symtab_index].st_value,
71
                  symtab[symtab_index].st_size,
72
                  symtab[symtab_index].st_info,
73
                  symtab[symtab_index].st_other,
74
                  symtab[symtab_index].st_shndx);
75
    }
76
  }
77
}
78
 
79
static void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt)
80
{
81
  if(_dl_debug_reloc)
82
  {
83
    int symtab_index;
84
    const char *sym;
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
#ifdef ELF_USES_RELOCA
93
    _dl_dprintf(_dl_debug_file, "%s\toffset=%x\taddend=%x",
94
                _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
95
                rpnt->r_offset,
96
                rpnt->r_addend);
97
#else
98
    _dl_dprintf(_dl_debug_file, "%s\toffset=%x\n",
99
                _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
100
                rpnt->r_offset);
101
#endif
102
  }
103
}
104
#endif
105
 
106
extern int _dl_linux_resolve(void);
107
 
108
#define OFFSET_GP_GOT 0x7ff0
109
 
110
unsigned long _dl_linux_resolver(unsigned long sym_index,
111
        unsigned long old_gpreg)
112
{
113
        unsigned long *got = (unsigned long *) (old_gpreg - OFFSET_GP_GOT);
114
        struct elf_resolve *tpnt = (struct elf_resolve *) got[1];
115
        Elf32_Sym *sym;
116
        char *strtab;
117
        unsigned long local_gotno;
118
        unsigned long gotsym;
119
        unsigned long new_addr;
120
        unsigned long instr_addr;
121
        char **got_addr;
122
        char *symname;
123
 
124
        gotsym = tpnt->mips_gotsym;
125
        local_gotno = tpnt->mips_local_gotno;
126
 
127
        sym = ((Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr)) + sym_index;
128
        strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
129
        symname = strtab + sym->st_name;
130
 
131
        new_addr = (unsigned long) _dl_find_hash(strtab + sym->st_name,
132
                 tpnt->symbol_scope, tpnt, resolver);
133
 
134
        /* Address of jump instruction to fix up */
135
        instr_addr = (unsigned long) (got + local_gotno + sym_index - gotsym);
136
        got_addr = (char **) instr_addr;
137
 
138
#if defined (__SUPPORT_LD_DEBUG__)
139
        if (_dl_debug_bindings)
140
        {
141
                _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
142
                if(_dl_debug_detail) _dl_dprintf(_dl_debug_file,
143
                                "\n\tpatched %x ==> %x @ %x\n", *got_addr, new_addr, got_addr);
144
        }
145
        if (!_dl_debug_nofixups) {
146
                *got_addr = (char*)new_addr;
147
        }
148
#else
149
        *got_addr = (char*)new_addr;
150
#endif
151
 
152
        return new_addr;
153
}
154
 
155
void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
156
        unsigned long rel_addr, unsigned long rel_size, int type)
157
{
158
        /* Nothing to do */
159
        return;
160
}
161
 
162
int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
163
        unsigned long rel_size, int type)
164
{
165
        /* Nothing to do */
166
        return 0;
167
}
168
 
169
 
170
int _dl_parse_relocation_information(struct elf_resolve *tpnt,
171
        unsigned long rel_addr, unsigned long rel_size, int type)
172
{
173
        Elf32_Sym *symtab;
174
        Elf32_Rel *rpnt;
175
        char *strtab;
176
        unsigned long *got;
177
        unsigned long *reloc_addr=NULL, old_val=0;
178
        unsigned long symbol_addr;
179
        int i, reloc_type, symtab_index;
180
 
181
        /* Now parse the relocation information */
182
        rel_size = rel_size / sizeof(Elf32_Rel);
183
        rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr);
184
 
185
        symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
186
        strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
187
        got = (unsigned long *) (tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
188
 
189
        for (i = 0; i < rel_size; i++, rpnt++) {
190
                reloc_addr = (unsigned long *) (tpnt->loadaddr +
191
                        (unsigned long) rpnt->r_offset);
192
                reloc_type = ELF32_R_TYPE(rpnt->r_info);
193
                symtab_index = ELF32_R_SYM(rpnt->r_info);
194
                symbol_addr = 0;
195
 
196
                if (!symtab_index && tpnt->libtype == program_interpreter)
197
                        continue;
198
 
199
#if defined (__SUPPORT_LD_DEBUG__)
200
                debug_sym(symtab,strtab,symtab_index);
201
                debug_reloc(symtab,strtab,rpnt);
202
                old_val = *reloc_addr;
203
#endif
204
 
205
                switch (reloc_type) {
206
                case R_MIPS_REL32:
207
                        if (symtab_index) {
208
                                if (symtab_index < tpnt->mips_gotsym)
209
                                        *reloc_addr +=
210
                                                symtab[symtab_index].st_value +
211
                                                (unsigned long) tpnt->loadaddr;
212
                                else {
213
                                        *reloc_addr += got[symtab_index + tpnt->mips_local_gotno -
214
                                                tpnt->mips_gotsym];
215
                                }
216
                        }
217
                        else {
218
                                *reloc_addr += (unsigned long) tpnt->loadaddr;
219
                        }
220
                        break;
221
                case R_MIPS_NONE:
222
                        break;
223
                default:
224
                        {
225
                                int reloc_type = ELF32_R_TYPE(rpnt->r_info);
226
                                _dl_dprintf(2, "\n%s: ",_dl_progname);
227
 
228
                                if (symtab_index)
229
                                        _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
230
 
231
#if defined (__SUPPORT_LD_DEBUG__)
232
                                _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
233
#else
234
                                _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
235
#endif                  
236
                                _dl_exit(1);
237
                        }
238
                };
239
 
240
        };
241
#if defined (__SUPPORT_LD_DEBUG__)
242
        if(_dl_debug_reloc && _dl_debug_detail)
243
                _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x\n", old_val, *reloc_addr, reloc_addr);
244
#endif
245
 
246
        return 0;
247
}
248
 
249
void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt)
250
{
251
        Elf32_Sym *sym;
252
        char *strtab;
253
        unsigned long i;
254
        unsigned long *got_entry;
255
 
256
        for (; tpnt ; tpnt = tpnt->next) {
257
 
258
                /* We don't touch the dynamic linker */
259
                if (tpnt->libtype == program_interpreter)
260
                        continue;
261
 
262
                /* Setup the loop variables */
263
                got_entry = (unsigned long *) (tpnt->loadaddr +
264
                        tpnt->dynamic_info[DT_PLTGOT]) + tpnt->mips_local_gotno;
265
                sym = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] +
266
                        (unsigned long) tpnt->loadaddr) + tpnt->mips_gotsym;
267
                strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] +
268
                        (unsigned long) tpnt->loadaddr);
269
                i = tpnt->mips_symtabno - tpnt->mips_gotsym;
270
 
271
                /* Relocate the global GOT entries for the object */
272
                while(i--) {
273
                        if (sym->st_shndx == SHN_UNDEF) {
274
                                if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC && sym->st_value)
275
                                        *got_entry = sym->st_value + (unsigned long) tpnt->loadaddr;
276
                                else {
277
                                        *got_entry = (unsigned long) _dl_find_hash(strtab +
278
                                                sym->st_name, tpnt->symbol_scope, NULL, copyrel);
279
                                }
280
                        }
281
                        else if (sym->st_shndx == SHN_COMMON) {
282
                                *got_entry = (unsigned long) _dl_find_hash(strtab +
283
                                        sym->st_name, tpnt->symbol_scope, NULL, copyrel);
284
                        }
285
                        else if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC &&
286
                                *got_entry != sym->st_value)
287
                                *got_entry += (unsigned long) tpnt->loadaddr;
288
                        else if (ELF32_ST_TYPE(sym->st_info) == STT_SECTION) {
289
                                if (sym->st_other == 0)
290
                                        *got_entry += (unsigned long) tpnt->loadaddr;
291
                        }
292
                        else {
293
                                *got_entry = (unsigned long) _dl_find_hash(strtab +
294
                                        sym->st_name, tpnt->symbol_scope, NULL, copyrel);
295
                        }
296
 
297
                        got_entry++;
298
                        sym++;
299
                }
300
        }
301
}

powered by: WebSVN 2.1.0

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