1 /* OR32-specific support for 32-bit ELF
2 Copyright 2002, 2004, 2005 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 2 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, MA 02110-1301, USA. */
26 #include "libiberty.h"
28 /* Try to minimize the amount of space occupied by relocation tables
29 on the ROM (not that the ROM won't be swamped by other ELF overhead). */
32 /* Set the right machine number for an OR32 ELF file. */
35 or32_elf_object_p (bfd
*abfd
)
37 (void) bfd_default_set_arch_mach (abfd
, bfd_arch_or32
, 0);
41 /* The final processing done just before writing out an OR32 ELF object file.
42 This gets the OR32 architecture right based on the machine number. */
45 or32_elf_final_write_processing (bfd
*abfd
,
46 bfd_boolean linker ATTRIBUTE_UNUSED
)
48 elf_elfheader (abfd
)->e_flags
&=~ EF_OR32_MACH
;
51 static bfd_reloc_status_type
52 or32_elf_32_reloc (bfd
*abfd
,
56 asection
*input_section
,
58 char **error_message ATTRIBUTE_UNUSED
)
60 if (output_bfd
!= NULL
)
63 bfd_size_type addr
= reloc_entry
->address
;
65 reloc_entry
->address
+= input_section
->output_offset
;
67 insn
= bfd_get_32 (abfd
, (bfd_byte
*) data
+ addr
);
68 insn
+= symbol
->section
->output_section
->vma
;
69 insn
+= symbol
->section
->output_offset
;
70 insn
+= symbol
->value
;
71 bfd_put_32 (abfd
, insn
, (bfd_byte
*) data
+ addr
);
76 return bfd_reloc_continue
;
79 static bfd_reloc_status_type
80 or32_elf_16_reloc (bfd
*abfd
,
84 asection
*input_section
,
86 char **error_message ATTRIBUTE_UNUSED
)
88 if (output_bfd
!= NULL
)
91 bfd_size_type addr
= reloc_entry
->address
;
93 reloc_entry
->address
+= input_section
->output_offset
;
95 insn
= bfd_get_16 (abfd
, (bfd_byte
*) data
+ addr
);
96 insn
+= symbol
->section
->output_section
->vma
;
97 insn
+= symbol
->section
->output_offset
;
98 insn
+= symbol
->value
;
99 bfd_put_16 (abfd
, insn
, (bfd_byte
*) data
+ addr
);
104 return bfd_reloc_continue
;
107 static bfd_reloc_status_type
108 or32_elf_8_reloc (bfd
*abfd ATTRIBUTE_UNUSED
,
109 arelent
*reloc_entry
,
112 asection
*input_section
,
114 char **error_message ATTRIBUTE_UNUSED
)
116 if (output_bfd
!= NULL
)
119 bfd_size_type addr
= reloc_entry
->address
;
121 reloc_entry
->address
+= input_section
->output_offset
;
123 insn
= bfd_get_8 (abfd
, (bfd_byte
*) data
+ addr
);
124 insn
+= symbol
->section
->output_section
->vma
;
125 insn
+= symbol
->section
->output_offset
;
126 insn
+= symbol
->value
;
127 bfd_put_8 (abfd
, insn
, (bfd_byte
*) data
+ addr
);
132 return bfd_reloc_continue
;
135 /* Do a R_OR32_CONSTH relocation. This has to be done in combination
136 with a R_OR32_CONST reloc, because there is a carry from the LO16 to
137 the HI16. Here we just save the information we need; we do the
138 actual relocation when we see the LO16. OR32 ELF requires that the
139 LO16 immediately follow the HI16. As a GNU extension, we permit an
140 arbitrary number of HI16 relocs to be associated with a single LO16
141 reloc. This extension permits gcc to output the HI and LO relocs
142 itself. This code is copied from the elf32-mips.c. */
146 struct or32_consth
*next
;
151 /* FIXME: This should not be a static variable. */
153 static struct or32_consth
*or32_consth_list
;
155 static bfd_reloc_status_type
156 or32_elf_consth_reloc (bfd
*abfd ATTRIBUTE_UNUSED
,
157 arelent
*reloc_entry
,
160 asection
*input_section
,
162 char **error_message ATTRIBUTE_UNUSED
)
164 bfd_reloc_status_type ret
;
166 struct or32_consth
*n
;
170 if (bfd_is_und_section (symbol
->section
)
171 && output_bfd
== NULL
)
172 ret
= bfd_reloc_undefined
;
174 if (bfd_is_com_section (symbol
->section
))
177 relocation
= symbol
->value
;
179 relocation
+= symbol
->section
->output_section
->vma
;
180 relocation
+= symbol
->section
->output_offset
;
181 relocation
+= reloc_entry
->addend
;
183 if (reloc_entry
->address
> bfd_get_section_limit (abfd
, input_section
))
184 return bfd_reloc_outofrange
;
186 /* Save the information, and let LO16 do the actual relocation. */
187 n
= bfd_malloc (sizeof *n
);
189 return bfd_reloc_outofrange
;
190 n
->addr
= (bfd_byte
*) data
+ reloc_entry
->address
;
191 n
->addend
= relocation
;
192 n
->next
= or32_consth_list
;
193 or32_consth_list
= n
;
195 if (output_bfd
!= NULL
)
196 reloc_entry
->address
+= input_section
->output_offset
;
201 /* Do a R_OR32_CONST relocation. This is a straightforward 16 bit
202 inplace relocation; this function exists in order to do the
203 R_OR32_CONSTH relocation described above. */
205 static bfd_reloc_status_type
206 or32_elf_const_reloc (bfd
*abfd
,
207 arelent
*reloc_entry
,
210 asection
*input_section
,
212 char **error_message
)
214 if (or32_consth_list
!= NULL
)
216 struct or32_consth
*l
;
218 l
= or32_consth_list
;
224 struct or32_consth
*next
;
226 /* Do the HI16 relocation. Note that we actually don't need
227 to know anything about the LO16 itself, except where to
228 find the low 16 bits of the addend needed by the LO16. */
229 insn
= bfd_get_32 (abfd
, l
->addr
);
230 vallo
= (bfd_get_32 (abfd
, (bfd_byte
*) data
+ reloc_entry
->address
)
232 val
= ((insn
& 0xffff) << 16) + vallo
;
235 insn
= (insn
&~ 0xffff) | ((val
>> 16) & 0xffff);
236 bfd_put_32 (abfd
, insn
, l
->addr
);
243 or32_consth_list
= NULL
;
246 if (output_bfd
!= NULL
)
248 unsigned long insn
, tmp
;
249 bfd_size_type addr
= reloc_entry
->address
;
251 reloc_entry
->address
+= input_section
->output_offset
;
253 insn
= bfd_get_32 (abfd
, (bfd_byte
*) data
+ addr
);
254 tmp
= insn
& 0x0000ffff;
255 tmp
+= symbol
->section
->output_section
->vma
;
256 tmp
+= symbol
->section
->output_offset
;
257 tmp
+= symbol
->value
;
258 insn
= (insn
& 0xffff0000) | (tmp
& 0x0000ffff);
259 bfd_put_32 (abfd
, insn
, (bfd_byte
*) data
+ addr
);
264 /* Now do the LO16 reloc in the usual way. */
265 return bfd_elf_generic_reloc (abfd
, reloc_entry
, symbol
, data
,
266 input_section
, output_bfd
, error_message
);
269 static bfd_reloc_status_type
270 or32_elf_jumptarg_reloc (bfd
*abfd
,
271 arelent
*reloc_entry
,
272 asymbol
*symbol ATTRIBUTE_UNUSED
,
274 asection
*input_section
,
276 char **error_message ATTRIBUTE_UNUSED
)
278 if (output_bfd
!= NULL
)
280 unsigned long insn
, tmp
;
281 bfd_size_type addr
= reloc_entry
->address
;
283 reloc_entry
->address
+= input_section
->output_offset
;
285 insn
= bfd_get_32 (abfd
, (bfd_byte
*) data
+ addr
);
286 tmp
= insn
| 0xfc000000;
287 tmp
-= (input_section
->output_offset
>> 2);
288 insn
= (insn
& 0xfc000000) | (tmp
& 0x03ffffff);
289 bfd_put_32 (abfd
, insn
, (bfd_byte
*) data
+ addr
);
294 return bfd_reloc_continue
;
297 static reloc_howto_type elf_or32_howto_table
[] =
299 /* This reloc does nothing. */
300 HOWTO (R_OR32_NONE
, /* type */
302 2, /* size (0 = byte, 1 = short, 2 = long) */
304 FALSE
, /* pc_relative */
306 complain_overflow_bitfield
, /* complain_on_overflow */
307 bfd_elf_generic_reloc
, /* special_function */
308 "R_OR32_NONE", /* name */
309 FALSE
, /* partial_inplace */
312 FALSE
), /* pcrel_offset */
314 /* A standard 32 bit relocation. */
315 HOWTO (R_OR32_32
, /* type */
317 2, /* size (0 = byte, 1 = short, 2 = long) */
319 FALSE
, /* pc_relative */
321 complain_overflow_bitfield
, /* complain_on_overflow */
322 or32_elf_32_reloc
, /* special_function */
323 "R_OR32_32", /* name */
324 FALSE
, /* partial_inplace */
325 0xffffffff, /* src_mask */
326 0xffffffff, /* dst_mask */
327 FALSE
), /* pcrel_offset */
329 /* A standard 16 bit relocation. */
330 HOWTO (R_OR32_16
, /* type */
332 1, /* size (0 = byte, 1 = short, 2 = long) */
334 FALSE
, /* pc_relative */
336 complain_overflow_bitfield
, /* complain_on_overflow */
337 or32_elf_16_reloc
, /* special_function */
338 "R_OR32_16", /* name */
339 FALSE
, /* partial_inplace */
340 0x0000ffff, /* src_mask */
341 0x0000ffff, /* dst_mask */
342 FALSE
), /* pcrel_offset */
344 /* A standard 8 bit relocation. */
345 HOWTO (R_OR32_8
, /* type */
347 0, /* size (0 = byte, 1 = short, 2 = long) */
349 FALSE
, /* pc_relative */
351 complain_overflow_bitfield
, /* complain_on_overflow */
352 or32_elf_8_reloc
, /* special_function */
353 "R_OR32_8", /* name */
354 FALSE
, /* partial_inplace */
355 0x000000ff, /* src_mask */
356 0x000000ff, /* dst_mask */
357 FALSE
), /* pcrel_offset */
359 /* A standard low 16 bit relocation. */
360 HOWTO (R_OR32_CONST
, /* type */
362 2, /* size (0 = byte, 1 = short, 2 = long) */
364 FALSE
, /* pc_relative */
366 complain_overflow_dont
, /* complain_on_overflow */
367 or32_elf_const_reloc
, /* special_function */
368 "R_OR32_CONST", /* name */
369 FALSE
, /* partial_inplace */
370 0x0000ffff, /* src_mask */
371 0x0000ffff, /* dst_mask */
372 FALSE
), /* pcrel_offset */
374 /* A standard high 16 bit relocation. */
375 HOWTO (R_OR32_CONSTH
, /* type */
377 2, /* size (0 = byte, 1 = short, 2 = long) */
379 TRUE
, /* pc_relative */
381 complain_overflow_dont
, /* complain_on_overflow */
382 or32_elf_consth_reloc
, /* special_function */
383 "R_OR32_CONSTH", /* name */
384 FALSE
, /* partial_inplace */
385 0xffff0000, /* src_mask */
386 0x0000ffff, /* dst_mask */
387 FALSE
), /* pcrel_offset */
389 /* A standard branch relocation. */
390 HOWTO (R_OR32_JUMPTARG
, /* type */
392 2, /* size (0 = byte, 1 = short, 2 = long) */
394 TRUE
, /* pc_relative */
396 complain_overflow_signed
, /* complain_on_overflow */
397 or32_elf_jumptarg_reloc
,/* special_function */
398 "R_OR32_JUMPTARG", /* name */
399 FALSE
, /* partial_inplace */
401 0x03ffffff, /* dst_mask */
402 TRUE
), /* pcrel_offset */
404 /* GNU extension to record C++ vtable hierarchy. */
405 HOWTO (R_OR32_GNU_VTINHERIT
, /* type */
407 2, /* size (0 = byte, 1 = short, 2 = long) */
409 FALSE
, /* pc_relative */
411 complain_overflow_dont
, /* complain_on_overflow */
412 NULL
, /* special_function */
413 "R_OR32_GNU_VTINHERIT", /* name */
414 FALSE
, /* partial_inplace */
417 FALSE
), /* pcrel_offset */
419 /* GNU extension to record C++ vtable member usage. */
420 HOWTO (R_OR32_GNU_VTENTRY
, /* type */
422 2, /* size (0 = byte, 1 = short, 2 = long) */
424 FALSE
, /* pc_relative */
426 complain_overflow_dont
, /* complain_on_overflow */
427 _bfd_elf_rel_vtable_reloc_fn
, /* special_function */
428 "R_OR32_GNU_VTENTRY", /* name */
429 FALSE
, /* partial_inplace */
432 FALSE
), /* pcrel_offset */
435 /* Map BFD reloc types to OR32 ELF reloc types. */
437 struct or32_reloc_map
439 bfd_reloc_code_real_type bfd_reloc_val
;
440 unsigned char elf_reloc_val
;
443 static const struct or32_reloc_map or32_reloc_map
[] =
445 { BFD_RELOC_NONE
, R_OR32_NONE
},
446 { BFD_RELOC_32
, R_OR32_32
},
447 { BFD_RELOC_16
, R_OR32_16
},
448 { BFD_RELOC_8
, R_OR32_8
},
449 { BFD_RELOC_LO16
, R_OR32_CONST
},
450 { BFD_RELOC_HI16
, R_OR32_CONSTH
},
451 { BFD_RELOC_32_GOT_PCREL
, R_OR32_JUMPTARG
},
452 { BFD_RELOC_VTABLE_INHERIT
, R_OR32_GNU_VTINHERIT
},
453 { BFD_RELOC_VTABLE_ENTRY
, R_OR32_GNU_VTENTRY
},
456 static reloc_howto_type
*
457 bfd_elf32_bfd_reloc_type_lookup (bfd
*abfd ATTRIBUTE_UNUSED
,
458 bfd_reloc_code_real_type code
)
462 for (i
= ARRAY_SIZE (or32_reloc_map
); i
--;)
463 if (or32_reloc_map
[i
].bfd_reloc_val
== code
)
464 return &elf_or32_howto_table
[or32_reloc_map
[i
].elf_reloc_val
];
469 /* Set the howto pointer for an OR32 ELF reloc. */
472 or32_info_to_howto_rel (bfd
*abfd ATTRIBUTE_UNUSED
,
474 Elf_Internal_Rela
*dst
)
478 r_type
= ELF32_R_TYPE (dst
->r_info
);
479 BFD_ASSERT (r_type
< (unsigned int) R_OR32_max
);
480 cache_ptr
->howto
= &elf_or32_howto_table
[r_type
];
483 #define TARGET_LITTLE_SYM bfd_elf32_or32_little_vec
484 #define TARGET_LITTLE_NAME "elf32-littleor32"
485 #define TARGET_BIG_SYM bfd_elf32_or32_big_vec
486 #define TARGET_BIG_NAME "elf32-or32"
487 #define ELF_ARCH bfd_arch_or32
488 #define ELF_MACHINE_CODE EM_OR32
489 #define ELF_MAXPAGESIZE 0x1000
491 #define elf_info_to_howto 0
492 #define elf_info_to_howto_rel or32_info_to_howto_rel
493 #define elf_backend_object_p or32_elf_object_p
494 #define elf_backend_final_write_processing \
495 or32_elf_final_write_processing
497 #include "elf32-target.h"