debuggers.hg

view xen/common/libelf/libelf-relocate.c @ 22848:6341fe0f4e5a

Added tag 4.1.0-rc2 for changeset 9dca60d88c63
author Keir Fraser <keir@xen.org>
date Tue Jan 25 14:06:55 2011 +0000 (2011-01-25)
parents eccfdeb41b80
children
line source
1 /*
2 * ELF relocation code (not used by xen kernel right now).
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation;
7 * version 2.1 of the License.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
19 #include "libelf-private.h"
21 /* ------------------------------------------------------------------------ */
23 static const char *rel_names_i386[] = {
24 "R_386_NONE",
25 "R_386_32",
26 "R_386_PC32",
27 "R_386_GOT32",
28 "R_386_PLT32",
29 "R_386_COPY",
30 "R_386_GLOB_DAT",
31 "R_386_JMP_SLOT",
32 "R_386_RELATIVE",
33 "R_386_GOTOFF",
34 "R_386_GOTPC",
35 "R_386_32PLT",
36 "R_386_TLS_TPOFF",
37 "R_386_TLS_IE",
38 "R_386_TLS_GOTIE",
39 "R_386_TLS_LE",
40 "R_386_TLS_GD",
41 "R_386_TLS_LDM",
42 "R_386_16",
43 "R_386_PC16",
44 "R_386_8",
45 "R_386_PC8",
46 "R_386_TLS_GD_32",
47 "R_386_TLS_GD_PUSH",
48 "R_386_TLS_GD_CALL",
49 "R_386_TLS_GD_POP",
50 "R_386_TLS_LDM_32",
51 "R_386_TLS_LDM_PUSH",
52 "R_386_TLS_LDM_CALL",
53 "R_386_TLS_LDM_POP",
54 "R_386_TLS_LDO_32",
55 "R_386_TLS_IE_32",
56 "R_386_TLS_LE_32",
57 "R_386_TLS_DTPMOD32",
58 "R_386_TLS_DTPOFF32",
59 "R_386_TLS_TPOFF32",
60 };
62 static int elf_reloc_i386(struct elf_binary *elf, int type,
63 uint64_t addr, uint64_t value)
64 {
65 void *ptr = elf_get_ptr(elf, addr);
66 uint32_t *u32;
68 switch ( type )
69 {
70 case 1 /* R_386_32 */ :
71 u32 = ptr;
72 *u32 += elf->reloc_offset;
73 break;
74 case 2 /* R_386_PC32 */ :
75 /* nothing */
76 break;
77 default:
78 return -1;
79 }
80 return 0;
81 }
83 /* ------------------------------------------------------------------------ */
85 static const char *rel_names_x86_64[] = {
86 "R_X86_64_NONE",
87 "R_X86_64_64",
88 "R_X86_64_PC32",
89 "R_X86_64_GOT32",
90 "R_X86_64_PLT32",
91 "R_X86_64_COPY",
92 "R_X86_64_GLOB_DAT",
93 "R_X86_64_JUMP_SLOT",
94 "R_X86_64_RELATIVE",
95 "R_X86_64_GOTPCREL",
96 "R_X86_64_32",
97 "R_X86_64_32S",
98 "R_X86_64_16",
99 "R_X86_64_PC16",
100 "R_X86_64_8",
101 "R_X86_64_PC8",
102 "R_X86_64_DTPMOD64",
103 "R_X86_64_DTPOFF64",
104 "R_X86_64_TPOFF64",
105 "R_X86_64_TLSGD",
106 "R_X86_64_TLSLD",
107 "R_X86_64_DTPOFF32",
108 "R_X86_64_GOTTPOFF",
109 "R_X86_64_TPOFF32",
110 };
112 static int elf_reloc_x86_64(struct elf_binary *elf, int type,
113 uint64_t addr, uint64_t value)
114 {
115 void *ptr = elf_get_ptr(elf, addr);
116 uint64_t *u64;
117 uint32_t *u32;
118 int32_t *s32;
120 switch ( type )
121 {
122 case 1 /* R_X86_64_64 */ :
123 u64 = ptr;
124 value += elf->reloc_offset;
125 *u64 = value;
126 break;
127 case 2 /* R_X86_64_PC32 */ :
128 u32 = ptr;
129 *u32 = value - addr;
130 if ( *u32 != (uint32_t)(value - addr) )
131 {
132 elf_err(elf, "R_X86_64_PC32 overflow: 0x%" PRIx32
133 " != 0x%" PRIx32 "\n",
134 *u32, (uint32_t) (value - addr));
135 return -1;
136 }
137 break;
138 case 10 /* R_X86_64_32 */ :
139 u32 = ptr;
140 value += elf->reloc_offset;
141 *u32 = value;
142 if ( *u32 != value )
143 {
144 elf_err(elf, "R_X86_64_32 overflow: 0x%" PRIx32
145 " != 0x%" PRIx64 "\n",
146 *u32, value);
147 return -1;
148 }
149 break;
150 case 11 /* R_X86_64_32S */ :
151 s32 = ptr;
152 value += elf->reloc_offset;
153 *s32 = value;
154 if ( *s32 != (int64_t) value )
155 {
156 elf_err(elf, "R_X86_64_32S overflow: 0x%" PRIx32
157 " != 0x%" PRIx64 "\n",
158 *s32, (int64_t) value);
159 return -1;
160 }
161 break;
162 default:
163 return -1;
164 }
165 return 0;
166 }
168 /* ------------------------------------------------------------------------ */
170 static struct relocs {
171 const char **names;
172 int count;
173 int (*func) (struct elf_binary * elf, int type, uint64_t addr,
174 uint64_t value);
175 } relocs[] =
176 /* *INDENT-OFF* */
177 {
178 [EM_386] = {
179 .names = rel_names_i386,
180 .count = sizeof(rel_names_i386) / sizeof(rel_names_i386[0]),
181 .func = elf_reloc_i386,
182 },
183 [EM_X86_64] = {
184 .names = rel_names_x86_64,
185 .count = sizeof(rel_names_x86_64) / sizeof(rel_names_x86_64[0]),
186 .func = elf_reloc_x86_64,
187 }
188 };
189 /* *INDENT-ON* */
191 /* ------------------------------------------------------------------------ */
193 static const char *rela_name(int machine, int type)
194 {
195 if ( machine > sizeof(relocs) / sizeof(relocs[0]) )
196 return "unknown mach";
197 if ( !relocs[machine].names )
198 return "unknown mach";
199 if ( type > relocs[machine].count )
200 return "unknown rela";
201 return relocs[machine].names[type];
202 }
204 static int elf_reloc_section(struct elf_binary *elf,
205 const elf_shdr * rels,
206 const elf_shdr * sect, const elf_shdr * syms)
207 {
208 const void *ptr, *end;
209 const elf_shdr *shdr;
210 const elf_rela *rela;
211 const elf_rel *rel;
212 const elf_sym *sym;
213 uint64_t s_type;
214 uint64_t r_offset;
215 uint64_t r_info;
216 uint64_t r_addend;
217 int r_type, r_sym;
218 size_t rsize;
219 uint64_t shndx, sbase, addr, value;
220 const char *sname;
221 int machine;
223 machine = elf_uval(elf, elf->ehdr, e_machine);
224 if ( (machine >= (sizeof(relocs) / sizeof(relocs[0]))) ||
225 (relocs[machine].func == NULL) )
226 {
227 elf_err(elf, "%s: can't handle machine %d\n",
228 __FUNCTION__, machine);
229 return -1;
230 }
231 if ( elf_swap(elf) )
232 {
233 elf_err(elf, "%s: non-native byte order, relocation not supported\n",
234 __FUNCTION__);
235 return -1;
236 }
238 s_type = elf_uval(elf, rels, sh_type);
239 rsize = (SHT_REL == s_type) ? elf_size(elf, rel) : elf_size(elf, rela);
240 ptr = elf_section_start(elf, rels);
241 end = elf_section_end(elf, rels);
243 for ( ; ptr < end; ptr += rsize )
244 {
245 switch ( s_type )
246 {
247 case SHT_REL:
248 rel = ptr;
249 r_offset = elf_uval(elf, rel, r_offset);
250 r_info = elf_uval(elf, rel, r_info);
251 r_addend = 0;
252 break;
253 case SHT_RELA:
254 rela = ptr;
255 r_offset = elf_uval(elf, rela, r_offset);
256 r_info = elf_uval(elf, rela, r_info);
257 r_addend = elf_uval(elf, rela, r_addend);
258 break;
259 default:
260 /* can't happen */
261 return -1;
262 }
263 if ( elf_64bit(elf) )
264 {
265 r_type = ELF64_R_TYPE(r_info);
266 r_sym = ELF64_R_SYM(r_info);
267 }
268 else
269 {
270 r_type = ELF32_R_TYPE(r_info);
271 r_sym = ELF32_R_SYM(r_info);
272 }
274 sym = elf_sym_by_index(elf, r_sym);
275 shndx = elf_uval(elf, sym, st_shndx);
276 switch ( shndx )
277 {
278 case SHN_UNDEF:
279 sname = "*UNDEF*";
280 sbase = 0;
281 break;
282 case SHN_COMMON:
283 elf_err(elf, "%s: invalid section: %" PRId64 "\n",
284 __FUNCTION__, shndx);
285 return -1;
286 case SHN_ABS:
287 sname = "*ABS*";
288 sbase = 0;
289 break;
290 default:
291 shdr = elf_shdr_by_index(elf, shndx);
292 if ( shdr == NULL )
293 {
294 elf_err(elf, "%s: invalid section: %" PRId64 "\n",
295 __FUNCTION__, shndx);
296 return -1;
297 }
298 sname = elf_section_name(elf, shdr);
299 sbase = elf_uval(elf, shdr, sh_addr);
300 }
302 addr = r_offset;
303 value = elf_uval(elf, sym, st_value);
304 value += r_addend;
306 if ( elf->log_callback && (elf->verbose > 1) )
307 {
308 uint64_t st_name = elf_uval(elf, sym, st_name);
309 const char *name = st_name ? elf->sym_strtab + st_name : "*NONE*";
311 elf_msg(elf,
312 "%s: type %s [%d], off 0x%" PRIx64 ", add 0x%" PRIx64 ","
313 " sym %s [0x%" PRIx64 "], sec %s [0x%" PRIx64 "]"
314 " -> addr 0x%" PRIx64 " value 0x%" PRIx64 "\n",
315 __FUNCTION__, rela_name(machine, r_type), r_type, r_offset,
316 r_addend, name, elf_uval(elf, sym, st_value), sname, sbase,
317 addr, value);
318 }
320 if ( relocs[machine].func(elf, r_type, addr, value) == -1 )
321 {
322 elf_err(elf, "%s: unknown/unsupported reloc type %s [%d]\n",
323 __FUNCTION__, rela_name(machine, r_type), r_type);
324 return -1;
325 }
326 }
327 return 0;
328 }
330 int elf_reloc(struct elf_binary *elf)
331 {
332 const elf_shdr *rels, *sect, *syms;
333 uint64_t i, count, type;
335 count = elf_shdr_count(elf);
336 for ( i = 0; i < count; i++ )
337 {
338 rels = elf_shdr_by_index(elf, i);
339 type = elf_uval(elf, rels, sh_type);
340 if ( (type != SHT_REL) && (type != SHT_RELA) )
341 continue;
343 sect = elf_shdr_by_index(elf, elf_uval(elf, rels, sh_info));
344 syms = elf_shdr_by_index(elf, elf_uval(elf, rels, sh_link));
345 if ( NULL == sect || NULL == syms )
346 continue;
348 if ( !(elf_uval(elf, sect, sh_flags) & SHF_ALLOC) )
349 {
350 elf_msg(elf, "%s: relocations for %s, skipping\n",
351 __FUNCTION__, elf_section_name(elf, sect));
352 continue;
353 }
355 elf_msg(elf, "%s: relocations for %s @ 0x%" PRIx64 "\n",
356 __FUNCTION__, elf_section_name(elf, sect),
357 elf_uval(elf, sect, sh_addr));
358 if ( elf_reloc_section(elf, rels, sect, syms) != 0 )
359 return -1;
360 }
361 return 0;
362 }
364 /*
365 * Local variables:
366 * mode: C
367 * c-set-style: "BSD"
368 * c-basic-offset: 4
369 * tab-width: 4
370 * indent-tabs-mode: nil
371 * End:
372 */