Add output_type to bfd_link_info
[deliverable/binutils-gdb.git] / bfd / elf32-dlx.c
1 /* DLX specific support for 32-bit ELF
2 Copyright (C) 2002-2015 Free Software Foundation, Inc.
3
4 This file is part of BFD, the Binary File Descriptor library.
5
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.
10
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.
15
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. */
20
21 #include "sysdep.h"
22 #include "bfd.h"
23 #include "libbfd.h"
24 #include "elf-bfd.h"
25 #include "elf/dlx.h"
26
27 #define USE_REL 1
28
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
34
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. */
40
41 static int skip_dlx_elf_hi16_reloc = 0;
42
43 extern int set_dlx_skip_hi16_flag (int);
44
45 int
46 set_dlx_skip_hi16_flag (int flag)
47 {
48 skip_dlx_elf_hi16_reloc = flag;
49 return flag;
50 }
51
52 static bfd_reloc_status_type
53 _bfd_dlx_elf_hi16_reloc (bfd *abfd,
54 arelent *reloc_entry,
55 asymbol *symbol,
56 void * data,
57 asection *input_section,
58 bfd *output_bfd,
59 char **error_message)
60 {
61 bfd_reloc_status_type ret;
62 bfd_vma relocation;
63
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);
70
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)
76 {
77 reloc_entry->address += input_section->output_offset;
78 return bfd_reloc_ok;
79 }
80
81 ret = bfd_reloc_ok;
82
83 if (bfd_is_und_section (symbol->section)
84 && output_bfd == (bfd *) NULL)
85 ret = bfd_reloc_undefined;
86
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);
92
93 if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
94 return bfd_reloc_outofrange;
95
96 bfd_put_16 (abfd, (short)((relocation >> 16) & 0xFFFF),
97 (bfd_byte *)data + reloc_entry->address);
98
99 return ret;
100 }
101
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. */
111
112 static bfd_reloc_status_type
113 elf32_dlx_relocate16 (bfd *abfd,
114 arelent *reloc_entry,
115 asymbol *symbol,
116 void * data,
117 asection *input_section,
118 bfd *output_bfd,
119 char **error_message ATTRIBUTE_UNUSED)
120 {
121 unsigned long insn, vallo, allignment;
122 int val;
123
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. */
128
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);
132
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;
137
138 /* Can not support a long jump to sections other then .text. */
139 if (strcmp (input_section->name, symbol->section->output_section->name) != 0)
140 {
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;
144 }
145
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;
149
150 if (vallo & 0x8000)
151 vallo = ~(vallo | 0xFFFF0000) + 1;
152
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);
157
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;
162
163 if (abs ((int) val) > 0x00007FFF)
164 return bfd_reloc_outofrange;
165
166 insn = (insn & 0xFFFF0000) | (val & 0x0000FFFF);
167
168 bfd_put_32 (abfd, insn,
169 (bfd_byte *) data + reloc_entry->address);
170
171 return bfd_reloc_ok;
172 }
173
174 static bfd_reloc_status_type
175 elf32_dlx_relocate26 (bfd *abfd,
176 arelent *reloc_entry,
177 asymbol *symbol,
178 void * data,
179 asection *input_section,
180 bfd *output_bfd,
181 char **error_message ATTRIBUTE_UNUSED)
182 {
183 unsigned long insn, vallo, allignment;
184 int val;
185
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. */
190
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);
194
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;
199
200 /* Can not support a long jump to sections other then .text */
201 if (strcmp (input_section->name, symbol->section->output_section->name) != 0)
202 {
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;
206 }
207
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;
211
212 if (vallo & 0x03000000)
213 vallo = ~(vallo | 0xFC000000) + 1;
214
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);
219
220 /* val is the displacement (PC relative to next instruction). */
221 val = (symbol->section->output_offset +
222 symbol->section->output_section->vma + symbol->value)
223 - vallo;
224
225 if (abs ((int) val) > 0x01FFFFFF)
226 return bfd_reloc_outofrange;
227
228 insn = (insn & 0xFC000000) | (val & 0x03FFFFFF);
229 bfd_put_32 (abfd, insn,
230 (bfd_byte *) data + reloc_entry->address);
231
232 return bfd_reloc_ok;
233 }
234
235 static reloc_howto_type dlx_elf_howto_table[]=
236 {
237 /* No relocation. */
238 HOWTO (R_DLX_NONE, /* Type. */
239 0, /* Rightshift. */
240 3, /* size (0 = byte, 1 = short, 2 = long). */
241 0, /* Bitsize. */
242 FALSE, /* PC_relative. */
243 0, /* Bitpos. */
244 complain_overflow_dont,/* Complain_on_overflow. */
245 bfd_elf_generic_reloc, /* Special_function. */
246 "R_DLX_NONE", /* Name. */
247 FALSE, /* Partial_inplace. */
248 0, /* Src_mask. */
249 0, /* Dst_mask. */
250 FALSE), /* PCrel_offset. */
251
252 /* 8 bit relocation. */
253 HOWTO (R_DLX_RELOC_8, /* Type. */
254 0, /* Rightshift. */
255 0, /* Size (0 = byte, 1 = short, 2 = long). */
256 8, /* Bitsize. */
257 FALSE, /* PC_relative. */
258 0, /* Bitpos. */
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. */
266
267 /* 16 bit relocation. */
268 HOWTO (R_DLX_RELOC_16, /* Type. */
269 0, /* Rightshift. */
270 1, /* Size (0 = byte, 1 = short, 2 = long). */
271 16, /* Bitsize. */
272 FALSE, /* PC_relative. */
273 0, /* Bitpos. */
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. */
281
282 /* 32 bit relocation. */
283 HOWTO (R_DLX_RELOC_32, /* Type. */
284 0, /* Rightshift. */
285 2, /* Size (0 = byte, 1 = short, 2 = long). */
286 32, /* Bitsize. */
287 FALSE, /* PC_relative. */
288 0, /* Bitpos. */
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. */
296
297 /* GNU extension to record C++ vtable hierarchy. */
298 HOWTO (R_DLX_GNU_VTINHERIT, /* Type. */
299 0, /* Rightshift. */
300 2, /* Size (0 = byte, 1 = short, 2 = long). */
301 0, /* Bitsize. */
302 FALSE, /* PC_relative. */
303 0, /* Bitpos. */
304 complain_overflow_dont,/* Complain_on_overflow. */
305 NULL, /* Special_function. */
306 "R_DLX_GNU_VTINHERIT", /* Name. */
307 FALSE, /* Partial_inplace. */
308 0, /* Src_mask. */
309 0, /* Dst_mask. */
310 FALSE), /* PCrel_offset. */
311
312 /* GNU extension to record C++ vtable member usage. */
313 HOWTO (R_DLX_GNU_VTENTRY, /* Type. */
314 0, /* Rightshift. */
315 2, /* Size (0 = byte, 1 = short, 2 = long). */
316 0, /* Bitsize. */
317 FALSE, /* PC_relative. */
318 0, /* Bitpos. */
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. */
323 0, /* Src_mask. */
324 0, /* Dst_mask. */
325 FALSE) /* PCrel_offset. */
326 };
327
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. */
331 0, /* Rightshift. */
332 1, /* Size (0 = byte, 1 = short, 2 = long). */
333 16, /* Bitsize. */
334 TRUE, /* PC_relative. */
335 0, /* Bitpos. */
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. */
343
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. */
347 0, /* Rightshift. */
348 2, /* Size (0 = byte, 1 = short, 2 = long). */
349 26, /* Bitsize. */
350 TRUE, /* PC_relative. */
351 0, /* Bitpos. */
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. */
359
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). */
365 32, /* Bitsize. */
366 FALSE, /* PC_relative. */
367 0, /* Bitpos. */
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. */
375
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. */
379 0, /* Rightshift. */
380 1, /* Size (0 = byte, 1 = short, 2 = long). */
381 16, /* Bitsize. */
382 FALSE, /* PC_relative. */
383 0, /* Bitpos. */
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. */
391
392 /* A mapping from BFD reloc types to DLX ELF reloc types.
393 Stolen from elf32-mips.c.
394
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. */
400 struct elf_reloc_map
401 {
402 bfd_reloc_code_real_type bfd_reloc_val;
403 enum elf_dlx_reloc_type elf_reloc_val;
404 };
405
406 static const struct elf_reloc_map dlx_reloc_map[] =
407 {
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 }
415 };
416
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. */
420
421 static bfd_boolean
422 elf32_dlx_check_relocs (bfd *abfd,
423 struct bfd_link_info *info,
424 asection *sec,
425 const Elf_Internal_Rela *relocs)
426 {
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;
431
432 if (bfd_link_relocatable (info))
433 return TRUE;
434
435 symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
436 sym_hashes = elf_sym_hashes (abfd);
437
438 rel_end = relocs + sec->reloc_count;
439 for (rel = relocs; rel < rel_end; rel++)
440 {
441 struct elf_link_hash_entry *h;
442 unsigned long r_symndx;
443
444 r_symndx = ELF32_R_SYM (rel->r_info);
445 if (r_symndx < symtab_hdr->sh_info)
446 h = NULL;
447 else
448 {
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;
453
454 /* PR15323, ref flags aren't set for references in the same
455 object. */
456 h->root.non_ir_ref = 1;
457 }
458
459 switch (ELF32_R_TYPE (rel->r_info))
460 {
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))
465 return FALSE;
466 break;
467
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);
472 if (h != NULL
473 && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
474 return FALSE;
475 break;
476 }
477 }
478
479 return TRUE;
480 }
481
482 /* Given a BFD reloc type, return a howto structure. */
483
484 static reloc_howto_type *
485 elf32_dlx_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
486 bfd_reloc_code_real_type code)
487 {
488 unsigned int i;
489
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];
493
494 switch (code)
495 {
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;
507 }
508 }
509
510 static reloc_howto_type *
511 elf32_dlx_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
512 const char *r_name)
513 {
514 unsigned int i;
515
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];
522
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;
531
532 return NULL;
533 }
534
535 static reloc_howto_type *
536 dlx_rtype_to_howto (unsigned int r_type)
537 {
538 switch (r_type)
539 {
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 if (r_type >= (unsigned int) R_DLX_max)
550 {
551 _bfd_error_handler (_("Invalid DLX reloc number: %d"), r_type);
552 r_type = 0;
553 }
554 return & dlx_elf_howto_table[r_type];
555 }
556 }
557
558 static void
559 elf32_dlx_info_to_howto (bfd * abfd ATTRIBUTE_UNUSED,
560 arelent * cache_ptr ATTRIBUTE_UNUSED,
561 Elf_Internal_Rela * dst ATTRIBUTE_UNUSED)
562 {
563 abort ();
564 }
565
566 static void
567 elf32_dlx_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
568 arelent *cache_ptr,
569 Elf_Internal_Rela *dst)
570 {
571 unsigned int r_type;
572
573 r_type = ELF32_R_TYPE (dst->r_info);
574 cache_ptr->howto = dlx_rtype_to_howto (r_type);
575 return;
576 }
577
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. */
583
584 #include "elf32-target.h"
This page took 0.042004 seconds and 5 git commands to generate.