* windres/windres.exp: Return unsupported rather than fail if
[binutils.git] / bfd / elf32-dlx.c
blobeebacebe865bcbfdd3af9548bbd721c27e2eedf5
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, **sym_hashes_end;
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);
440 sym_hashes_end = sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
441 if (!elf_bad_symtab (abfd))
442 sym_hashes_end -= symtab_hdr->sh_info;
444 rel_end = relocs + sec->reloc_count;
445 for (rel = relocs; rel < rel_end; rel++)
447 struct elf_link_hash_entry *h;
448 unsigned long r_symndx;
450 r_symndx = ELF32_R_SYM (rel->r_info);
451 if (r_symndx < symtab_hdr->sh_info)
452 h = NULL;
453 else
455 h = sym_hashes[r_symndx - symtab_hdr->sh_info];
456 while (h->root.type == bfd_link_hash_indirect
457 || h->root.type == bfd_link_hash_warning)
458 h = (struct elf_link_hash_entry *) h->root.u.i.link;
461 switch (ELF32_R_TYPE (rel->r_info))
463 /* This relocation describes the C++ object vtable hierarchy.
464 Reconstruct it for later use during GC. */
465 case R_DLX_GNU_VTINHERIT:
466 if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
467 return FALSE;
468 break;
470 /* This relocation describes which C++ vtable entries are actually
471 used. Record for later use during GC. */
472 case R_DLX_GNU_VTENTRY:
473 if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
474 return FALSE;
475 break;
479 return TRUE;
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)
488 unsigned int i;
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];
494 switch (code)
496 default:
497 bfd_set_error (bfd_error_bad_value);
498 return NULL;
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;
505 case BFD_RELOC_LO16:
506 return &elf_dlx_reloc_16_lo;
510 static reloc_howto_type *
511 elf32_dlx_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
512 const char *r_name)
514 unsigned int i;
516 for (i = 0;
517 i < sizeof (dlx_elf_howto_table) / sizeof (dlx_elf_howto_table[0]);
518 i++)
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;
532 return NULL;
535 static reloc_howto_type *
536 dlx_rtype_to_howto (unsigned int r_type)
538 switch (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;
548 default:
549 BFD_ASSERT (r_type < (unsigned int) R_DLX_max);
550 return & dlx_elf_howto_table[r_type];
554 static void
555 elf32_dlx_info_to_howto (bfd * abfd ATTRIBUTE_UNUSED,
556 arelent * cache_ptr ATTRIBUTE_UNUSED,
557 Elf_Internal_Rela * dst ATTRIBUTE_UNUSED)
559 abort ();
562 static void
563 elf32_dlx_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
564 arelent *cache_ptr,
565 Elf_Internal_Rela *dst)
567 unsigned int r_type;
569 r_type = ELF32_R_TYPE (dst->r_info);
570 cache_ptr->howto = dlx_rtype_to_howto (r_type);
571 return;
574 #define TARGET_BIG_SYM bfd_elf32_dlx_big_vec
575 #define TARGET_BIG_NAME "elf32-dlx"
576 #define ELF_ARCH bfd_arch_dlx
577 #define ELF_MACHINE_CODE EM_DLX
578 #define ELF_MAXPAGESIZE 1 /* FIXME: This number is wrong, It should be the page size in bytes. */
580 #include "elf32-target.h"