1 /* DLX specific support for 32-bit ELF
2 Copyright (C) 2002-2015 Free Software Foundation, Inc.
4 This file is part of BFD, the Binary File Descriptor library.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
29 #define bfd_elf32_bfd_reloc_type_lookup elf32_dlx_reloc_type_lookup
30 #define bfd_elf32_bfd_reloc_name_lookup elf32_dlx_reloc_name_lookup
31 #define elf_info_to_howto elf32_dlx_info_to_howto
32 #define elf_info_to_howto_rel elf32_dlx_info_to_howto_rel
33 #define elf_backend_check_relocs elf32_dlx_check_relocs
35 /* The gas default behavior is not to preform the %hi modifier so that the
36 GNU assembler can have the lower 16 bits offset placed in the insn, BUT
37 we do like the gas to indicate it is %hi reloc type so when we in the link
38 loader phase we can have the corrected hi16 vale replace the buggous lo16
39 value that was placed there by gas. */
41 static int skip_dlx_elf_hi16_reloc = 0;
43 extern int set_dlx_skip_hi16_flag (int);
46 set_dlx_skip_hi16_flag (int flag)
48 skip_dlx_elf_hi16_reloc = flag;
52 static bfd_reloc_status_type
53 _bfd_dlx_elf_hi16_reloc (bfd *abfd,
57 asection *input_section,
61 bfd_reloc_status_type ret;
64 /* If the skip flag is set then we simply do the generic relocating, this
65 is more of a hack for dlx gas/gld, so we do not need to do the %hi/%lo
66 fixup like mips gld did. */
67 if (skip_dlx_elf_hi16_reloc)
68 return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
69 input_section, output_bfd, error_message);
71 /* If we're relocating, and this an external symbol, we don't want
72 to change anything. */
73 if (output_bfd != (bfd *) NULL
74 && (symbol->flags & BSF_SECTION_SYM) == 0
75 && reloc_entry->addend == 0)
77 reloc_entry->address += input_section->output_offset;
83 if (bfd_is_und_section (symbol->section)
84 && output_bfd == (bfd *) NULL)
85 ret = bfd_reloc_undefined;
87 relocation = (bfd_is_com_section (symbol->section)) ? 0 : symbol->value;
88 relocation += symbol->section->output_section->vma;
89 relocation += symbol->section->output_offset;
90 relocation += reloc_entry->addend;
91 relocation += bfd_get_16 (abfd, (bfd_byte *)data + reloc_entry->address);
93 if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
94 return bfd_reloc_outofrange;
96 bfd_put_16 (abfd, (short)((relocation >> 16) & 0xFFFF),
97 (bfd_byte *)data + reloc_entry->address);
102 /* ELF relocs are against symbols. If we are producing relocatable
103 output, and the reloc is against an external symbol, and nothing
104 has given us any additional addend, the resulting reloc will also
105 be against the same symbol. In such a case, we don't want to
106 change anything about the way the reloc is handled, since it will
107 all be done at final link time. Rather than put special case code
108 into bfd_perform_relocation, all the reloc types use this howto
109 function. It just short circuits the reloc if producing
110 relocatable output against an external symbol. */
112 static bfd_reloc_status_type
113 elf32_dlx_relocate16 (bfd *abfd,
114 arelent *reloc_entry,
117 asection *input_section,
119 char **error_message ATTRIBUTE_UNUSED)
121 unsigned long insn, vallo, allignment;
124 /* HACK: I think this first condition is necessary when producing
125 relocatable output. After the end of HACK, the code is identical
126 to bfd_elf_generic_reloc(). I would _guess_ the first change
127 belongs there rather than here. martindo 1998-10-23. */
129 if (skip_dlx_elf_hi16_reloc)
130 return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
131 input_section, output_bfd, error_message);
133 /* Check undefined section and undefined symbols. */
134 if (bfd_is_und_section (symbol->section)
135 && output_bfd == (bfd *) NULL)
136 return bfd_reloc_undefined;
138 /* Can not support a long jump to sections other then .text. */
139 if (strcmp (input_section->name, symbol->section->output_section->name) != 0)
141 (*_bfd_error_handler) (_("BFD Link Error: branch (PC rel16) to section (%s) not supported"),
142 symbol->section->output_section->name);
143 return bfd_reloc_undefined;
146 insn = bfd_get_32 (abfd, (bfd_byte *)data + reloc_entry->address);
147 allignment = 1 << (input_section->output_section->alignment_power - 1);
148 vallo = insn & 0x0000FFFF;
151 vallo = ~(vallo | 0xFFFF0000) + 1;
153 /* vallo points to the vma of next instruction. */
154 vallo += (((unsigned long)(input_section->output_section->vma +
155 input_section->output_offset) +
156 allignment) & ~allignment);
158 /* val is the displacement (PC relative to next instruction). */
159 val = (symbol->section->output_offset +
160 symbol->section->output_section->vma +
161 symbol->value) - vallo;
163 if (abs ((int) val) > 0x00007FFF)
164 return bfd_reloc_outofrange;
166 insn = (insn & 0xFFFF0000) | (val & 0x0000FFFF);
168 bfd_put_32 (abfd, insn,
169 (bfd_byte *) data + reloc_entry->address);
174 static bfd_reloc_status_type
175 elf32_dlx_relocate26 (bfd *abfd,
176 arelent *reloc_entry,
179 asection *input_section,
181 char **error_message ATTRIBUTE_UNUSED)
183 unsigned long insn, vallo, allignment;
186 /* HACK: I think this first condition is necessary when producing
187 relocatable output. After the end of HACK, the code is identical
188 to bfd_elf_generic_reloc(). I would _guess_ the first change
189 belongs there rather than here. martindo 1998-10-23. */
191 if (skip_dlx_elf_hi16_reloc)
192 return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
193 input_section, output_bfd, error_message);
195 /* Check undefined section and undefined symbols. */
196 if (bfd_is_und_section (symbol->section)
197 && output_bfd == (bfd *) NULL)
198 return bfd_reloc_undefined;
200 /* Can not support a long jump to sections other then .text */
201 if (strcmp (input_section->name, symbol->section->output_section->name) != 0)
203 (*_bfd_error_handler) (_("BFD Link Error: jump (PC rel26) to section (%s) not supported"),
204 symbol->section->output_section->name);
205 return bfd_reloc_undefined;
208 insn = bfd_get_32 (abfd, (bfd_byte *)data + reloc_entry->address);
209 allignment = 1 << (input_section->output_section->alignment_power - 1);
210 vallo = insn & 0x03FFFFFF;
212 if (vallo & 0x03000000)
213 vallo = ~(vallo | 0xFC000000) + 1;
215 /* vallo is the vma for the next instruction. */
216 vallo += (((unsigned long) (input_section->output_section->vma +
217 input_section->output_offset) +
218 allignment) & ~allignment);
220 /* val is the displacement (PC relative to next instruction). */
221 val = (symbol->section->output_offset +
222 symbol->section->output_section->vma + symbol->value)
225 if (abs ((int) val) > 0x01FFFFFF)
226 return bfd_reloc_outofrange;
228 insn = (insn & 0xFC000000) | (val & 0x03FFFFFF);
229 bfd_put_32 (abfd, insn,
230 (bfd_byte *) data + reloc_entry->address);
235 static reloc_howto_type dlx_elf_howto_table[]=
238 HOWTO (R_DLX_NONE, /* Type. */
240 3, /* size (0 = byte, 1 = short, 2 = long). */
242 FALSE, /* PC_relative. */
244 complain_overflow_dont,/* Complain_on_overflow. */
245 bfd_elf_generic_reloc, /* Special_function. */
246 "R_DLX_NONE", /* Name. */
247 FALSE, /* Partial_inplace. */
250 FALSE), /* PCrel_offset. */
252 /* 8 bit relocation. */
253 HOWTO (R_DLX_RELOC_8, /* Type. */
255 0, /* Size (0 = byte, 1 = short, 2 = long). */
257 FALSE, /* PC_relative. */
259 complain_overflow_dont,/* Complain_on_overflow. */
260 bfd_elf_generic_reloc, /* Special_function. */
261 "R_DLX_RELOC_8", /* Name. */
262 TRUE, /* Partial_inplace. */
263 0xff, /* Src_mask. */
264 0xff, /* Dst_mask. */
265 FALSE), /* PCrel_offset. */
267 /* 16 bit relocation. */
268 HOWTO (R_DLX_RELOC_16, /* Type. */
270 1, /* Size (0 = byte, 1 = short, 2 = long). */
272 FALSE, /* PC_relative. */
274 complain_overflow_dont,/* Complain_on_overflow. */
275 bfd_elf_generic_reloc, /* Special_function. */
276 "R_DLX_RELOC_16", /* Name. */
277 TRUE, /* Partial_inplace. */
278 0xffff, /* Src_mask. */
279 0xffff, /* Dst_mask. */
280 FALSE), /* PCrel_offset. */
282 /* 32 bit relocation. */
283 HOWTO (R_DLX_RELOC_32, /* Type. */
285 2, /* Size (0 = byte, 1 = short, 2 = long). */
287 FALSE, /* PC_relative. */
289 complain_overflow_dont,/* Complain_on_overflow. */
290 bfd_elf_generic_reloc, /* Special_function. */
291 "R_DLX_RELOC_32", /* Name. */
292 TRUE, /* Partial_inplace. */
293 0xffffffff, /* Src_mask. */
294 0xffffffff, /* Dst_mask. */
295 FALSE), /* PCrel_offset. */
297 /* GNU extension to record C++ vtable hierarchy. */
298 HOWTO (R_DLX_GNU_VTINHERIT, /* Type. */
300 2, /* Size (0 = byte, 1 = short, 2 = long). */
302 FALSE, /* PC_relative. */
304 complain_overflow_dont,/* Complain_on_overflow. */
305 NULL, /* Special_function. */
306 "R_DLX_GNU_VTINHERIT", /* Name. */
307 FALSE, /* Partial_inplace. */
310 FALSE), /* PCrel_offset. */
312 /* GNU extension to record C++ vtable member usage. */
313 HOWTO (R_DLX_GNU_VTENTRY, /* Type. */
315 2, /* Size (0 = byte, 1 = short, 2 = long). */
317 FALSE, /* PC_relative. */
319 complain_overflow_dont,/* Complain_on_overflow. */
320 _bfd_elf_rel_vtable_reloc_fn,/* Special_function. */
321 "R_DLX_GNU_VTENTRY", /* Name. */
322 FALSE, /* Partial_inplace. */
325 FALSE) /* PCrel_offset. */
328 /* 16 bit offset for pc-relative branches. */
329 static reloc_howto_type elf_dlx_gnu_rel16_s2 =
330 HOWTO (R_DLX_RELOC_16_PCREL, /* Type. */
332 1, /* Size (0 = byte, 1 = short, 2 = long). */
334 TRUE, /* PC_relative. */
336 complain_overflow_signed, /* Complain_on_overflow. */
337 elf32_dlx_relocate16, /* Special_function. */
338 "R_DLX_RELOC_16_PCREL",/* Name. */
339 TRUE, /* Partial_inplace. */
340 0xffff, /* Src_mask. */
341 0xffff, /* Dst_mask. */
342 TRUE); /* PCrel_offset. */
344 /* 26 bit offset for pc-relative branches. */
345 static reloc_howto_type elf_dlx_gnu_rel26_s2 =
346 HOWTO (R_DLX_RELOC_26_PCREL, /* Type. */
348 2, /* Size (0 = byte, 1 = short, 2 = long). */
350 TRUE, /* PC_relative. */
352 complain_overflow_dont,/* Complain_on_overflow. */
353 elf32_dlx_relocate26, /* Special_function. */
354 "R_DLX_RELOC_26_PCREL",/* Name. */
355 TRUE, /* Partial_inplace. */
356 0xffff, /* Src_mask. */
357 0xffff, /* Dst_mask. */
358 TRUE); /* PCrel_offset. */
360 /* High 16 bits of symbol value. */
361 static reloc_howto_type elf_dlx_reloc_16_hi =
362 HOWTO (R_DLX_RELOC_16_HI, /* Type. */
363 16, /* Rightshift. */
364 2, /* Size (0 = byte, 1 = short, 2 = long). */
366 FALSE, /* PC_relative. */
368 complain_overflow_dont,/* Complain_on_overflow. */
369 _bfd_dlx_elf_hi16_reloc,/* Special_function. */
370 "R_DLX_RELOC_16_HI", /* Name. */
371 TRUE, /* Partial_inplace. */
372 0xFFFF, /* Src_mask. */
373 0xffff, /* Dst_mask. */
374 FALSE); /* PCrel_offset. */
376 /* Low 16 bits of symbol value. */
377 static reloc_howto_type elf_dlx_reloc_16_lo =
378 HOWTO (R_DLX_RELOC_16_LO, /* Type. */
380 1, /* Size (0 = byte, 1 = short, 2 = long). */
382 FALSE, /* PC_relative. */
384 complain_overflow_dont,/* Complain_on_overflow. */
385 bfd_elf_generic_reloc, /* Special_function. */
386 "R_DLX_RELOC_16_LO", /* Name. */
387 TRUE, /* Partial_inplace. */
388 0xffff, /* Src_mask. */
389 0xffff, /* Dst_mask. */
390 FALSE); /* PCrel_offset. */
392 /* A mapping from BFD reloc types to DLX ELF reloc types.
393 Stolen from elf32-mips.c.
395 More about this table - for dlx elf relocation we do not really
396 need this table, if we have a rtype defined in this table will
397 caused tc_gen_relocate confused and die on us, but if we remove
398 this table it will caused more problem, so for now simple solution
399 is to remove those entries which may cause problem. */
402 bfd_reloc_code_real_type bfd_reloc_val;
403 enum elf_dlx_reloc_type elf_reloc_val;
406 static const struct elf_reloc_map dlx_reloc_map[] =
408 { BFD_RELOC_NONE, R_DLX_NONE },
409 { BFD_RELOC_16, R_DLX_RELOC_16 },
410 { BFD_RELOC_32, R_DLX_RELOC_32 },
411 { BFD_RELOC_DLX_HI16_S, R_DLX_RELOC_16_HI },
412 { BFD_RELOC_DLX_LO16, R_DLX_RELOC_16_LO },
413 { BFD_RELOC_VTABLE_INHERIT, R_DLX_GNU_VTINHERIT },
414 { BFD_RELOC_VTABLE_ENTRY, R_DLX_GNU_VTENTRY }
417 /* Look through the relocs for a section during the first phase.
418 Since we don't do .gots or .plts, we just need to consider the
419 virtual table relocs for gc. */
422 elf32_dlx_check_relocs (bfd *abfd,
423 struct bfd_link_info *info,
425 const Elf_Internal_Rela *relocs)
427 Elf_Internal_Shdr *symtab_hdr;
428 struct elf_link_hash_entry **sym_hashes;
429 const Elf_Internal_Rela *rel;
430 const Elf_Internal_Rela *rel_end;
432 if (info->relocatable)
435 symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
436 sym_hashes = elf_sym_hashes (abfd);
438 rel_end = relocs + sec->reloc_count;
439 for (rel = relocs; rel < rel_end; rel++)
441 struct elf_link_hash_entry *h;
442 unsigned long r_symndx;
444 r_symndx = ELF32_R_SYM (rel->r_info);
445 if (r_symndx < symtab_hdr->sh_info)
449 h = sym_hashes[r_symndx - symtab_hdr->sh_info];
450 while (h->root.type == bfd_link_hash_indirect
451 || h->root.type == bfd_link_hash_warning)
452 h = (struct elf_link_hash_entry *) h->root.u.i.link;
454 /* PR15323, ref flags aren't set for references in the same
456 h->root.non_ir_ref = 1;
459 switch (ELF32_R_TYPE (rel->r_info))
461 /* This relocation describes the C++ object vtable hierarchy.
462 Reconstruct it for later use during GC. */
463 case R_DLX_GNU_VTINHERIT:
464 if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
468 /* This relocation describes which C++ vtable entries are actually
469 used. Record for later use during GC. */
470 case R_DLX_GNU_VTENTRY:
471 BFD_ASSERT (h != NULL);
473 && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
482 /* Given a BFD reloc type, return a howto structure. */
484 static reloc_howto_type *
485 elf32_dlx_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
486 bfd_reloc_code_real_type code)
490 for (i = 0; i < sizeof (dlx_reloc_map) / sizeof (struct elf_reloc_map); i++)
491 if (dlx_reloc_map[i].bfd_reloc_val == code)
492 return &dlx_elf_howto_table[(int) dlx_reloc_map[i].elf_reloc_val];
497 bfd_set_error (bfd_error_bad_value);
499 case BFD_RELOC_16_PCREL_S2:
500 return &elf_dlx_gnu_rel16_s2;
501 case BFD_RELOC_DLX_JMP26:
502 return &elf_dlx_gnu_rel26_s2;
503 case BFD_RELOC_HI16_S:
504 return &elf_dlx_reloc_16_hi;
506 return &elf_dlx_reloc_16_lo;
510 static reloc_howto_type *
511 elf32_dlx_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
517 i < sizeof (dlx_elf_howto_table) / sizeof (dlx_elf_howto_table[0]);
519 if (dlx_elf_howto_table[i].name != NULL
520 && strcasecmp (dlx_elf_howto_table[i].name, r_name) == 0)
521 return &dlx_elf_howto_table[i];
523 if (strcasecmp (elf_dlx_gnu_rel16_s2.name, r_name) == 0)
524 return &elf_dlx_gnu_rel16_s2;
525 if (strcasecmp (elf_dlx_gnu_rel26_s2.name, r_name) == 0)
526 return &elf_dlx_gnu_rel26_s2;
527 if (strcasecmp (elf_dlx_reloc_16_hi.name, r_name) == 0)
528 return &elf_dlx_reloc_16_hi;
529 if (strcasecmp (elf_dlx_reloc_16_lo.name, r_name) == 0)
530 return &elf_dlx_reloc_16_lo;
535 static reloc_howto_type *
536 dlx_rtype_to_howto (unsigned int r_type)
540 case R_DLX_RELOC_16_PCREL:
541 return & elf_dlx_gnu_rel16_s2;
542 case R_DLX_RELOC_26_PCREL:
543 return & elf_dlx_gnu_rel26_s2;
544 case R_DLX_RELOC_16_HI:
545 return & elf_dlx_reloc_16_hi;
546 case R_DLX_RELOC_16_LO:
547 return & elf_dlx_reloc_16_lo;
549 if (r_type >= (unsigned int) R_DLX_max)
551 _bfd_error_handler (_("Invalid DLX reloc number: %d"), r_type);
554 return & dlx_elf_howto_table[r_type];
559 elf32_dlx_info_to_howto (bfd * abfd ATTRIBUTE_UNUSED,
560 arelent * cache_ptr ATTRIBUTE_UNUSED,
561 Elf_Internal_Rela * dst ATTRIBUTE_UNUSED)
567 elf32_dlx_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
569 Elf_Internal_Rela *dst)
573 r_type = ELF32_R_TYPE (dst->r_info);
574 cache_ptr->howto = dlx_rtype_to_howto (r_type);
578 #define TARGET_BIG_SYM dlx_elf32_be_vec
579 #define TARGET_BIG_NAME "elf32-dlx"
580 #define ELF_ARCH bfd_arch_dlx
581 #define ELF_MACHINE_CODE EM_DLX
582 #define ELF_MAXPAGESIZE 1 /* FIXME: This number is wrong, It should be the page size in bytes. */
584 #include "elf32-target.h"