1 /* OR32-specific support for 32-bit ELF
2 Copyright 2002, 2004, 2005, 2007 Free Software Foundation, Inc.
3 Contributed by Ivan Guzvinec <ivang@opencores.org>
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. */
27 #include "libiberty.h"
29 /* Try to minimize the amount of space occupied by relocation tables
30 on the ROM (not that the ROM won't be swamped by other ELF overhead). */
33 /* Set the right machine number for an OR32 ELF file. */
36 or32_elf_object_p (bfd
*abfd
)
38 (void) bfd_default_set_arch_mach (abfd
, bfd_arch_or32
, 0);
42 /* The final processing done just before writing out an OR32 ELF object file.
43 This gets the OR32 architecture right based on the machine number. */
46 or32_elf_final_write_processing (bfd
*abfd
,
47 bfd_boolean linker ATTRIBUTE_UNUSED
)
49 elf_elfheader (abfd
)->e_flags
&=~ EF_OR32_MACH
;
52 static bfd_reloc_status_type
53 or32_elf_32_reloc (bfd
*abfd
,
57 asection
*input_section
,
59 char **error_message ATTRIBUTE_UNUSED
)
61 if (output_bfd
!= NULL
)
64 bfd_size_type addr
= reloc_entry
->address
;
66 reloc_entry
->address
+= input_section
->output_offset
;
68 insn
= bfd_get_32 (abfd
, (bfd_byte
*) data
+ addr
);
69 insn
+= symbol
->section
->output_section
->vma
;
70 insn
+= symbol
->section
->output_offset
;
71 insn
+= symbol
->value
;
72 bfd_put_32 (abfd
, insn
, (bfd_byte
*) data
+ addr
);
77 return bfd_reloc_continue
;
80 static bfd_reloc_status_type
81 or32_elf_16_reloc (bfd
*abfd
,
85 asection
*input_section
,
87 char **error_message ATTRIBUTE_UNUSED
)
89 if (output_bfd
!= NULL
)
92 bfd_size_type addr
= reloc_entry
->address
;
94 reloc_entry
->address
+= input_section
->output_offset
;
96 insn
= bfd_get_16 (abfd
, (bfd_byte
*) data
+ addr
);
97 insn
+= symbol
->section
->output_section
->vma
;
98 insn
+= symbol
->section
->output_offset
;
99 insn
+= symbol
->value
;
100 bfd_put_16 (abfd
, insn
, (bfd_byte
*) data
+ addr
);
105 return bfd_reloc_continue
;
108 static bfd_reloc_status_type
109 or32_elf_8_reloc (bfd
*abfd ATTRIBUTE_UNUSED
,
110 arelent
*reloc_entry
,
113 asection
*input_section
,
115 char **error_message ATTRIBUTE_UNUSED
)
117 if (output_bfd
!= NULL
)
120 bfd_size_type addr
= reloc_entry
->address
;
122 reloc_entry
->address
+= input_section
->output_offset
;
124 insn
= bfd_get_8 (abfd
, (bfd_byte
*) data
+ addr
);
125 insn
+= symbol
->section
->output_section
->vma
;
126 insn
+= symbol
->section
->output_offset
;
127 insn
+= symbol
->value
;
128 bfd_put_8 (abfd
, insn
, (bfd_byte
*) data
+ addr
);
133 return bfd_reloc_continue
;
136 /* Do a R_OR32_CONSTH relocation. This has to be done in combination
137 with a R_OR32_CONST reloc, because there is a carry from the LO16 to
138 the HI16. Here we just save the information we need; we do the
139 actual relocation when we see the LO16. OR32 ELF requires that the
140 LO16 immediately follow the HI16. As a GNU extension, we permit an
141 arbitrary number of HI16 relocs to be associated with a single LO16
142 reloc. This extension permits gcc to output the HI and LO relocs
143 itself. This code is copied from the elf32-mips.c. */
147 struct or32_consth
*next
;
152 /* FIXME: This should not be a static variable. */
154 static struct or32_consth
*or32_consth_list
;
156 static bfd_reloc_status_type
157 or32_elf_consth_reloc (bfd
*abfd ATTRIBUTE_UNUSED
,
158 arelent
*reloc_entry
,
161 asection
*input_section
,
163 char **error_message ATTRIBUTE_UNUSED
)
165 bfd_reloc_status_type ret
;
167 struct or32_consth
*n
;
171 if (bfd_is_und_section (symbol
->section
)
172 && output_bfd
== NULL
)
173 ret
= bfd_reloc_undefined
;
175 if (bfd_is_com_section (symbol
->section
))
178 relocation
= symbol
->value
;
180 relocation
+= symbol
->section
->output_section
->vma
;
181 relocation
+= symbol
->section
->output_offset
;
182 relocation
+= reloc_entry
->addend
;
184 if (reloc_entry
->address
> bfd_get_section_limit (abfd
, input_section
))
185 return bfd_reloc_outofrange
;
187 /* Save the information, and let LO16 do the actual relocation. */
188 n
= bfd_malloc (sizeof *n
);
190 return bfd_reloc_outofrange
;
191 n
->addr
= (bfd_byte
*) data
+ reloc_entry
->address
;
192 n
->addend
= relocation
;
193 n
->next
= or32_consth_list
;
194 or32_consth_list
= n
;
196 if (output_bfd
!= NULL
)
197 reloc_entry
->address
+= input_section
->output_offset
;
202 /* Do a R_OR32_CONST relocation. This is a straightforward 16 bit
203 inplace relocation; this function exists in order to do the
204 R_OR32_CONSTH relocation described above. */
206 static bfd_reloc_status_type
207 or32_elf_const_reloc (bfd
*abfd
,
208 arelent
*reloc_entry
,
211 asection
*input_section
,
213 char **error_message
)
215 if (or32_consth_list
!= NULL
)
217 struct or32_consth
*l
;
219 l
= or32_consth_list
;
225 struct or32_consth
*next
;
227 /* Do the HI16 relocation. Note that we actually don't need
228 to know anything about the LO16 itself, except where to
229 find the low 16 bits of the addend needed by the LO16. */
230 insn
= bfd_get_32 (abfd
, l
->addr
);
231 vallo
= (bfd_get_32 (abfd
, (bfd_byte
*) data
+ reloc_entry
->address
)
233 val
= ((insn
& 0xffff) << 16) + vallo
;
236 insn
= (insn
&~ 0xffff) | ((val
>> 16) & 0xffff);
237 bfd_put_32 (abfd
, insn
, l
->addr
);
244 or32_consth_list
= NULL
;
247 if (output_bfd
!= NULL
)
249 unsigned long insn
, tmp
;
250 bfd_size_type addr
= reloc_entry
->address
;
252 reloc_entry
->address
+= input_section
->output_offset
;
254 insn
= bfd_get_32 (abfd
, (bfd_byte
*) data
+ addr
);
255 tmp
= insn
& 0x0000ffff;
256 tmp
+= symbol
->section
->output_section
->vma
;
257 tmp
+= symbol
->section
->output_offset
;
258 tmp
+= symbol
->value
;
259 insn
= (insn
& 0xffff0000) | (tmp
& 0x0000ffff);
260 bfd_put_32 (abfd
, insn
, (bfd_byte
*) data
+ addr
);
265 /* Now do the LO16 reloc in the usual way. */
266 return bfd_elf_generic_reloc (abfd
, reloc_entry
, symbol
, data
,
267 input_section
, output_bfd
, error_message
);
270 static bfd_reloc_status_type
271 or32_elf_jumptarg_reloc (bfd
*abfd
,
272 arelent
*reloc_entry
,
273 asymbol
*symbol ATTRIBUTE_UNUSED
,
275 asection
*input_section
,
277 char **error_message ATTRIBUTE_UNUSED
)
279 if (output_bfd
!= NULL
)
281 unsigned long insn
, tmp
;
282 bfd_size_type addr
= reloc_entry
->address
;
284 reloc_entry
->address
+= input_section
->output_offset
;
286 insn
= bfd_get_32 (abfd
, (bfd_byte
*) data
+ addr
);
287 tmp
= insn
| 0xfc000000;
288 tmp
-= (input_section
->output_offset
>> 2);
289 insn
= (insn
& 0xfc000000) | (tmp
& 0x03ffffff);
290 bfd_put_32 (abfd
, insn
, (bfd_byte
*) data
+ addr
);
295 return bfd_reloc_continue
;
298 static reloc_howto_type elf_or32_howto_table
[] =
300 /* This reloc does nothing. */
301 HOWTO (R_OR32_NONE
, /* type */
303 2, /* size (0 = byte, 1 = short, 2 = long) */
305 FALSE
, /* pc_relative */
307 complain_overflow_bitfield
, /* complain_on_overflow */
308 bfd_elf_generic_reloc
, /* special_function */
309 "R_OR32_NONE", /* name */
310 FALSE
, /* partial_inplace */
313 FALSE
), /* pcrel_offset */
315 /* A standard 32 bit relocation. */
316 HOWTO (R_OR32_32
, /* type */
318 2, /* size (0 = byte, 1 = short, 2 = long) */
320 FALSE
, /* pc_relative */
322 complain_overflow_bitfield
, /* complain_on_overflow */
323 or32_elf_32_reloc
, /* special_function */
324 "R_OR32_32", /* name */
325 FALSE
, /* partial_inplace */
326 0xffffffff, /* src_mask */
327 0xffffffff, /* dst_mask */
328 FALSE
), /* pcrel_offset */
330 /* A standard 16 bit relocation. */
331 HOWTO (R_OR32_16
, /* type */
333 1, /* size (0 = byte, 1 = short, 2 = long) */
335 FALSE
, /* pc_relative */
337 complain_overflow_bitfield
, /* complain_on_overflow */
338 or32_elf_16_reloc
, /* special_function */
339 "R_OR32_16", /* name */
340 FALSE
, /* partial_inplace */
341 0x0000ffff, /* src_mask */
342 0x0000ffff, /* dst_mask */
343 FALSE
), /* pcrel_offset */
345 /* A standard 8 bit relocation. */
346 HOWTO (R_OR32_8
, /* type */
348 0, /* size (0 = byte, 1 = short, 2 = long) */
350 FALSE
, /* pc_relative */
352 complain_overflow_bitfield
, /* complain_on_overflow */
353 or32_elf_8_reloc
, /* special_function */
354 "R_OR32_8", /* name */
355 FALSE
, /* partial_inplace */
356 0x000000ff, /* src_mask */
357 0x000000ff, /* dst_mask */
358 FALSE
), /* pcrel_offset */
360 /* A standard low 16 bit relocation. */
361 HOWTO (R_OR32_CONST
, /* type */
363 2, /* size (0 = byte, 1 = short, 2 = long) */
365 FALSE
, /* pc_relative */
367 complain_overflow_dont
, /* complain_on_overflow */
368 or32_elf_const_reloc
, /* special_function */
369 "R_OR32_CONST", /* name */
370 FALSE
, /* partial_inplace */
371 0x0000ffff, /* src_mask */
372 0x0000ffff, /* dst_mask */
373 FALSE
), /* pcrel_offset */
375 /* A standard high 16 bit relocation. */
376 HOWTO (R_OR32_CONSTH
, /* type */
378 2, /* size (0 = byte, 1 = short, 2 = long) */
380 TRUE
, /* pc_relative */
382 complain_overflow_dont
, /* complain_on_overflow */
383 or32_elf_consth_reloc
, /* special_function */
384 "R_OR32_CONSTH", /* name */
385 FALSE
, /* partial_inplace */
386 0xffff0000, /* src_mask */
387 0x0000ffff, /* dst_mask */
388 FALSE
), /* pcrel_offset */
390 /* A standard branch relocation. */
391 HOWTO (R_OR32_JUMPTARG
, /* type */
393 2, /* size (0 = byte, 1 = short, 2 = long) */
395 TRUE
, /* pc_relative */
397 complain_overflow_signed
, /* complain_on_overflow */
398 or32_elf_jumptarg_reloc
,/* special_function */
399 "R_OR32_JUMPTARG", /* name */
400 FALSE
, /* partial_inplace */
402 0x03ffffff, /* dst_mask */
403 TRUE
), /* pcrel_offset */
405 /* GNU extension to record C++ vtable hierarchy. */
406 HOWTO (R_OR32_GNU_VTINHERIT
, /* type */
408 2, /* size (0 = byte, 1 = short, 2 = long) */
410 FALSE
, /* pc_relative */
412 complain_overflow_dont
, /* complain_on_overflow */
413 NULL
, /* special_function */
414 "R_OR32_GNU_VTINHERIT", /* name */
415 FALSE
, /* partial_inplace */
418 FALSE
), /* pcrel_offset */
420 /* GNU extension to record C++ vtable member usage. */
421 HOWTO (R_OR32_GNU_VTENTRY
, /* type */
423 2, /* size (0 = byte, 1 = short, 2 = long) */
425 FALSE
, /* pc_relative */
427 complain_overflow_dont
, /* complain_on_overflow */
428 _bfd_elf_rel_vtable_reloc_fn
, /* special_function */
429 "R_OR32_GNU_VTENTRY", /* name */
430 FALSE
, /* partial_inplace */
433 FALSE
), /* pcrel_offset */
436 /* Map BFD reloc types to OR32 ELF reloc types. */
438 struct or32_reloc_map
440 bfd_reloc_code_real_type bfd_reloc_val
;
441 unsigned char elf_reloc_val
;
444 static const struct or32_reloc_map or32_reloc_map
[] =
446 { BFD_RELOC_NONE
, R_OR32_NONE
},
447 { BFD_RELOC_32
, R_OR32_32
},
448 { BFD_RELOC_16
, R_OR32_16
},
449 { BFD_RELOC_8
, R_OR32_8
},
450 { BFD_RELOC_LO16
, R_OR32_CONST
},
451 { BFD_RELOC_HI16
, R_OR32_CONSTH
},
452 { BFD_RELOC_32_GOT_PCREL
, R_OR32_JUMPTARG
},
453 { BFD_RELOC_VTABLE_INHERIT
, R_OR32_GNU_VTINHERIT
},
454 { BFD_RELOC_VTABLE_ENTRY
, R_OR32_GNU_VTENTRY
},
457 static reloc_howto_type
*
458 bfd_elf32_bfd_reloc_type_lookup (bfd
*abfd ATTRIBUTE_UNUSED
,
459 bfd_reloc_code_real_type code
)
463 for (i
= ARRAY_SIZE (or32_reloc_map
); i
--;)
464 if (or32_reloc_map
[i
].bfd_reloc_val
== code
)
465 return &elf_or32_howto_table
[or32_reloc_map
[i
].elf_reloc_val
];
470 static reloc_howto_type
*
471 bfd_elf32_bfd_reloc_name_lookup (bfd
*abfd ATTRIBUTE_UNUSED
,
477 i
< sizeof (elf_or32_howto_table
) / sizeof (elf_or32_howto_table
[0]);
479 if (elf_or32_howto_table
[i
].name
!= NULL
480 && strcasecmp (elf_or32_howto_table
[i
].name
, r_name
) == 0)
481 return &elf_or32_howto_table
[i
];
486 /* Set the howto pointer for an OR32 ELF reloc. */
489 or32_info_to_howto_rel (bfd
*abfd ATTRIBUTE_UNUSED
,
491 Elf_Internal_Rela
*dst
)
495 r_type
= ELF32_R_TYPE (dst
->r_info
);
496 BFD_ASSERT (r_type
< (unsigned int) R_OR32_max
);
497 cache_ptr
->howto
= &elf_or32_howto_table
[r_type
];
500 #define TARGET_LITTLE_SYM bfd_elf32_or32_little_vec
501 #define TARGET_LITTLE_NAME "elf32-littleor32"
502 #define TARGET_BIG_SYM bfd_elf32_or32_big_vec
503 #define TARGET_BIG_NAME "elf32-or32"
504 #define ELF_ARCH bfd_arch_or32
505 #define ELF_MACHINE_CODE EM_OR32
506 #define ELF_MAXPAGESIZE 0x1000
508 #define elf_info_to_howto 0
509 #define elf_info_to_howto_rel or32_info_to_howto_rel
510 #define elf_backend_object_p or32_elf_object_p
511 #define elf_backend_final_write_processing \
512 or32_elf_final_write_processing
514 #include "elf32-target.h"