PR 6526
[binutils.git] / bfd / elf32-dlx.c
blob69e7dc963bd0675f610f8363023529cd912a15c7
1 /* DLX specific support for 32-bit ELF
2 Copyright 2002, 2003, 2004, 2005, 2007
3 Free Software Foundation, Inc.
5 This file is part of BFD, the Binary File Descriptor library.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20 MA 02110-1301, USA. */
22 #include "sysdep.h"
23 #include "bfd.h"
24 #include "libbfd.h"
25 #include "elf-bfd.h"
26 #include "elf/dlx.h"
28 #define USE_REL 1
30 #define bfd_elf32_bfd_reloc_type_lookup elf32_dlx_reloc_type_lookup
31 #define bfd_elf32_bfd_reloc_name_lookup elf32_dlx_reloc_name_lookup
32 #define elf_info_to_howto elf32_dlx_info_to_howto
33 #define elf_info_to_howto_rel elf32_dlx_info_to_howto_rel
34 #define elf_backend_check_relocs elf32_dlx_check_relocs
36 /* The gas default behavior is not to preform the %hi modifier so that the
37 GNU assembler can have the lower 16 bits offset placed in the insn, BUT
38 we do like the gas to indicate it is %hi reloc type so when we in the link
39 loader phase we can have the corrected hi16 vale replace the buggous lo16
40 value that was placed there by gas. */
42 static int skip_dlx_elf_hi16_reloc = 0;
44 extern int set_dlx_skip_hi16_flag (int);
46 int
47 set_dlx_skip_hi16_flag (int flag)
49 skip_dlx_elf_hi16_reloc = flag;
50 return flag;
53 static bfd_reloc_status_type
54 _bfd_dlx_elf_hi16_reloc (bfd *abfd,
55 arelent *reloc_entry,
56 asymbol *symbol,
57 void * data,
58 asection *input_section,
59 bfd *output_bfd,
60 char **error_message)
62 bfd_reloc_status_type ret;
63 bfd_vma relocation;
65 /* If the skip flag is set then we simply do the generic relocating, this
66 is more of a hack for dlx gas/gld, so we do not need to do the %hi/%lo
67 fixup like mips gld did. */
68 if (skip_dlx_elf_hi16_reloc)
69 return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
70 input_section, output_bfd, error_message);
72 /* If we're relocating, and this an external symbol, we don't want
73 to change anything. */
74 if (output_bfd != (bfd *) NULL
75 && (symbol->flags & BSF_SECTION_SYM) == 0
76 && reloc_entry->addend == 0)
78 reloc_entry->address += input_section->output_offset;
79 return bfd_reloc_ok;
82 ret = bfd_reloc_ok;
84 if (bfd_is_und_section (symbol->section)
85 && output_bfd == (bfd *) NULL)
86 ret = bfd_reloc_undefined;
88 relocation = (bfd_is_com_section (symbol->section)) ? 0 : symbol->value;
89 relocation += symbol->section->output_section->vma;
90 relocation += symbol->section->output_offset;
91 relocation += reloc_entry->addend;
92 relocation += bfd_get_16 (abfd, (bfd_byte *)data + reloc_entry->address);
94 if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
95 return bfd_reloc_outofrange;
97 bfd_put_16 (abfd, (short)((relocation >> 16) & 0xFFFF),
98 (bfd_byte *)data + reloc_entry->address);
100 return ret;
103 /* ELF relocs are against symbols. If we are producing relocatable
104 output, and the reloc is against an external symbol, and nothing
105 has given us any additional addend, the resulting reloc will also
106 be against the same symbol. In such a case, we don't want to
107 change anything about the way the reloc is handled, since it will
108 all be done at final link time. Rather than put special case code
109 into bfd_perform_relocation, all the reloc types use this howto
110 function. It just short circuits the reloc if producing
111 relocatable output against an external symbol. */
113 static bfd_reloc_status_type
114 elf32_dlx_relocate16 (bfd *abfd,
115 arelent *reloc_entry,
116 asymbol *symbol,
117 void * data,
118 asection *input_section,
119 bfd *output_bfd,
120 char **error_message ATTRIBUTE_UNUSED)
122 unsigned long insn, vallo, allignment;
123 int val;
125 /* HACK: I think this first condition is necessary when producing
126 relocatable output. After the end of HACK, the code is identical
127 to bfd_elf_generic_reloc(). I would _guess_ the first change
128 belongs there rather than here. martindo 1998-10-23. */
130 if (skip_dlx_elf_hi16_reloc)
131 return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
132 input_section, output_bfd, error_message);
134 /* Check undefined section and undefined symbols. */
135 if (bfd_is_und_section (symbol->section)
136 && output_bfd == (bfd *) NULL)
137 return bfd_reloc_undefined;
139 /* Can not support a long jump to sections other then .text. */
140 if (strcmp (input_section->name, symbol->section->output_section->name) != 0)
142 fprintf (stderr,
143 "BFD Link Error: branch (PC rel16) to section (%s) not supported\n",
144 symbol->section->output_section->name);
145 return bfd_reloc_undefined;
148 insn = bfd_get_32 (abfd, (bfd_byte *)data + reloc_entry->address);
149 allignment = 1 << (input_section->output_section->alignment_power - 1);
150 vallo = insn & 0x0000FFFF;
152 if (vallo & 0x8000)
153 vallo = ~(vallo | 0xFFFF0000) + 1;
155 /* vallo points to the vma of next instruction. */
156 vallo += (((unsigned long)(input_section->output_section->vma +
157 input_section->output_offset) +
158 allignment) & ~allignment);
160 /* val is the displacement (PC relative to next instruction). */
161 val = (symbol->section->output_offset +
162 symbol->section->output_section->vma +
163 symbol->value) - vallo;
165 if (abs ((int) val) > 0x00007FFF)
166 return bfd_reloc_outofrange;
168 insn = (insn & 0xFFFF0000) | (val & 0x0000FFFF);
170 bfd_put_32 (abfd, insn,
171 (bfd_byte *) data + reloc_entry->address);
173 return bfd_reloc_ok;
176 static bfd_reloc_status_type
177 elf32_dlx_relocate26 (bfd *abfd,
178 arelent *reloc_entry,
179 asymbol *symbol,
180 void * data,
181 asection *input_section,
182 bfd *output_bfd,
183 char **error_message ATTRIBUTE_UNUSED)
185 unsigned long insn, vallo, allignment;
186 int val;
188 /* HACK: I think this first condition is necessary when producing
189 relocatable output. After the end of HACK, the code is identical
190 to bfd_elf_generic_reloc(). I would _guess_ the first change
191 belongs there rather than here. martindo 1998-10-23. */
193 if (skip_dlx_elf_hi16_reloc)
194 return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
195 input_section, output_bfd, error_message);
197 /* Check undefined section and undefined symbols. */
198 if (bfd_is_und_section (symbol->section)
199 && output_bfd == (bfd *) NULL)
200 return bfd_reloc_undefined;
202 /* Can not support a long jump to sections other then .text */
203 if (strcmp (input_section->name, symbol->section->output_section->name) != 0)
205 fprintf (stderr,
206 "BFD Link Error: jump (PC rel26) to section (%s) not supported\n",
207 symbol->section->output_section->name);
208 return bfd_reloc_undefined;
211 insn = bfd_get_32 (abfd, (bfd_byte *)data + reloc_entry->address);
212 allignment = 1 << (input_section->output_section->alignment_power - 1);
213 vallo = insn & 0x03FFFFFF;
215 if (vallo & 0x03000000)
216 vallo = ~(vallo | 0xFC000000) + 1;
218 /* vallo is the vma for the next instruction. */
219 vallo += (((unsigned long) (input_section->output_section->vma +
220 input_section->output_offset) +
221 allignment) & ~allignment);
223 /* val is the displacement (PC relative to next instruction). */
224 val = (symbol->section->output_offset +
225 symbol->section->output_section->vma + symbol->value)
226 - vallo;
228 if (abs ((int) val) > 0x01FFFFFF)
229 return bfd_reloc_outofrange;
231 insn = (insn & 0xFC000000) | (val & 0x03FFFFFF);
232 bfd_put_32 (abfd, insn,
233 (bfd_byte *) data + reloc_entry->address);
235 return bfd_reloc_ok;
238 static reloc_howto_type dlx_elf_howto_table[]=
240 /* No relocation. */
241 HOWTO (R_DLX_NONE, /* Type. */
242 0, /* Rightshift. */
243 0, /* size (0 = byte, 1 = short, 2 = long). */
244 0, /* Bitsize. */
245 FALSE, /* PC_relative. */
246 0, /* Bitpos. */
247 complain_overflow_dont,/* Complain_on_overflow. */
248 bfd_elf_generic_reloc, /* Special_function. */
249 "R_DLX_NONE", /* Name. */
250 FALSE, /* Partial_inplace. */
251 0, /* Src_mask. */
252 0, /* Dst_mask. */
253 FALSE), /* PCrel_offset. */
255 /* 8 bit relocation. */
256 HOWTO (R_DLX_RELOC_8, /* Type. */
257 0, /* Rightshift. */
258 0, /* Size (0 = byte, 1 = short, 2 = long). */
259 8, /* Bitsize. */
260 FALSE, /* PC_relative. */
261 0, /* Bitpos. */
262 complain_overflow_dont,/* Complain_on_overflow. */
263 bfd_elf_generic_reloc, /* Special_function. */
264 "R_DLX_RELOC_8", /* Name. */
265 TRUE, /* Partial_inplace. */
266 0xff, /* Src_mask. */
267 0xff, /* Dst_mask. */
268 FALSE), /* PCrel_offset. */
270 /* 16 bit relocation. */
271 HOWTO (R_DLX_RELOC_16, /* Type. */
272 0, /* Rightshift. */
273 1, /* Size (0 = byte, 1 = short, 2 = long). */
274 16, /* Bitsize. */
275 FALSE, /* PC_relative. */
276 0, /* Bitpos. */
277 complain_overflow_dont,/* Complain_on_overflow. */
278 bfd_elf_generic_reloc, /* Special_function. */
279 "R_DLX_RELOC_16", /* Name. */
280 TRUE, /* Partial_inplace. */
281 0xffff, /* Src_mask. */
282 0xffff, /* Dst_mask. */
283 FALSE), /* PCrel_offset. */
285 /* 32 bit relocation. */
286 HOWTO (R_DLX_RELOC_32, /* Type. */
287 0, /* Rightshift. */
288 2, /* Size (0 = byte, 1 = short, 2 = long). */
289 32, /* Bitsize. */
290 FALSE, /* PC_relative. */
291 0, /* Bitpos. */
292 complain_overflow_dont,/* Complain_on_overflow. */
293 bfd_elf_generic_reloc, /* Special_function. */
294 "R_DLX_RELOC_32", /* Name. */
295 TRUE, /* Partial_inplace. */
296 0xffffffff, /* Src_mask. */
297 0xffffffff, /* Dst_mask. */
298 FALSE), /* PCrel_offset. */
300 /* GNU extension to record C++ vtable hierarchy. */
301 HOWTO (R_DLX_GNU_VTINHERIT, /* Type. */
302 0, /* Rightshift. */
303 2, /* Size (0 = byte, 1 = short, 2 = long). */
304 0, /* Bitsize. */
305 FALSE, /* PC_relative. */
306 0, /* Bitpos. */
307 complain_overflow_dont,/* Complain_on_overflow. */
308 NULL, /* Special_function. */
309 "R_DLX_GNU_VTINHERIT", /* Name. */
310 FALSE, /* Partial_inplace. */
311 0, /* Src_mask. */
312 0, /* Dst_mask. */
313 FALSE), /* PCrel_offset. */
315 /* GNU extension to record C++ vtable member usage. */
316 HOWTO (R_DLX_GNU_VTENTRY, /* Type. */
317 0, /* Rightshift. */
318 2, /* Size (0 = byte, 1 = short, 2 = long). */
319 0, /* Bitsize. */
320 FALSE, /* PC_relative. */
321 0, /* Bitpos. */
322 complain_overflow_dont,/* Complain_on_overflow. */
323 _bfd_elf_rel_vtable_reloc_fn,/* Special_function. */
324 "R_DLX_GNU_VTENTRY", /* Name. */
325 FALSE, /* Partial_inplace. */
326 0, /* Src_mask. */
327 0, /* Dst_mask. */
328 FALSE) /* PCrel_offset. */
331 /* 16 bit offset for pc-relative branches. */
332 static reloc_howto_type elf_dlx_gnu_rel16_s2 =
333 HOWTO (R_DLX_RELOC_16_PCREL, /* Type. */
334 0, /* Rightshift. */
335 1, /* Size (0 = byte, 1 = short, 2 = long). */
336 16, /* Bitsize. */
337 TRUE, /* PC_relative. */
338 0, /* Bitpos. */
339 complain_overflow_signed, /* Complain_on_overflow. */
340 elf32_dlx_relocate16, /* Special_function. */
341 "R_DLX_RELOC_16_PCREL",/* Name. */
342 TRUE, /* Partial_inplace. */
343 0xffff, /* Src_mask. */
344 0xffff, /* Dst_mask. */
345 TRUE); /* PCrel_offset. */
347 /* 26 bit offset for pc-relative branches. */
348 static reloc_howto_type elf_dlx_gnu_rel26_s2 =
349 HOWTO (R_DLX_RELOC_26_PCREL, /* Type. */
350 0, /* Rightshift. */
351 2, /* Size (0 = byte, 1 = short, 2 = long). */
352 26, /* Bitsize. */
353 TRUE, /* PC_relative. */
354 0, /* Bitpos. */
355 complain_overflow_dont,/* Complain_on_overflow. */
356 elf32_dlx_relocate26, /* Special_function. */
357 "R_DLX_RELOC_26_PCREL",/* Name. */
358 TRUE, /* Partial_inplace. */
359 0xffff, /* Src_mask. */
360 0xffff, /* Dst_mask. */
361 TRUE); /* PCrel_offset. */
363 /* High 16 bits of symbol value. */
364 static reloc_howto_type elf_dlx_reloc_16_hi =
365 HOWTO (R_DLX_RELOC_16_HI, /* Type. */
366 16, /* Rightshift. */
367 2, /* Size (0 = byte, 1 = short, 2 = long). */
368 32, /* Bitsize. */
369 FALSE, /* PC_relative. */
370 0, /* Bitpos. */
371 complain_overflow_dont,/* Complain_on_overflow. */
372 _bfd_dlx_elf_hi16_reloc,/* Special_function. */
373 "R_DLX_RELOC_16_HI", /* Name. */
374 TRUE, /* Partial_inplace. */
375 0xFFFF, /* Src_mask. */
376 0xffff, /* Dst_mask. */
377 FALSE); /* PCrel_offset. */
379 /* Low 16 bits of symbol value. */
380 static reloc_howto_type elf_dlx_reloc_16_lo =
381 HOWTO (R_DLX_RELOC_16_LO, /* Type. */
382 0, /* Rightshift. */
383 1, /* Size (0 = byte, 1 = short, 2 = long). */
384 16, /* Bitsize. */
385 FALSE, /* PC_relative. */
386 0, /* Bitpos. */
387 complain_overflow_dont,/* Complain_on_overflow. */
388 bfd_elf_generic_reloc, /* Special_function. */
389 "R_DLX_RELOC_16_LO", /* Name. */
390 TRUE, /* Partial_inplace. */
391 0xffff, /* Src_mask. */
392 0xffff, /* Dst_mask. */
393 FALSE); /* PCrel_offset. */
395 /* A mapping from BFD reloc types to DLX ELF reloc types.
396 Stolen from elf32-mips.c.
398 More about this table - for dlx elf relocation we do not really
399 need this table, if we have a rtype defined in this table will
400 caused tc_gen_relocate confused and die on us, but if we remove
401 this table it will caused more problem, so for now simple solution
402 is to remove those entries which may cause problem. */
403 struct elf_reloc_map
405 bfd_reloc_code_real_type bfd_reloc_val;
406 enum elf_dlx_reloc_type elf_reloc_val;
409 static const struct elf_reloc_map dlx_reloc_map[] =
411 { BFD_RELOC_NONE, R_DLX_NONE },
412 { BFD_RELOC_16, R_DLX_RELOC_16 },
413 { BFD_RELOC_32, R_DLX_RELOC_32 },
414 { BFD_RELOC_DLX_HI16_S, R_DLX_RELOC_16_HI },
415 { BFD_RELOC_DLX_LO16, R_DLX_RELOC_16_LO },
416 { BFD_RELOC_VTABLE_INHERIT, R_DLX_GNU_VTINHERIT },
417 { BFD_RELOC_VTABLE_ENTRY, R_DLX_GNU_VTENTRY }
420 /* Look through the relocs for a section during the first phase.
421 Since we don't do .gots or .plts, we just need to consider the
422 virtual table relocs for gc. */
424 static bfd_boolean
425 elf32_dlx_check_relocs (bfd *abfd,
426 struct bfd_link_info *info,
427 asection *sec,
428 const Elf_Internal_Rela *relocs)
430 Elf_Internal_Shdr *symtab_hdr;
431 struct elf_link_hash_entry **sym_hashes;
432 const Elf_Internal_Rela *rel;
433 const Elf_Internal_Rela *rel_end;
435 if (info->relocatable)
436 return TRUE;
438 symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
439 sym_hashes = elf_sym_hashes (abfd);
441 rel_end = relocs + sec->reloc_count;
442 for (rel = relocs; rel < rel_end; rel++)
444 struct elf_link_hash_entry *h;
445 unsigned long r_symndx;
447 r_symndx = ELF32_R_SYM (rel->r_info);
448 if (r_symndx < symtab_hdr->sh_info)
449 h = NULL;
450 else
452 h = sym_hashes[r_symndx - symtab_hdr->sh_info];
453 while (h->root.type == bfd_link_hash_indirect
454 || h->root.type == bfd_link_hash_warning)
455 h = (struct elf_link_hash_entry *) h->root.u.i.link;
458 switch (ELF32_R_TYPE (rel->r_info))
460 /* This relocation describes the C++ object vtable hierarchy.
461 Reconstruct it for later use during GC. */
462 case R_DLX_GNU_VTINHERIT:
463 if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
464 return FALSE;
465 break;
467 /* This relocation describes which C++ vtable entries are actually
468 used. Record for later use during GC. */
469 case R_DLX_GNU_VTENTRY:
470 BFD_ASSERT (h != NULL);
471 if (h != NULL
472 && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
473 return FALSE;
474 break;
478 return TRUE;
481 /* Given a BFD reloc type, return a howto structure. */
483 static reloc_howto_type *
484 elf32_dlx_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
485 bfd_reloc_code_real_type code)
487 unsigned int i;
489 for (i = 0; i < sizeof (dlx_reloc_map) / sizeof (struct elf_reloc_map); i++)
490 if (dlx_reloc_map[i].bfd_reloc_val == code)
491 return &dlx_elf_howto_table[(int) dlx_reloc_map[i].elf_reloc_val];
493 switch (code)
495 default:
496 bfd_set_error (bfd_error_bad_value);
497 return NULL;
498 case BFD_RELOC_16_PCREL_S2:
499 return &elf_dlx_gnu_rel16_s2;
500 case BFD_RELOC_DLX_JMP26:
501 return &elf_dlx_gnu_rel26_s2;
502 case BFD_RELOC_HI16_S:
503 return &elf_dlx_reloc_16_hi;
504 case BFD_RELOC_LO16:
505 return &elf_dlx_reloc_16_lo;
509 static reloc_howto_type *
510 elf32_dlx_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
511 const char *r_name)
513 unsigned int i;
515 for (i = 0;
516 i < sizeof (dlx_elf_howto_table) / sizeof (dlx_elf_howto_table[0]);
517 i++)
518 if (dlx_elf_howto_table[i].name != NULL
519 && strcasecmp (dlx_elf_howto_table[i].name, r_name) == 0)
520 return &dlx_elf_howto_table[i];
522 if (strcasecmp (elf_dlx_gnu_rel16_s2.name, r_name) == 0)
523 return &elf_dlx_gnu_rel16_s2;
524 if (strcasecmp (elf_dlx_gnu_rel26_s2.name, r_name) == 0)
525 return &elf_dlx_gnu_rel26_s2;
526 if (strcasecmp (elf_dlx_reloc_16_hi.name, r_name) == 0)
527 return &elf_dlx_reloc_16_hi;
528 if (strcasecmp (elf_dlx_reloc_16_lo.name, r_name) == 0)
529 return &elf_dlx_reloc_16_lo;
531 return NULL;
534 static reloc_howto_type *
535 dlx_rtype_to_howto (unsigned int r_type)
537 switch (r_type)
539 case R_DLX_RELOC_16_PCREL:
540 return & elf_dlx_gnu_rel16_s2;
541 case R_DLX_RELOC_26_PCREL:
542 return & elf_dlx_gnu_rel26_s2;
543 case R_DLX_RELOC_16_HI:
544 return & elf_dlx_reloc_16_hi;
545 case R_DLX_RELOC_16_LO:
546 return & elf_dlx_reloc_16_lo;
547 default:
548 BFD_ASSERT (r_type < (unsigned int) R_DLX_max);
549 return & dlx_elf_howto_table[r_type];
553 static void
554 elf32_dlx_info_to_howto (bfd * abfd ATTRIBUTE_UNUSED,
555 arelent * cache_ptr ATTRIBUTE_UNUSED,
556 Elf_Internal_Rela * dst ATTRIBUTE_UNUSED)
558 abort ();
561 static void
562 elf32_dlx_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
563 arelent *cache_ptr,
564 Elf_Internal_Rela *dst)
566 unsigned int r_type;
568 r_type = ELF32_R_TYPE (dst->r_info);
569 cache_ptr->howto = dlx_rtype_to_howto (r_type);
570 return;
573 #define TARGET_BIG_SYM bfd_elf32_dlx_big_vec
574 #define TARGET_BIG_NAME "elf32-dlx"
575 #define ELF_ARCH bfd_arch_dlx
576 #define ELF_MACHINE_CODE EM_DLX
577 #define ELF_MAXPAGESIZE 1 /* FIXME: This number is wrong, It should be the page size in bytes. */
579 #include "elf32-target.h"