ia64/xen-unstable

view xen/common/libelf/libelf-relocate.c @ 18594:5e4e234d58be

x86: Define __per_cpu_shift label to help kdump/crashdump.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Oct 08 13:11:06 2008 +0100 (2008-10-08)
parents 58e71ae679d5
children
line source
1 /*
2 * ELF relocation code (not used by xen kernel right now).
3 */
5 #include "libelf-private.h"
7 /* ------------------------------------------------------------------------ */
9 static const char *rel_names_i386[] = {
10 "R_386_NONE",
11 "R_386_32",
12 "R_386_PC32",
13 "R_386_GOT32",
14 "R_386_PLT32",
15 "R_386_COPY",
16 "R_386_GLOB_DAT",
17 "R_386_JMP_SLOT",
18 "R_386_RELATIVE",
19 "R_386_GOTOFF",
20 "R_386_GOTPC",
21 "R_386_32PLT",
22 "R_386_TLS_TPOFF",
23 "R_386_TLS_IE",
24 "R_386_TLS_GOTIE",
25 "R_386_TLS_LE",
26 "R_386_TLS_GD",
27 "R_386_TLS_LDM",
28 "R_386_16",
29 "R_386_PC16",
30 "R_386_8",
31 "R_386_PC8",
32 "R_386_TLS_GD_32",
33 "R_386_TLS_GD_PUSH",
34 "R_386_TLS_GD_CALL",
35 "R_386_TLS_GD_POP",
36 "R_386_TLS_LDM_32",
37 "R_386_TLS_LDM_PUSH",
38 "R_386_TLS_LDM_CALL",
39 "R_386_TLS_LDM_POP",
40 "R_386_TLS_LDO_32",
41 "R_386_TLS_IE_32",
42 "R_386_TLS_LE_32",
43 "R_386_TLS_DTPMOD32",
44 "R_386_TLS_DTPOFF32",
45 "R_386_TLS_TPOFF32",
46 };
48 static int elf_reloc_i386(struct elf_binary *elf, int type,
49 uint64_t addr, uint64_t value)
50 {
51 void *ptr = elf_get_ptr(elf, addr);
52 uint32_t *u32;
54 switch ( type )
55 {
56 case 1 /* R_386_32 */ :
57 u32 = ptr;
58 *u32 += elf->reloc_offset;
59 break;
60 case 2 /* R_386_PC32 */ :
61 /* nothing */
62 break;
63 default:
64 return -1;
65 }
66 return 0;
67 }
69 /* ------------------------------------------------------------------------ */
71 static const char *rel_names_x86_64[] = {
72 "R_X86_64_NONE",
73 "R_X86_64_64",
74 "R_X86_64_PC32",
75 "R_X86_64_GOT32",
76 "R_X86_64_PLT32",
77 "R_X86_64_COPY",
78 "R_X86_64_GLOB_DAT",
79 "R_X86_64_JUMP_SLOT",
80 "R_X86_64_RELATIVE",
81 "R_X86_64_GOTPCREL",
82 "R_X86_64_32",
83 "R_X86_64_32S",
84 "R_X86_64_16",
85 "R_X86_64_PC16",
86 "R_X86_64_8",
87 "R_X86_64_PC8",
88 "R_X86_64_DTPMOD64",
89 "R_X86_64_DTPOFF64",
90 "R_X86_64_TPOFF64",
91 "R_X86_64_TLSGD",
92 "R_X86_64_TLSLD",
93 "R_X86_64_DTPOFF32",
94 "R_X86_64_GOTTPOFF",
95 "R_X86_64_TPOFF32",
96 };
98 static int elf_reloc_x86_64(struct elf_binary *elf, int type,
99 uint64_t addr, uint64_t value)
100 {
101 void *ptr = elf_get_ptr(elf, addr);
102 uint64_t *u64;
103 uint32_t *u32;
104 int32_t *s32;
106 switch ( type )
107 {
108 case 1 /* R_X86_64_64 */ :
109 u64 = ptr;
110 value += elf->reloc_offset;
111 *u64 = value;
112 break;
113 case 2 /* R_X86_64_PC32 */ :
114 u32 = ptr;
115 *u32 = value - addr;
116 if ( *u32 != (uint32_t)(value - addr) )
117 {
118 elf_err(elf, "R_X86_64_PC32 overflow: 0x%" PRIx32
119 " != 0x%" PRIx32 "\n",
120 *u32, (uint32_t) (value - addr));
121 return -1;
122 }
123 break;
124 case 10 /* R_X86_64_32 */ :
125 u32 = ptr;
126 value += elf->reloc_offset;
127 *u32 = value;
128 if ( *u32 != value )
129 {
130 elf_err(elf, "R_X86_64_32 overflow: 0x%" PRIx32
131 " != 0x%" PRIx64 "\n",
132 *u32, value);
133 return -1;
134 }
135 break;
136 case 11 /* R_X86_64_32S */ :
137 s32 = ptr;
138 value += elf->reloc_offset;
139 *s32 = value;
140 if ( *s32 != (int64_t) value )
141 {
142 elf_err(elf, "R_X86_64_32S overflow: 0x%" PRIx32
143 " != 0x%" PRIx64 "\n",
144 *s32, (int64_t) value);
145 return -1;
146 }
147 break;
148 default:
149 return -1;
150 }
151 return 0;
152 }
154 /* ------------------------------------------------------------------------ */
156 static struct relocs {
157 const char **names;
158 int count;
159 int (*func) (struct elf_binary * elf, int type, uint64_t addr,
160 uint64_t value);
161 } relocs[] =
162 /* *INDENT-OFF* */
163 {
164 [EM_386] = {
165 .names = rel_names_i386,
166 .count = sizeof(rel_names_i386) / sizeof(rel_names_i386[0]),
167 .func = elf_reloc_i386,
168 },
169 [EM_X86_64] = {
170 .names = rel_names_x86_64,
171 .count = sizeof(rel_names_x86_64) / sizeof(rel_names_x86_64[0]),
172 .func = elf_reloc_x86_64,
173 }
174 };
175 /* *INDENT-ON* */
177 /* ------------------------------------------------------------------------ */
179 static const char *rela_name(int machine, int type)
180 {
181 if ( machine > sizeof(relocs) / sizeof(relocs[0]) )
182 return "unknown mach";
183 if ( !relocs[machine].names )
184 return "unknown mach";
185 if ( type > relocs[machine].count )
186 return "unknown rela";
187 return relocs[machine].names[type];
188 }
190 static int elf_reloc_section(struct elf_binary *elf,
191 const elf_shdr * rels,
192 const elf_shdr * sect, const elf_shdr * syms)
193 {
194 const void *ptr, *end;
195 const elf_shdr *shdr;
196 const elf_rela *rela;
197 const elf_rel *rel;
198 const elf_sym *sym;
199 uint64_t s_type;
200 uint64_t r_offset;
201 uint64_t r_info;
202 uint64_t r_addend;
203 int r_type, r_sym;
204 size_t rsize;
205 uint64_t shndx, sbase, addr, value;
206 const char *sname;
207 int machine;
209 machine = elf_uval(elf, elf->ehdr, e_machine);
210 if ( (machine >= (sizeof(relocs) / sizeof(relocs[0]))) ||
211 (relocs[machine].func == NULL) )
212 {
213 elf_err(elf, "%s: can't handle machine %d\n",
214 __FUNCTION__, machine);
215 return -1;
216 }
217 if ( elf_swap(elf) )
218 {
219 elf_err(elf, "%s: non-native byte order, relocation not supported\n",
220 __FUNCTION__);
221 return -1;
222 }
224 s_type = elf_uval(elf, rels, sh_type);
225 rsize = (SHT_REL == s_type) ? elf_size(elf, rel) : elf_size(elf, rela);
226 ptr = elf_section_start(elf, rels);
227 end = elf_section_end(elf, rels);
229 for ( ; ptr < end; ptr += rsize )
230 {
231 switch ( s_type )
232 {
233 case SHT_REL:
234 rel = ptr;
235 r_offset = elf_uval(elf, rel, r_offset);
236 r_info = elf_uval(elf, rel, r_info);
237 r_addend = 0;
238 break;
239 case SHT_RELA:
240 rela = ptr;
241 r_offset = elf_uval(elf, rela, r_offset);
242 r_info = elf_uval(elf, rela, r_info);
243 r_addend = elf_uval(elf, rela, r_addend);
244 break;
245 default:
246 /* can't happen */
247 return -1;
248 }
249 if ( elf_64bit(elf) )
250 {
251 r_type = ELF64_R_TYPE(r_info);
252 r_sym = ELF64_R_SYM(r_info);
253 }
254 else
255 {
256 r_type = ELF32_R_TYPE(r_info);
257 r_sym = ELF32_R_SYM(r_info);
258 }
260 sym = elf_sym_by_index(elf, r_sym);
261 shndx = elf_uval(elf, sym, st_shndx);
262 switch ( shndx )
263 {
264 case SHN_UNDEF:
265 sname = "*UNDEF*";
266 sbase = 0;
267 break;
268 case SHN_COMMON:
269 elf_err(elf, "%s: invalid section: %" PRId64 "\n",
270 __FUNCTION__, shndx);
271 return -1;
272 case SHN_ABS:
273 sname = "*ABS*";
274 sbase = 0;
275 break;
276 default:
277 shdr = elf_shdr_by_index(elf, shndx);
278 if ( shdr == NULL )
279 {
280 elf_err(elf, "%s: invalid section: %" PRId64 "\n",
281 __FUNCTION__, shndx);
282 return -1;
283 }
284 sname = elf_section_name(elf, shdr);
285 sbase = elf_uval(elf, shdr, sh_addr);
286 }
288 addr = r_offset;
289 value = elf_uval(elf, sym, st_value);
290 value += r_addend;
292 if ( elf->log && (elf->verbose > 1) )
293 {
294 uint64_t st_name = elf_uval(elf, sym, st_name);
295 const char *name = st_name ? elf->sym_strtab + st_name : "*NONE*";
297 elf_msg(elf,
298 "%s: type %s [%d], off 0x%" PRIx64 ", add 0x%" PRIx64 ","
299 " sym %s [0x%" PRIx64 "], sec %s [0x%" PRIx64 "]"
300 " -> addr 0x%" PRIx64 " value 0x%" PRIx64 "\n",
301 __FUNCTION__, rela_name(machine, r_type), r_type, r_offset,
302 r_addend, name, elf_uval(elf, sym, st_value), sname, sbase,
303 addr, value);
304 }
306 if ( relocs[machine].func(elf, r_type, addr, value) == -1 )
307 {
308 elf_err(elf, "%s: unknown/unsupported reloc type %s [%d]\n",
309 __FUNCTION__, rela_name(machine, r_type), r_type);
310 return -1;
311 }
312 }
313 return 0;
314 }
316 int elf_reloc(struct elf_binary *elf)
317 {
318 const elf_shdr *rels, *sect, *syms;
319 uint64_t i, count, type;
321 count = elf_shdr_count(elf);
322 for ( i = 0; i < count; i++ )
323 {
324 rels = elf_shdr_by_index(elf, i);
325 type = elf_uval(elf, rels, sh_type);
326 if ( (type != SHT_REL) && (type != SHT_RELA) )
327 continue;
329 sect = elf_shdr_by_index(elf, elf_uval(elf, rels, sh_info));
330 syms = elf_shdr_by_index(elf, elf_uval(elf, rels, sh_link));
331 if ( NULL == sect || NULL == syms )
332 continue;
334 if ( !(elf_uval(elf, sect, sh_flags) & SHF_ALLOC) )
335 {
336 elf_msg(elf, "%s: relocations for %s, skipping\n",
337 __FUNCTION__, elf_section_name(elf, sect));
338 continue;
339 }
341 elf_msg(elf, "%s: relocations for %s @ 0x%" PRIx64 "\n",
342 __FUNCTION__, elf_section_name(elf, sect),
343 elf_uval(elf, sect, sh_addr));
344 if ( elf_reloc_section(elf, rels, sect, syms) != 0 )
345 return -1;
346 }
347 return 0;
348 }
350 /*
351 * Local variables:
352 * mode: C
353 * c-set-style: "BSD"
354 * c-basic-offset: 4
355 * tab-width: 4
356 * indent-tabs-mode: nil
357 * End:
358 */