1 /* DLX specific support for 32-bit ELF
2 Copyright 2002, 2003, 2004, 2005 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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
26 int set_dlx_skip_hi16_flag
PARAMS ((int));
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));
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
54 static reloc_howto_type dlx_elf_howto_table
[]=
57 HOWTO (R_DLX_NONE
, /* type */
59 0, /* size (0 = byte, 1 = short, 2 = long) */
61 FALSE
, /* pc_relative */
63 complain_overflow_dont
,/* complain_on_overflow */
64 bfd_elf_generic_reloc
, /* special_function */
65 "R_DLX_NONE", /* name */
66 FALSE
, /* partial_inplace */
69 FALSE
), /* pcrel_offset */
71 /* 8 bit relocation. */
72 HOWTO (R_DLX_RELOC_8
, /* type */
74 0, /* size (0 = byte, 1 = short, 2 = long) */
76 FALSE
, /* pc_relative */
78 complain_overflow_dont
,/* complain_on_overflow */
79 bfd_elf_generic_reloc
, /* special_function */
80 "R_DLX_RELOC_8", /* name */
81 TRUE
, /* partial_inplace */
84 FALSE
), /* pcrel_offset */
86 /* 16 bit relocation. */
87 HOWTO (R_DLX_RELOC_16
, /* type */
89 1, /* size (0 = byte, 1 = short, 2 = long) */
91 FALSE
, /* pc_relative */
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 */
101 /* 32 bit relocation. */
102 HOWTO (R_DLX_RELOC_32
, /* type */
104 2, /* size (0 = byte, 1 = short, 2 = long) */
106 FALSE
, /* pc_relative */
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 */
116 /* GNU extension to record C++ vtable hierarchy */
117 HOWTO (R_DLX_GNU_VTINHERIT
, /* type */
119 2, /* size (0 = byte, 1 = short, 2 = long) */
121 FALSE
, /* pc_relative */
123 complain_overflow_dont
,/* complain_on_overflow */
124 NULL
, /* special_function */
125 "R_DLX_GNU_VTINHERIT", /* name */
126 FALSE
, /* partial_inplace */
129 FALSE
), /* pcrel_offset */
131 /* GNU extension to record C++ vtable member usage */
132 HOWTO (R_DLX_GNU_VTENTRY
, /* type */
134 2, /* size (0 = byte, 1 = short, 2 = long) */
136 FALSE
, /* pc_relative */
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 */
144 FALSE
) /* pcrel_offset */
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 */
151 1, /* size (0 = byte, 1 = short, 2 = long) */
153 TRUE
, /* pc_relative */
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 */
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 */
167 2, /* size (0 = byte, 1 = short, 2 = long) */
169 TRUE
, /* pc_relative */
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 */
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 */
183 2, /* size (0 = byte, 1 = short, 2 = long) */
185 FALSE
, /* pc_relative */
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 */
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 */
199 1, /* size (0 = byte, 1 = short, 2 = long) */
201 FALSE
, /* pc_relative */
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 */
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. */
218 static int skip_dlx_elf_hi16_reloc
= 0;
221 set_dlx_skip_hi16_flag (flag
)
224 skip_dlx_elf_hi16_reloc
= flag
;
228 static bfd_reloc_status_type
229 _bfd_dlx_elf_hi16_reloc (abfd
, reloc_entry
, symbol
, data
,
230 input_section
, output_bfd
, error_message
)
232 arelent
*reloc_entry
;
235 asection
*input_section
;
237 char **error_message
;
239 bfd_reloc_status_type ret
;
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
);
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)
255 reloc_entry
->address
+= input_section
->output_offset
;
261 if (bfd_is_und_section (symbol
->section
)
262 && output_bfd
== (bfd
*) NULL
)
263 ret
= bfd_reloc_undefined
;
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
);
271 if (reloc_entry
->address
> bfd_get_section_limit (abfd
, input_section
))
272 return bfd_reloc_outofrange
;
274 bfd_put_16 (abfd
, (short)((relocation
>> 16) & 0xFFFF),
275 (bfd_byte
*)data
+ reloc_entry
->address
);
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. */
290 static bfd_reloc_status_type
291 elf32_dlx_relocate16 (abfd
, reloc_entry
, symbol
, data
,
292 input_section
, output_bfd
, error_message
)
294 arelent
*reloc_entry
;
297 asection
*input_section
;
299 char **error_message ATTRIBUTE_UNUSED
;
301 unsigned long insn
, vallo
, allignment
;
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. */
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
);
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
;
318 /* Can not support a long jump to sections other then .text */
319 if (strcmp (input_section
->name
, symbol
->section
->output_section
->name
) != 0)
322 "BFD Link Error: branch (PC rel16) to section (%s) not supported\n",
323 symbol
->section
->output_section
->name
);
324 return bfd_reloc_undefined
;
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;
332 vallo
= ~(vallo
| 0xFFFF0000) + 1;
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
);
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
;
344 if (abs ((int) val
) > 0x00007FFF)
345 return bfd_reloc_outofrange
;
347 insn
= (insn
& 0xFFFF0000) | (val
& 0x0000FFFF);
349 bfd_put_32 (abfd
, insn
,
350 (bfd_byte
*) data
+ reloc_entry
->address
);
355 static bfd_reloc_status_type
356 elf32_dlx_relocate26 (abfd
, reloc_entry
, symbol
, data
,
357 input_section
, output_bfd
, error_message
)
359 arelent
*reloc_entry
;
362 asection
*input_section
;
364 char **error_message ATTRIBUTE_UNUSED
;
366 unsigned long insn
, vallo
, allignment
;
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. */
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
);
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
;
383 /* Can not support a long jump to sections other then .text */
384 if (strcmp (input_section
->name
, symbol
->section
->output_section
->name
) != 0)
387 "BFD Link Error: jump (PC rel26) to section (%s) not supported\n",
388 symbol
->section
->output_section
->name
);
389 return bfd_reloc_undefined
;
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;
396 if (vallo
& 0x03000000)
397 vallo
= ~(vallo
| 0xFC000000) + 1;
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
);
404 /* val is the displacement (PC relative to next instruction). */
405 val
= (symbol
->section
->output_offset
+
406 symbol
->section
->output_section
->vma
+ symbol
->value
)
409 if (abs ((int) val
) > 0x01FFFFFF)
410 return bfd_reloc_outofrange
;
412 insn
= (insn
& 0xFC000000) | (val
& 0x03FFFFFF);
413 bfd_put_32 (abfd
, insn
,
414 (bfd_byte
*) data
+ reloc_entry
->address
);
419 /* A mapping from BFD reloc types to DLX ELF reloc types.
420 Stolen from elf32-mips.c.
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. */
429 bfd_reloc_code_real_type bfd_reloc_val
;
430 enum elf_dlx_reloc_type elf_reloc_val
;
433 static const struct elf_reloc_map dlx_reloc_map
[] =
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
}
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. */
450 elf32_dlx_check_relocs (abfd
, info
, sec
, relocs
)
452 struct bfd_link_info
*info
;
454 const Elf_Internal_Rela
*relocs
;
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
;
461 if (info
->relocatable
)
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
;
470 rel_end
= relocs
+ sec
->reloc_count
;
471 for (rel
= relocs
; rel
< rel_end
; rel
++)
473 struct elf_link_hash_entry
*h
;
474 unsigned long r_symndx
;
476 r_symndx
= ELF32_R_SYM (rel
->r_info
);
477 if (r_symndx
< symtab_hdr
->sh_info
)
480 h
= sym_hashes
[r_symndx
- symtab_hdr
->sh_info
];
482 switch (ELF32_R_TYPE (rel
->r_info
))
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
))
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
))
503 /* Given a BFD reloc type, return a howto structure. */
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
;
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
];
519 bfd_set_error (bfd_error_bad_value
);
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
;
528 return &elf_dlx_reloc_16_lo
;
532 static reloc_howto_type
*
533 dlx_rtype_to_howto (r_type
)
538 case R_DLX_RELOC_16_PCREL
:
539 return & elf_dlx_gnu_rel16_s2
;
541 case R_DLX_RELOC_26_PCREL
:
542 return & elf_dlx_gnu_rel26_s2
;
544 case R_DLX_RELOC_16_HI
:
545 return & elf_dlx_reloc_16_hi
;
547 case R_DLX_RELOC_16_LO
:
548 return & elf_dlx_reloc_16_lo
;
552 BFD_ASSERT (r_type
< (unsigned int) R_DLX_max
);
553 return & dlx_elf_howto_table
[r_type
];
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
;
568 elf32_dlx_info_to_howto_rel (abfd
, cache_ptr
, dst
)
569 bfd
*abfd ATTRIBUTE_UNUSED
;
571 Elf_Internal_Rela
*dst
;
575 r_type
= ELF32_R_TYPE (dst
->r_info
);
576 cache_ptr
->howto
= dlx_rtype_to_howto (r_type
);
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. */
586 #include "elf32-target.h"