]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - bfd/elf32-dlx.c
Update the FSF address in the copyright/GPL notice
[thirdparty/binutils-gdb.git] / bfd / elf32-dlx.c
1 /* DLX specific support for 32-bit ELF
2 Copyright 2002, 2003, 2004, 2005 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 2 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., 59 Temple Place - Suite 330, Boston, MA 02110-1301, USA. */
19
20 #include "bfd.h"
21 #include "sysdep.h"
22 #include "libbfd.h"
23 #include "elf-bfd.h"
24 #include "elf/dlx.h"
25
26 int set_dlx_skip_hi16_flag PARAMS ((int));
27
28 static bfd_boolean elf32_dlx_check_relocs
29 PARAMS ((bfd *, struct bfd_link_info *, asection *,
30 const Elf_Internal_Rela *));
31 static void elf32_dlx_info_to_howto
32 PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
33 static void elf32_dlx_info_to_howto_rel
34 PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
35 static bfd_reloc_status_type elf32_dlx_relocate16
36 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
37 static bfd_reloc_status_type elf32_dlx_relocate26
38 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
39 static reloc_howto_type *elf32_dlx_reloc_type_lookup
40 PARAMS ((bfd *, bfd_reloc_code_real_type));
41 static bfd_reloc_status_type _bfd_dlx_elf_hi16_reloc
42 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
43 static reloc_howto_type * dlx_rtype_to_howto
44 PARAMS ((unsigned int));
45
46
47 #define USE_REL 1
48
49 #define bfd_elf32_bfd_reloc_type_lookup elf32_dlx_reloc_type_lookup
50 #define elf_info_to_howto elf32_dlx_info_to_howto
51 #define elf_info_to_howto_rel elf32_dlx_info_to_howto_rel
52 #define elf_backend_check_relocs elf32_dlx_check_relocs
53
54 static reloc_howto_type dlx_elf_howto_table[]=
55 {
56 /* No relocation. */
57 HOWTO (R_DLX_NONE, /* type */
58 0, /* rightshift */
59 0, /* size (0 = byte, 1 = short, 2 = long) */
60 0, /* bitsize */
61 FALSE, /* pc_relative */
62 0, /* bitpos */
63 complain_overflow_dont,/* complain_on_overflow */
64 bfd_elf_generic_reloc, /* special_function */
65 "R_DLX_NONE", /* name */
66 FALSE, /* partial_inplace */
67 0, /* src_mask */
68 0, /* dst_mask */
69 FALSE), /* pcrel_offset */
70
71 /* 8 bit relocation. */
72 HOWTO (R_DLX_RELOC_8, /* type */
73 0, /* rightshift */
74 0, /* size (0 = byte, 1 = short, 2 = long) */
75 8, /* bitsize */
76 FALSE, /* pc_relative */
77 0, /* bitpos */
78 complain_overflow_dont,/* complain_on_overflow */
79 bfd_elf_generic_reloc, /* special_function */
80 "R_DLX_RELOC_8", /* name */
81 TRUE, /* partial_inplace */
82 0xff, /* src_mask */
83 0xff, /* dst_mask */
84 FALSE), /* pcrel_offset */
85
86 /* 16 bit relocation. */
87 HOWTO (R_DLX_RELOC_16, /* type */
88 0, /* rightshift */
89 1, /* size (0 = byte, 1 = short, 2 = long) */
90 16, /* bitsize */
91 FALSE, /* pc_relative */
92 0, /* bitpos */
93 complain_overflow_dont,/* complain_on_overflow */
94 bfd_elf_generic_reloc, /* special_function */
95 "R_DLX_RELOC_16", /* name */
96 TRUE, /* partial_inplace */
97 0xffff, /* src_mask */
98 0xffff, /* dst_mask */
99 FALSE), /* pcrel_offset */
100
101 /* 32 bit relocation. */
102 HOWTO (R_DLX_RELOC_32, /* type */
103 0, /* rightshift */
104 2, /* size (0 = byte, 1 = short, 2 = long) */
105 32, /* bitsize */
106 FALSE, /* pc_relative */
107 0, /* bitpos */
108 complain_overflow_dont,/* complain_on_overflow */
109 bfd_elf_generic_reloc, /* special_function */
110 "R_DLX_RELOC_32", /* name */
111 TRUE, /* partial_inplace */
112 0xffffffff, /* src_mask */
113 0xffffffff, /* dst_mask */
114 FALSE), /* pcrel_offset */
115
116 /* GNU extension to record C++ vtable hierarchy */
117 HOWTO (R_DLX_GNU_VTINHERIT, /* type */
118 0, /* rightshift */
119 2, /* size (0 = byte, 1 = short, 2 = long) */
120 0, /* bitsize */
121 FALSE, /* pc_relative */
122 0, /* bitpos */
123 complain_overflow_dont,/* complain_on_overflow */
124 NULL, /* special_function */
125 "R_DLX_GNU_VTINHERIT", /* name */
126 FALSE, /* partial_inplace */
127 0, /* src_mask */
128 0, /* dst_mask */
129 FALSE), /* pcrel_offset */
130
131 /* GNU extension to record C++ vtable member usage */
132 HOWTO (R_DLX_GNU_VTENTRY, /* type */
133 0, /* rightshift */
134 2, /* size (0 = byte, 1 = short, 2 = long) */
135 0, /* bitsize */
136 FALSE, /* pc_relative */
137 0, /* bitpos */
138 complain_overflow_dont,/* complain_on_overflow */
139 _bfd_elf_rel_vtable_reloc_fn,/* special_function */
140 "R_DLX_GNU_VTENTRY", /* name */
141 FALSE, /* partial_inplace */
142 0, /* src_mask */
143 0, /* dst_mask */
144 FALSE) /* pcrel_offset */
145 };
146
147 /* 16 bit offset for pc-relative branches. */
148 static reloc_howto_type elf_dlx_gnu_rel16_s2 =
149 HOWTO (R_DLX_RELOC_16_PCREL, /* type */
150 0, /* rightshift */
151 1, /* size (0 = byte, 1 = short, 2 = long) */
152 16, /* bitsize */
153 TRUE, /* pc_relative */
154 0, /* bitpos */
155 complain_overflow_signed, /* complain_on_overflow */
156 elf32_dlx_relocate16, /* special_function */
157 "R_DLX_RELOC_16_PCREL",/* name */
158 TRUE, /* partial_inplace */
159 0xffff, /* src_mask */
160 0xffff, /* dst_mask */
161 TRUE); /* pcrel_offset */
162
163 /* 26 bit offset for pc-relative branches. */
164 static reloc_howto_type elf_dlx_gnu_rel26_s2 =
165 HOWTO (R_DLX_RELOC_26_PCREL, /* type */
166 0, /* rightshift */
167 2, /* size (0 = byte, 1 = short, 2 = long) */
168 26, /* bitsize */
169 TRUE, /* pc_relative */
170 0, /* bitpos */
171 complain_overflow_dont,/* complain_on_overflow */
172 elf32_dlx_relocate26, /* special_function */
173 "R_DLX_RELOC_26_PCREL",/* name */
174 TRUE, /* partial_inplace */
175 0xffff, /* src_mask */
176 0xffff, /* dst_mask */
177 TRUE); /* pcrel_offset */
178
179 /* High 16 bits of symbol value. */
180 static reloc_howto_type elf_dlx_reloc_16_hi =
181 HOWTO (R_DLX_RELOC_16_HI, /* type */
182 16, /* rightshift */
183 2, /* size (0 = byte, 1 = short, 2 = long) */
184 32, /* bitsize */
185 FALSE, /* pc_relative */
186 0, /* bitpos */
187 complain_overflow_dont, /* complain_on_overflow */
188 _bfd_dlx_elf_hi16_reloc,/* special_function */
189 "R_DLX_RELOC_16_HI", /* name */
190 TRUE, /* partial_inplace */
191 0xFFFF, /* src_mask */
192 0xffff, /* dst_mask */
193 FALSE); /* pcrel_offset */
194
195 /* Low 16 bits of symbol value. */
196 static reloc_howto_type elf_dlx_reloc_16_lo =
197 HOWTO (R_DLX_RELOC_16_LO, /* type */
198 0, /* rightshift */
199 1, /* size (0 = byte, 1 = short, 2 = long) */
200 16, /* bitsize */
201 FALSE, /* pc_relative */
202 0, /* bitpos */
203 complain_overflow_dont,/* complain_on_overflow */
204 bfd_elf_generic_reloc, /* special_function */
205 "R_DLX_RELOC_16_LO", /* name */
206 TRUE, /* partial_inplace */
207 0xffff, /* src_mask */
208 0xffff, /* dst_mask */
209 FALSE); /* pcrel_offset */
210
211
212 /* The gas default behavior is not to preform the %hi modifier so that the
213 GNU assembler can have the lower 16 bits offset placed in the insn, BUT
214 we do like the gas to indicate it is %hi reloc type so when we in the link
215 loader phase we can have the corrected hi16 vale replace the buggous lo16
216 value that was placed there by gas. */
217
218 static int skip_dlx_elf_hi16_reloc = 0;
219
220 int
221 set_dlx_skip_hi16_flag (flag)
222 int flag;
223 {
224 skip_dlx_elf_hi16_reloc = flag;
225 return flag;
226 }
227
228 static bfd_reloc_status_type
229 _bfd_dlx_elf_hi16_reloc (abfd, reloc_entry, symbol, data,
230 input_section, output_bfd, error_message)
231 bfd *abfd;
232 arelent *reloc_entry;
233 asymbol *symbol;
234 PTR data;
235 asection *input_section;
236 bfd *output_bfd;
237 char **error_message;
238 {
239 bfd_reloc_status_type ret;
240 bfd_vma relocation;
241
242 /* If the skip flag is set then we simply do the generic relocating, this
243 is more of a hack for dlx gas/gld, so we do not need to do the %hi/%lo
244 fixup like mips gld did. */
245 if (skip_dlx_elf_hi16_reloc)
246 return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
247 input_section, output_bfd, error_message);
248
249 /* If we're relocating, and this an external symbol, we don't want
250 to change anything. */
251 if (output_bfd != (bfd *) NULL
252 && (symbol->flags & BSF_SECTION_SYM) == 0
253 && reloc_entry->addend == 0)
254 {
255 reloc_entry->address += input_section->output_offset;
256 return bfd_reloc_ok;
257 }
258
259 ret = bfd_reloc_ok;
260
261 if (bfd_is_und_section (symbol->section)
262 && output_bfd == (bfd *) NULL)
263 ret = bfd_reloc_undefined;
264
265 relocation = (bfd_is_com_section (symbol->section)) ? 0 : symbol->value;
266 relocation += symbol->section->output_section->vma;
267 relocation += symbol->section->output_offset;
268 relocation += reloc_entry->addend;
269 relocation += bfd_get_16 (abfd, (bfd_byte *)data + reloc_entry->address);
270
271 if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
272 return bfd_reloc_outofrange;
273
274 bfd_put_16 (abfd, (short)((relocation >> 16) & 0xFFFF),
275 (bfd_byte *)data + reloc_entry->address);
276
277 return ret;
278 }
279
280 /* ELF relocs are against symbols. If we are producing relocatable
281 output, and the reloc is against an external symbol, and nothing
282 has given us any additional addend, the resulting reloc will also
283 be against the same symbol. In such a case, we don't want to
284 change anything about the way the reloc is handled, since it will
285 all be done at final link time. Rather than put special case code
286 into bfd_perform_relocation, all the reloc types use this howto
287 function. It just short circuits the reloc if producing
288 relocatable output against an external symbol. */
289
290 static bfd_reloc_status_type
291 elf32_dlx_relocate16 (abfd, reloc_entry, symbol, data,
292 input_section, output_bfd, error_message)
293 bfd *abfd;
294 arelent *reloc_entry;
295 asymbol *symbol;
296 PTR data;
297 asection *input_section;
298 bfd *output_bfd;
299 char **error_message ATTRIBUTE_UNUSED;
300 {
301 unsigned long insn, vallo, allignment;
302 int val;
303
304 /* HACK: I think this first condition is necessary when producing
305 relocatable output. After the end of HACK, the code is identical
306 to bfd_elf_generic_reloc(). I would _guess_ the first change
307 belongs there rather than here. martindo 1998-10-23. */
308
309 if (skip_dlx_elf_hi16_reloc)
310 return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
311 input_section, output_bfd, error_message);
312
313 /* Check undefined section and undefined symbols */
314 if (bfd_is_und_section (symbol->section)
315 && output_bfd == (bfd *) NULL)
316 return bfd_reloc_undefined;
317
318 /* Can not support a long jump to sections other then .text */
319 if (strcmp (input_section->name, symbol->section->output_section->name) != 0)
320 {
321 fprintf (stderr,
322 "BFD Link Error: branch (PC rel16) to section (%s) not supported\n",
323 symbol->section->output_section->name);
324 return bfd_reloc_undefined;
325 }
326
327 insn = bfd_get_32 (abfd, (bfd_byte *)data + reloc_entry->address);
328 allignment = 1 << (input_section->output_section->alignment_power - 1);
329 vallo = insn & 0x0000FFFF;
330
331 if (vallo & 0x8000)
332 vallo = ~(vallo | 0xFFFF0000) + 1;
333
334 /* vallo points to the vma of next instruction. */
335 vallo += (((unsigned long)(input_section->output_section->vma +
336 input_section->output_offset) +
337 allignment) & ~allignment);
338
339 /* val is the displacement (PC relative to next instruction). */
340 val = (symbol->section->output_offset +
341 symbol->section->output_section->vma +
342 symbol->value) - vallo;
343
344 if (abs ((int) val) > 0x00007FFF)
345 return bfd_reloc_outofrange;
346
347 insn = (insn & 0xFFFF0000) | (val & 0x0000FFFF);
348
349 bfd_put_32 (abfd, insn,
350 (bfd_byte *) data + reloc_entry->address);
351
352 return bfd_reloc_ok;
353 }
354
355 static bfd_reloc_status_type
356 elf32_dlx_relocate26 (abfd, reloc_entry, symbol, data,
357 input_section, output_bfd, error_message)
358 bfd *abfd;
359 arelent *reloc_entry;
360 asymbol *symbol;
361 PTR data;
362 asection *input_section;
363 bfd *output_bfd;
364 char **error_message ATTRIBUTE_UNUSED;
365 {
366 unsigned long insn, vallo, allignment;
367 int val;
368
369 /* HACK: I think this first condition is necessary when producing
370 relocatable output. After the end of HACK, the code is identical
371 to bfd_elf_generic_reloc(). I would _guess_ the first change
372 belongs there rather than here. martindo 1998-10-23. */
373
374 if (skip_dlx_elf_hi16_reloc)
375 return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
376 input_section, output_bfd, error_message);
377
378 /* Check undefined section and undefined symbols. */
379 if (bfd_is_und_section (symbol->section)
380 && output_bfd == (bfd *) NULL)
381 return bfd_reloc_undefined;
382
383 /* Can not support a long jump to sections other then .text */
384 if (strcmp (input_section->name, symbol->section->output_section->name) != 0)
385 {
386 fprintf (stderr,
387 "BFD Link Error: jump (PC rel26) to section (%s) not supported\n",
388 symbol->section->output_section->name);
389 return bfd_reloc_undefined;
390 }
391
392 insn = bfd_get_32 (abfd, (bfd_byte *)data + reloc_entry->address);
393 allignment = 1 << (input_section->output_section->alignment_power - 1);
394 vallo = insn & 0x03FFFFFF;
395
396 if (vallo & 0x03000000)
397 vallo = ~(vallo | 0xFC000000) + 1;
398
399 /* vallo is the vma for the next instruction. */
400 vallo += (((unsigned long) (input_section->output_section->vma +
401 input_section->output_offset) +
402 allignment) & ~allignment);
403
404 /* val is the displacement (PC relative to next instruction). */
405 val = (symbol->section->output_offset +
406 symbol->section->output_section->vma + symbol->value)
407 - vallo;
408
409 if (abs ((int) val) > 0x01FFFFFF)
410 return bfd_reloc_outofrange;
411
412 insn = (insn & 0xFC000000) | (val & 0x03FFFFFF);
413 bfd_put_32 (abfd, insn,
414 (bfd_byte *) data + reloc_entry->address);
415
416 return bfd_reloc_ok;
417 }
418
419 /* A mapping from BFD reloc types to DLX ELF reloc types.
420 Stolen from elf32-mips.c.
421
422 More about this table - for dlx elf relocation we do not really
423 need this table, if we have a rtype defined in this table will
424 caused tc_gen_relocate confused and die on us, but if we remove
425 this table it will caused more problem, so for now simple solution
426 is to remove those entries which may cause problem. */
427 struct elf_reloc_map
428 {
429 bfd_reloc_code_real_type bfd_reloc_val;
430 enum elf_dlx_reloc_type elf_reloc_val;
431 };
432
433 static const struct elf_reloc_map dlx_reloc_map[] =
434 {
435 { BFD_RELOC_NONE, R_DLX_NONE },
436 { BFD_RELOC_16, R_DLX_RELOC_16 },
437 { BFD_RELOC_32, R_DLX_RELOC_32 },
438 { BFD_RELOC_DLX_HI16_S, R_DLX_RELOC_16_HI },
439 { BFD_RELOC_DLX_LO16, R_DLX_RELOC_16_LO },
440 { BFD_RELOC_VTABLE_INHERIT, R_DLX_GNU_VTINHERIT },
441 { BFD_RELOC_VTABLE_ENTRY, R_DLX_GNU_VTENTRY }
442 };
443
444
445 /* Look through the relocs for a section during the first phase.
446 Since we don't do .gots or .plts, we just need to consider the
447 virtual table relocs for gc. */
448
449 static bfd_boolean
450 elf32_dlx_check_relocs (abfd, info, sec, relocs)
451 bfd *abfd;
452 struct bfd_link_info *info;
453 asection *sec;
454 const Elf_Internal_Rela *relocs;
455 {
456 Elf_Internal_Shdr *symtab_hdr;
457 struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
458 const Elf_Internal_Rela *rel;
459 const Elf_Internal_Rela *rel_end;
460
461 if (info->relocatable)
462 return TRUE;
463
464 symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
465 sym_hashes = elf_sym_hashes (abfd);
466 sym_hashes_end = sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
467 if (!elf_bad_symtab (abfd))
468 sym_hashes_end -= symtab_hdr->sh_info;
469
470 rel_end = relocs + sec->reloc_count;
471 for (rel = relocs; rel < rel_end; rel++)
472 {
473 struct elf_link_hash_entry *h;
474 unsigned long r_symndx;
475
476 r_symndx = ELF32_R_SYM (rel->r_info);
477 if (r_symndx < symtab_hdr->sh_info)
478 h = NULL;
479 else
480 h = sym_hashes[r_symndx - symtab_hdr->sh_info];
481
482 switch (ELF32_R_TYPE (rel->r_info))
483 {
484 /* This relocation describes the C++ object vtable hierarchy.
485 Reconstruct it for later use during GC. */
486 case R_DLX_GNU_VTINHERIT:
487 if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
488 return FALSE;
489 break;
490
491 /* This relocation describes which C++ vtable entries are actually
492 used. Record for later use during GC. */
493 case R_DLX_GNU_VTENTRY:
494 if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
495 return FALSE;
496 break;
497 }
498 }
499
500 return TRUE;
501 }
502
503 /* Given a BFD reloc type, return a howto structure. */
504
505 static reloc_howto_type *
506 elf32_dlx_reloc_type_lookup (abfd, code)
507 bfd *abfd ATTRIBUTE_UNUSED;
508 bfd_reloc_code_real_type code;
509 {
510 unsigned int i;
511
512 for (i = 0; i < sizeof (dlx_reloc_map) / sizeof (struct elf_reloc_map); i++)
513 if (dlx_reloc_map[i].bfd_reloc_val == code)
514 return &dlx_elf_howto_table[(int) dlx_reloc_map[i].elf_reloc_val];
515
516 switch (code)
517 {
518 default:
519 bfd_set_error (bfd_error_bad_value);
520 return NULL;
521 case BFD_RELOC_16_PCREL_S2:
522 return &elf_dlx_gnu_rel16_s2;
523 case BFD_RELOC_DLX_JMP26:
524 return &elf_dlx_gnu_rel26_s2;
525 case BFD_RELOC_HI16_S:
526 return &elf_dlx_reloc_16_hi;
527 case BFD_RELOC_LO16:
528 return &elf_dlx_reloc_16_lo;
529 }
530 }
531
532 static reloc_howto_type *
533 dlx_rtype_to_howto (r_type)
534 unsigned int r_type;
535 {
536 switch (r_type)
537 {
538 case R_DLX_RELOC_16_PCREL:
539 return & elf_dlx_gnu_rel16_s2;
540 break;
541 case R_DLX_RELOC_26_PCREL:
542 return & elf_dlx_gnu_rel26_s2;
543 break;
544 case R_DLX_RELOC_16_HI:
545 return & elf_dlx_reloc_16_hi;
546 break;
547 case R_DLX_RELOC_16_LO:
548 return & elf_dlx_reloc_16_lo;
549 break;
550
551 default:
552 BFD_ASSERT (r_type < (unsigned int) R_DLX_max);
553 return & dlx_elf_howto_table[r_type];
554 break;
555 }
556 }
557
558 static void
559 elf32_dlx_info_to_howto (abfd, cache_ptr, dst)
560 bfd * abfd ATTRIBUTE_UNUSED;
561 arelent * cache_ptr ATTRIBUTE_UNUSED;
562 Elf_Internal_Rela * dst ATTRIBUTE_UNUSED;
563 {
564 abort ();
565 }
566
567 static void
568 elf32_dlx_info_to_howto_rel (abfd, cache_ptr, dst)
569 bfd *abfd ATTRIBUTE_UNUSED;
570 arelent *cache_ptr;
571 Elf_Internal_Rela *dst;
572 {
573 unsigned int r_type;
574
575 r_type = ELF32_R_TYPE (dst->r_info);
576 cache_ptr->howto = dlx_rtype_to_howto (r_type);
577 return;
578 }
579
580 #define TARGET_BIG_SYM bfd_elf32_dlx_big_vec
581 #define TARGET_BIG_NAME "elf32-dlx"
582 #define ELF_ARCH bfd_arch_dlx
583 #define ELF_MACHINE_CODE EM_DLX
584 #define ELF_MAXPAGESIZE 1 /* FIXME: This number is wrong, It should be the page size in bytes. */
585
586 #include "elf32-target.h"