source: trunk/src/binutils/bfd/elf32-d10v.c@ 610

Last change on this file since 610 was 610, checked in by bird, 22 years ago

This commit was generated by cvs2svn to compensate for changes in r609,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 16.0 KB
Line 
1/* D10V-specific support for 32-bit ELF
2 Copyright 1996, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
3 Contributed by Martin Hunt (hunt@cygnus.com).
4
5This file is part of BFD, the Binary File Descriptor library.
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or
10(at your option) any later version.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program; if not, write to the Free Software
19Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21#include "bfd.h"
22#include "sysdep.h"
23#include "libbfd.h"
24#include "elf-bfd.h"
25#include "elf/d10v.h"
26
27static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
28 PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
29static void d10v_info_to_howto_rel
30 PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
31static asection * elf32_d10v_gc_mark_hook
32 PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
33 struct elf_link_hash_entry *, Elf_Internal_Sym *));
34static bfd_boolean elf32_d10v_gc_sweep_hook
35 PARAMS ((bfd *, struct bfd_link_info *, asection *,
36 const Elf_Internal_Rela *));
37static bfd_boolean elf32_d10v_check_relocs
38 PARAMS ((bfd *, struct bfd_link_info *, asection *,
39 const Elf_Internal_Rela *));
40static bfd_boolean elf32_d10v_relocate_section
41 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *,
42 bfd_byte *, Elf_Internal_Rela *, Elf_Internal_Sym *,
43 asection **));
44
45/* Use REL instead of RELA to save space. */
46#define USE_REL 1
47
48static reloc_howto_type elf_d10v_howto_table[] =
49 {
50 /* This reloc does nothing. */
51 HOWTO (R_D10V_NONE, /* type */
52 0, /* rightshift */
53 2, /* size (0 = byte, 1 = short, 2 = long) */
54 32, /* bitsize */
55 FALSE, /* pc_relative */
56 0, /* bitpos */
57 complain_overflow_dont, /* complain_on_overflow */
58 bfd_elf_generic_reloc, /* special_function */
59 "R_D10V_NONE", /* name */
60 FALSE, /* partial_inplace */
61 0, /* src_mask */
62 0, /* dst_mask */
63 FALSE), /* pcrel_offset */
64
65 /* An PC Relative 10-bit relocation, shifted by 2 */
66 /* right container */
67 HOWTO (R_D10V_10_PCREL_R, /* type */
68 2, /* rightshift */
69 2, /* size (0 = byte, 1 = short, 2 = long) */
70 7, /* bitsize */
71 TRUE, /* pc_relative */
72 0, /* bitpos */
73 complain_overflow_bitfield, /* complain_on_overflow */
74 bfd_elf_generic_reloc, /* special_function */
75 "R_D10V_10_PCREL_R", /* name */
76 FALSE, /* partial_inplace */
77 0xff, /* src_mask */
78 0xff, /* dst_mask */
79 TRUE), /* pcrel_offset */
80
81 /* An PC Relative 10-bit relocation, shifted by 2 */
82 /* left container */
83 HOWTO (R_D10V_10_PCREL_L, /* type */
84 2, /* rightshift */
85 2, /* size (0 = byte, 1 = short, 2 = long) */
86 7, /* bitsize */
87 TRUE, /* pc_relative */
88 15, /* bitpos */
89 complain_overflow_bitfield, /* complain_on_overflow */
90 bfd_elf_generic_reloc, /* special_function */
91 "R_D10V_10_PCREL_L", /* name */
92 FALSE, /* partial_inplace */
93 0x07f8000, /* src_mask */
94 0x07f8000, /* dst_mask */
95 TRUE), /* pcrel_offset */
96
97 /* A 16 bit absolute relocation */
98 HOWTO (R_D10V_16, /* type */
99 0, /* rightshift */
100 1, /* size (0 = byte, 1 = short, 2 = long) */
101 16, /* bitsize */
102 FALSE, /* pc_relative */
103 0, /* bitpos */
104 complain_overflow_dont, /* complain_on_overflow */
105 bfd_elf_generic_reloc, /* special_function */
106 "R_D10V_16", /* name */
107 FALSE, /* partial_inplace */
108 0xffff, /* src_mask */
109 0xffff, /* dst_mask */
110 FALSE), /* pcrel_offset */
111
112 /* An 18 bit absolute relocation, right shifted 2 */
113 HOWTO (R_D10V_18, /* type */
114 2, /* rightshift */
115 1, /* size (0 = byte, 1 = short, 2 = long) */
116 16, /* bitsize */
117 FALSE, /* pc_relative */
118 0, /* bitpos */
119 complain_overflow_dont, /* complain_on_overflow */
120 bfd_elf_generic_reloc, /* special_function */
121 "R_D10V_18", /* name */
122 FALSE, /* partial_inplace */
123 0xffff, /* src_mask */
124 0xffff, /* dst_mask */
125 FALSE), /* pcrel_offset */
126
127 /* A relative 18 bit relocation, right shifted by 2 */
128 HOWTO (R_D10V_18_PCREL, /* type */
129 2, /* rightshift */
130 2, /* size (0 = byte, 1 = short, 2 = long) */
131 15, /* bitsize */
132 TRUE, /* pc_relative */
133 0, /* bitpos */
134 complain_overflow_bitfield, /* complain_on_overflow */
135 bfd_elf_generic_reloc, /* special_function */
136 "R_D10V_18_PCREL", /* name */
137 FALSE, /* partial_inplace */
138 0xffff, /* src_mask */
139 0xffff, /* dst_mask */
140 TRUE), /* pcrel_offset */
141
142 /* A 32 bit absolute relocation */
143 HOWTO (R_D10V_32, /* type */
144 0, /* rightshift */
145 2, /* size (0 = byte, 1 = short, 2 = long) */
146 32, /* bitsize */
147 FALSE, /* pc_relative */
148 0, /* bitpos */
149 complain_overflow_dont, /* complain_on_overflow */
150 bfd_elf_generic_reloc, /* special_function */
151 "R_D10V_32", /* name */
152 FALSE, /* partial_inplace */
153 0xffffffff, /* src_mask */
154 0xffffffff, /* dst_mask */
155 FALSE), /* pcrel_offset */
156
157 /* GNU extension to record C++ vtable hierarchy */
158 HOWTO (R_D10V_GNU_VTINHERIT, /* type */
159 0, /* rightshift */
160 2, /* size (0 = byte, 1 = short, 2 = long) */
161 0, /* bitsize */
162 FALSE, /* pc_relative */
163 0, /* bitpos */
164 complain_overflow_dont, /* complain_on_overflow */
165 NULL, /* special_function */
166 "R_D10V_GNU_VTINHERIT", /* name */
167 FALSE, /* partial_inplace */
168 0, /* src_mask */
169 0, /* dst_mask */
170 FALSE), /* pcrel_offset */
171
172 /* GNU extension to record C++ vtable member usage */
173 HOWTO (R_D10V_GNU_VTENTRY, /* type */
174 0, /* rightshift */
175 2, /* size (0 = byte, 1 = short, 2 = long) */
176 0, /* bitsize */
177 FALSE, /* pc_relative */
178 0, /* bitpos */
179 complain_overflow_dont, /* complain_on_overflow */
180 _bfd_elf_rel_vtable_reloc_fn, /* special_function */
181 "R_D10V_GNU_VTENTRY", /* name */
182 FALSE, /* partial_inplace */
183 0, /* src_mask */
184 0, /* dst_mask */
185 FALSE), /* pcrel_offset */
186 };
187
188/* Map BFD reloc types to D10V ELF reloc types. */
189
190struct d10v_reloc_map
191 {
192 bfd_reloc_code_real_type bfd_reloc_val;
193 unsigned char elf_reloc_val;
194 };
195
196static const struct d10v_reloc_map d10v_reloc_map[] =
197 {
198 { BFD_RELOC_NONE, R_D10V_NONE, },
199 { BFD_RELOC_D10V_10_PCREL_R, R_D10V_10_PCREL_R },
200 { BFD_RELOC_D10V_10_PCREL_L, R_D10V_10_PCREL_L },
201 { BFD_RELOC_16, R_D10V_16 },
202 { BFD_RELOC_D10V_18, R_D10V_18 },
203 { BFD_RELOC_D10V_18_PCREL, R_D10V_18_PCREL },
204 { BFD_RELOC_32, R_D10V_32 },
205 { BFD_RELOC_VTABLE_INHERIT, R_D10V_GNU_VTINHERIT },
206 { BFD_RELOC_VTABLE_ENTRY, R_D10V_GNU_VTENTRY },
207 };
208
209static reloc_howto_type *
210bfd_elf32_bfd_reloc_type_lookup (abfd, code)
211 bfd *abfd ATTRIBUTE_UNUSED;
212 bfd_reloc_code_real_type code;
213{
214 unsigned int i;
215
216 for (i = 0;
217 i < sizeof (d10v_reloc_map) / sizeof (struct d10v_reloc_map);
218 i++)
219 {
220 if (d10v_reloc_map[i].bfd_reloc_val == code)
221 return &elf_d10v_howto_table[d10v_reloc_map[i].elf_reloc_val];
222 }
223
224 return NULL;
225}
226
227/* Set the howto pointer for an D10V ELF reloc. */
228
229static void
230d10v_info_to_howto_rel (abfd, cache_ptr, dst)
231 bfd *abfd ATTRIBUTE_UNUSED;
232 arelent *cache_ptr;
233 Elf_Internal_Rela *dst;
234{
235 unsigned int r_type;
236
237 r_type = ELF32_R_TYPE (dst->r_info);
238 BFD_ASSERT (r_type < (unsigned int) R_D10V_max);
239 cache_ptr->howto = &elf_d10v_howto_table[r_type];
240}
241
242static asection *
243elf32_d10v_gc_mark_hook (sec, info, rel, h, sym)
244 asection *sec;
245 struct bfd_link_info *info ATTRIBUTE_UNUSED;
246 Elf_Internal_Rela *rel;
247 struct elf_link_hash_entry *h;
248 Elf_Internal_Sym *sym;
249{
250 if (h != NULL)
251 {
252 switch (ELF32_R_TYPE (rel->r_info))
253 {
254 case R_D10V_GNU_VTINHERIT:
255 case R_D10V_GNU_VTENTRY:
256 break;
257
258 default:
259 switch (h->root.type)
260 {
261 case bfd_link_hash_defined:
262 case bfd_link_hash_defweak:
263 return h->root.u.def.section;
264
265 case bfd_link_hash_common:
266 return h->root.u.c.p->section;
267
268 default:
269 break;
270 }
271 }
272 }
273 else
274 return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
275
276 return NULL;
277}
278
279static bfd_boolean
280elf32_d10v_gc_sweep_hook (abfd, info, sec, relocs)
281 bfd *abfd ATTRIBUTE_UNUSED;
282 struct bfd_link_info *info ATTRIBUTE_UNUSED;
283 asection *sec ATTRIBUTE_UNUSED;
284 const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED;
285{
286 /* we don't use got and plt entries for d10v */
287 return TRUE;
288}
289
290/* Look through the relocs for a section during the first phase.
291 Since we don't do .gots or .plts, we just need to consider the
292 virtual table relocs for gc. */
293
294static bfd_boolean
295elf32_d10v_check_relocs (abfd, info, sec, relocs)
296 bfd *abfd;
297 struct bfd_link_info *info;
298 asection *sec;
299 const Elf_Internal_Rela *relocs;
300{
301 Elf_Internal_Shdr *symtab_hdr;
302 struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
303 const Elf_Internal_Rela *rel;
304 const Elf_Internal_Rela *rel_end;
305
306 if (info->relocateable)
307 return TRUE;
308
309 symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
310 sym_hashes = elf_sym_hashes (abfd);
311 sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym);
312 if (!elf_bad_symtab (abfd))
313 sym_hashes_end -= symtab_hdr->sh_info;
314
315 rel_end = relocs + sec->reloc_count;
316 for (rel = relocs; rel < rel_end; rel++)
317 {
318 struct elf_link_hash_entry *h;
319 unsigned long r_symndx;
320
321 r_symndx = ELF32_R_SYM (rel->r_info);
322 if (r_symndx < symtab_hdr->sh_info)
323 h = NULL;
324 else
325 h = sym_hashes[r_symndx - symtab_hdr->sh_info];
326
327 switch (ELF32_R_TYPE (rel->r_info))
328 {
329 /* This relocation describes the C++ object vtable hierarchy.
330 Reconstruct it for later use during GC. */
331 case R_D10V_GNU_VTINHERIT:
332 if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
333 return FALSE;
334 break;
335
336 /* This relocation describes which C++ vtable entries are actually
337 used. Record for later use during GC. */
338 case R_D10V_GNU_VTENTRY:
339 if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_offset))
340 return FALSE;
341 break;
342 }
343 }
344
345 return TRUE;
346}
347
348/* Relocate a D10V ELF section. */
349static bfd_boolean
350elf32_d10v_relocate_section (output_bfd, info, input_bfd, input_section,
351 contents, relocs, local_syms, local_sections)
352 bfd *output_bfd;
353 struct bfd_link_info *info;
354 bfd *input_bfd;
355 asection *input_section;
356 bfd_byte *contents;
357 Elf_Internal_Rela *relocs;
358 Elf_Internal_Sym *local_syms;
359 asection **local_sections;
360{
361 Elf_Internal_Shdr *symtab_hdr;
362 struct elf_link_hash_entry **sym_hashes;
363 Elf_Internal_Rela *rel, *relend;
364 const char *name;
365
366 symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
367 sym_hashes = elf_sym_hashes (input_bfd);
368
369 rel = relocs;
370 relend = relocs + input_section->reloc_count;
371 for (; rel < relend; rel++)
372 {
373 int r_type;
374 reloc_howto_type *howto;
375 unsigned long r_symndx;
376 Elf_Internal_Sym *sym;
377 asection *sec;
378 struct elf_link_hash_entry *h;
379 bfd_vma relocation;
380 bfd_reloc_status_type r;
381
382 r_symndx = ELF32_R_SYM (rel->r_info);
383 r_type = ELF32_R_TYPE (rel->r_info);
384
385 if (r_type == R_D10V_GNU_VTENTRY
386 || r_type == R_D10V_GNU_VTINHERIT )
387 continue;
388
389 howto = elf_d10v_howto_table + r_type;
390
391 if (info->relocateable)
392 {
393 /* This is a relocateable link. We don't have to change
394 anything, unless the reloc is against a section symbol,
395 in which case we have to adjust according to where the
396 section symbol winds up in the output section. */
397 if (r_symndx < symtab_hdr->sh_info)
398 {
399 sym = local_syms + r_symndx;
400 if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
401 {
402 sec = local_sections[r_symndx];
403 rel->r_addend += sec->output_offset + sym->st_value;
404 }
405 }
406
407 continue;
408 }
409
410 /* This is a final link. */
411 h = NULL;
412 sym = NULL;
413 sec = NULL;
414 if (r_symndx < symtab_hdr->sh_info)
415 {
416 sym = local_syms + r_symndx;
417 sec = local_sections[r_symndx];
418 relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
419 }
420 else
421 {
422 h = sym_hashes[r_symndx - symtab_hdr->sh_info];
423 while (h->root.type == bfd_link_hash_indirect
424 || h->root.type == bfd_link_hash_warning)
425 h = (struct elf_link_hash_entry *) h->root.u.i.link;
426 if (h->root.type == bfd_link_hash_defined
427 || h->root.type == bfd_link_hash_defweak)
428 {
429 sec = h->root.u.def.section;
430 relocation = (h->root.u.def.value
431 + sec->output_section->vma
432 + sec->output_offset);
433 }
434 else if (h->root.type == bfd_link_hash_undefweak)
435 relocation = 0;
436 else
437 {
438 if (!((*info->callbacks->undefined_symbol)
439 (info, h->root.root.string, input_bfd,
440 input_section, rel->r_offset, TRUE)))
441 return FALSE;
442 relocation = 0;
443 }
444 }
445
446 if (h != NULL)
447 name = h->root.root.string;
448 else
449 {
450 name = (bfd_elf_string_from_elf_section
451 (input_bfd, symtab_hdr->sh_link, sym->st_name));
452 if (name == NULL || *name == '\0')
453 name = bfd_section_name (input_bfd, sec);
454 }
455
456 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
457 contents, rel->r_offset,
458 relocation, rel->r_addend);
459
460 if (r != bfd_reloc_ok)
461 {
462 const char * msg = (const char *) 0;
463
464 switch (r)
465 {
466 case bfd_reloc_overflow:
467 if (!((*info->callbacks->reloc_overflow)
468 (info, name, howto->name, (bfd_vma) 0,
469 input_bfd, input_section, rel->r_offset)))
470 return FALSE;
471 break;
472
473 case bfd_reloc_undefined:
474 if (!((*info->callbacks->undefined_symbol)
475 (info, name, input_bfd, input_section,
476 rel->r_offset, TRUE)))
477 return FALSE;
478 break;
479
480 case bfd_reloc_outofrange:
481 msg = _("internal error: out of range error");
482 goto common_error;
483
484 case bfd_reloc_notsupported:
485 msg = _("internal error: unsupported relocation error");
486 goto common_error;
487
488 case bfd_reloc_dangerous:
489 msg = _("internal error: dangerous error");
490 goto common_error;
491
492 default:
493 msg = _("internal error: unknown error");
494 /* fall through */
495
496 common_error:
497 if (!((*info->callbacks->warning)
498 (info, msg, name, input_bfd, input_section,
499 rel->r_offset)))
500 return FALSE;
501 break;
502 }
503 }
504 }
505
506 return TRUE;
507}
508#define ELF_ARCH bfd_arch_d10v
509#define ELF_MACHINE_CODE EM_D10V
510#define ELF_MACHINE_ALT1 EM_CYGNUS_D10V
511#define ELF_MAXPAGESIZE 0x1000
512
513#define TARGET_BIG_SYM bfd_elf32_d10v_vec
514#define TARGET_BIG_NAME "elf32-d10v"
515
516#define elf_info_to_howto 0
517#define elf_info_to_howto_rel d10v_info_to_howto_rel
518#define elf_backend_object_p 0
519#define elf_backend_final_write_processing 0
520#define elf_backend_gc_mark_hook elf32_d10v_gc_mark_hook
521#define elf_backend_gc_sweep_hook elf32_d10v_gc_sweep_hook
522#define elf_backend_check_relocs elf32_d10v_check_relocs
523#define elf_backend_relocate_section elf32_d10v_relocate_section
524#define elf_backend_can_gc_sections 1
525
526#include "elf32-target.h"
Note: See TracBrowser for help on using the repository browser.