]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/uclibc/lib/contrib/uclibc/ldso/ldso/avr32/elfinterp.c
update
[l4.git] / l4 / pkg / uclibc / lib / contrib / uclibc / ldso / ldso / avr32 / elfinterp.c
1 /*
2  * AVR32 ELF shared library loader suppport
3  *
4  * Copyright (C) 2004-2006 Atmel Corporation
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 unsigned long _dl_linux_resolver(unsigned long got_offset, unsigned long *got)
31 {
32         /*
33          * AVR32 currently does not do lazy relocation.
34          */
35 #if 0
36         struct elf_resolve *tpnt = (struct elf_resolve *)got[1];
37         ElfW(Sym) *sym;
38         unsigned long local_gotno;
39         unsigned long gotsym;
40         unsigned long new_addr;
41         char *strtab, *symname;
42         unsigned long *entry;
43         unsigned long sym_index = got_offset / 4;
44
45         local_gotno = tpnt->dynamic_info[DT_AVR32_LOCAL_GOTNO];
46         gotsym = tpnt->dynamic_info[DT_AVR32_GOTSYM];
47
48         sym = ((ElfW(Sym) *)(tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr))
49                 + sym_index;
50         strtab = (char *)(tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
51         symname = strtab + sym->st_name;
52
53         new_addr = (unsigned long) _dl_find_hash(symname,
54                                                  &_dl_loaded_modules->symbol_scope, tpnt,
55                                                  ELF_RTYPE_CLASS_PLT, NULL);
56
57         entry = (unsigned long *)(got + local_gotno + sym_index - gotsym);
58         *entry = new_addr;
59
60         return new_addr;
61 #endif
62         return 0;
63 }
64
65 static int
66 _dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope,
67           unsigned long rel_addr, unsigned long rel_size,
68           int (*reloc_func)(struct elf_resolve *tpnt, struct r_scope_elem *scope,
69                             ElfW(Rela) *rpnt, ElfW(Sym) *symtab, char *strtab))
70 {
71         ElfW(Sym) *symtab;
72         ElfW(Rela) *rpnt;
73         char *strtab;
74         int i;
75
76         rpnt = (ElfW(Rela) *)rel_addr;
77         rel_size /= sizeof(ElfW(Rela));
78         symtab = (ElfW(Sym) *)tpnt->dynamic_info[DT_SYMTAB];
79         strtab = (char *)tpnt->dynamic_info[DT_STRTAB];
80
81         for (i = 0; i < rel_size; i++, rpnt++) {
82                 int symtab_index, res;
83
84                 symtab_index = ELF_R_SYM(rpnt->r_info);
85
86                 debug_sym(symtab, strtab, symtab_index);
87                 debug_reloc(symtab, strtab, rpnt);
88
89                 res = reloc_func(tpnt, scope, rpnt, symtab, strtab);
90
91                 if (res == 0)
92                         continue;
93
94                 _dl_dprintf(2, "\n%s: ", _dl_progname);
95
96                 if (symtab_index)
97                         _dl_dprintf(2, "symbol '%s': ",
98                                     strtab + symtab[symtab_index].st_name);
99
100                 if (res < 0) {
101                         int reloc_type = ELF_R_TYPE(rpnt->r_info);
102 #if defined(__SUPPORT_LD_DEBUG__)
103                         _dl_dprintf(2, "can't handle reloc type %s\n",
104                                     _dl_reltypes(reloc_type));
105 #else
106                         _dl_dprintf(2, "can't handle reloc type %x\n",
107                                     reloc_type);
108 #endif
109                         _dl_exit(-res);
110                 } else {
111                         _dl_dprintf(2, "can't resolve symbol\n");
112                         return res;
113                 }
114         }
115
116         return 0;
117 }
118
119 static int _dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope,
120                         ElfW(Rela) *rpnt, ElfW(Sym) *symtab, char *strtab)
121 {
122         int reloc_type;
123         int symtab_index;
124         char *symname;
125         unsigned long *reloc_addr;
126         unsigned long symbol_addr;
127 #if defined(__SUPPORT_LD_DEBUG__)
128         unsigned long old_val;
129 #endif
130         struct symbol_ref sym_ref;
131
132         reloc_addr = (unsigned long *)(tpnt->loadaddr + rpnt->r_offset);
133         reloc_type = ELF_R_TYPE(rpnt->r_info);
134         symtab_index = ELF_R_SYM(rpnt->r_info);
135         symbol_addr = 0;
136         sym_ref.sym = &symtab[symtab_index];
137         sym_ref.tpnt = NULL;
138         symname = strtab + symtab[symtab_index].st_name;
139
140         if (symtab_index) {
141                 symbol_addr = (unsigned long)
142                         _dl_find_hash(symname, scope, tpnt,
143                                       elf_machine_type_class(reloc_type), &sym_ref);
144
145                 /* Allow undefined references to weak symbols */
146                 if (!symbol_addr &&
147                     ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK) {
148                         _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
149                                     _dl_progname, symname);
150                         return 0;
151                 }
152                 if (_dl_trace_prelink) {
153                         _dl_debug_lookup (symname, tpnt, &symtab[symtab_index],
154                                 &sym_ref, elf_machine_type_class(reloc_type));
155                 }
156         }
157
158 #if defined(__SUPPORT_LD_DEBUG__)
159         old_val = *reloc_addr;
160 #endif
161         switch (reloc_type) {
162         case R_AVR32_NONE:
163                 break;
164         case R_AVR32_GLOB_DAT:
165         case R_AVR32_JMP_SLOT:
166                 *reloc_addr = symbol_addr + rpnt->r_addend;
167                 break;
168         case R_AVR32_RELATIVE:
169                 *reloc_addr = (unsigned long)tpnt->loadaddr
170                         + rpnt->r_addend;
171                 break;
172         default:
173                 return -1;
174         }
175
176 #if defined(__SUPPORT_LD_DEBUG__)
177         if (_dl_debug_reloc && _dl_debug_detail)
178                 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x\n",
179                             old_val, *reloc_addr);
180 #endif
181
182         return 0;
183 }
184
185 void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
186                                            unsigned long rel_addr,
187                                            unsigned long rel_size)
188 {
189         /* TODO: Might want to support this in order to get faster
190          * startup times... */
191 }
192
193 int _dl_parse_relocation_information(struct dyn_elf *rpnt,
194                                      struct r_scope_elem *scope,
195                                      unsigned long rel_addr,
196                                      unsigned long rel_size)
197 {
198         return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size,
199                          _dl_do_reloc);
200 }