1 /* OR32-specific support for 32-bit ELF
2 Copyright 2002, 2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
26 #include "libiberty.h"
28 static reloc_howto_type
*bfd_elf32_bfd_reloc_type_lookup
29 PARAMS ((bfd
*, bfd_reloc_code_real_type
));
30 static void or32_info_to_howto_rel
31 PARAMS ((bfd
*, arelent
*, Elf_Internal_Rela
*));
32 static bfd_boolean or32_elf_object_p
34 static void or32_elf_final_write_processing
35 PARAMS ((bfd
*, bfd_boolean
));
36 static bfd_reloc_status_type or32_elf_32_reloc
37 PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
, asection
*, bfd
*, char **));
38 static bfd_reloc_status_type or32_elf_16_reloc
39 PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
, asection
*, bfd
*, char **));
40 static bfd_reloc_status_type or32_elf_8_reloc
41 PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
, asection
*, bfd
*, char **));
42 static bfd_reloc_status_type or32_elf_const_reloc
43 PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
, asection
*, bfd
*, char **));
44 static bfd_reloc_status_type or32_elf_consth_reloc
45 PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
, asection
*, bfd
*, char **));
46 static bfd_reloc_status_type or32_elf_jumptarg_reloc
47 PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
, asection
*, bfd
*, char **));
49 /* Try to minimize the amount of space occupied by relocation tables
50 on the ROM (not that the ROM won't be swamped by other ELF overhead). */
53 static reloc_howto_type elf_or32_howto_table
[] =
55 /* This reloc does nothing. */
56 HOWTO (R_OR32_NONE
, /* type */
58 2, /* size (0 = byte, 1 = short, 2 = long) */
60 FALSE
, /* pc_relative */
62 complain_overflow_bitfield
, /* complain_on_overflow */
63 bfd_elf_generic_reloc
, /* special_function */
64 "R_OR32_NONE", /* name */
65 FALSE
, /* partial_inplace */
68 FALSE
), /* pcrel_offset */
70 /* A standard 32 bit relocation. */
71 HOWTO (R_OR32_32
, /* type */
73 2, /* size (0 = byte, 1 = short, 2 = long) */
75 FALSE
, /* pc_relative */
77 complain_overflow_bitfield
, /* complain_on_overflow */
78 or32_elf_32_reloc
, /* special_function */
79 "R_OR32_32", /* name */
80 FALSE
, /* partial_inplace */
81 0xffffffff, /* src_mask */
82 0xffffffff, /* dst_mask */
83 FALSE
), /* pcrel_offset */
85 /* A standard 16 bit relocation. */
86 HOWTO (R_OR32_16
, /* type */
88 1, /* size (0 = byte, 1 = short, 2 = long) */
90 FALSE
, /* pc_relative */
92 complain_overflow_bitfield
, /* complain_on_overflow */
93 or32_elf_16_reloc
, /* special_function */
94 "R_OR32_16", /* name */
95 FALSE
, /* partial_inplace */
96 0x0000ffff, /* src_mask */
97 0x0000ffff, /* dst_mask */
98 FALSE
), /* pcrel_offset */
100 /* A standard 8 bit relocation. */
101 HOWTO (R_OR32_8
, /* type */
103 0, /* size (0 = byte, 1 = short, 2 = long) */
105 FALSE
, /* pc_relative */
107 complain_overflow_bitfield
, /* complain_on_overflow */
108 or32_elf_8_reloc
, /* special_function */
109 "R_OR32_8", /* name */
110 FALSE
, /* partial_inplace */
111 0x000000ff, /* src_mask */
112 0x000000ff, /* dst_mask */
113 FALSE
), /* pcrel_offset */
115 /* A standard low 16 bit relocation. */
116 HOWTO (R_OR32_CONST
, /* type */
118 2, /* size (0 = byte, 1 = short, 2 = long) */
120 FALSE
, /* pc_relative */
122 complain_overflow_dont
, /* complain_on_overflow */
123 or32_elf_const_reloc
, /* special_function */
124 "R_OR32_CONST", /* name */
125 FALSE
, /* partial_inplace */
126 0x0000ffff, /* src_mask */
127 0x0000ffff, /* dst_mask */
128 FALSE
), /* pcrel_offset */
130 /* A standard high 16 bit relocation. */
131 HOWTO (R_OR32_CONSTH
, /* type */
133 2, /* size (0 = byte, 1 = short, 2 = long) */
135 TRUE
, /* pc_relative */
137 complain_overflow_dont
, /* complain_on_overflow */
138 or32_elf_consth_reloc
, /* special_function */
139 "R_OR32_CONSTH", /* name */
140 FALSE
, /* partial_inplace */
141 0xffff0000, /* src_mask */
142 0x0000ffff, /* dst_mask */
143 FALSE
), /* pcrel_offset */
145 /* A standard branch relocation. */
146 HOWTO (R_OR32_JUMPTARG
, /* type */
148 2, /* size (0 = byte, 1 = short, 2 = long) */
150 TRUE
, /* pc_relative */
152 complain_overflow_signed
, /* complain_on_overflow */
153 or32_elf_jumptarg_reloc
,/* special_function */
154 "R_OR32_JUMPTARG", /* name */
155 FALSE
, /* partial_inplace */
157 0x03ffffff, /* dst_mask */
158 TRUE
), /* pcrel_offset */
160 /* GNU extension to record C++ vtable hierarchy. */
161 HOWTO (R_OR32_GNU_VTINHERIT
, /* type */
163 2, /* size (0 = byte, 1 = short, 2 = long) */
165 FALSE
, /* pc_relative */
167 complain_overflow_dont
, /* complain_on_overflow */
168 NULL
, /* special_function */
169 "R_OR32_GNU_VTINHERIT", /* name */
170 FALSE
, /* partial_inplace */
173 FALSE
), /* pcrel_offset */
175 /* GNU extension to record C++ vtable member usage. */
176 HOWTO (R_OR32_GNU_VTENTRY
, /* type */
178 2, /* size (0 = byte, 1 = short, 2 = long) */
180 FALSE
, /* pc_relative */
182 complain_overflow_dont
, /* complain_on_overflow */
183 _bfd_elf_rel_vtable_reloc_fn
, /* special_function */
184 "R_OR32_GNU_VTENTRY", /* name */
185 FALSE
, /* partial_inplace */
188 FALSE
), /* pcrel_offset */
191 /* Map BFD reloc types to OR32 ELF reloc types. */
193 struct or32_reloc_map
195 bfd_reloc_code_real_type bfd_reloc_val
;
196 unsigned char elf_reloc_val
;
199 static const struct or32_reloc_map or32_reloc_map
[] =
201 { BFD_RELOC_NONE
, R_OR32_NONE
},
202 { BFD_RELOC_32
, R_OR32_32
},
203 { BFD_RELOC_16
, R_OR32_16
},
204 { BFD_RELOC_8
, R_OR32_8
},
205 { BFD_RELOC_LO16
, R_OR32_CONST
},
206 { BFD_RELOC_HI16
, R_OR32_CONSTH
},
207 { BFD_RELOC_32_GOT_PCREL
, R_OR32_JUMPTARG
},
208 { BFD_RELOC_VTABLE_INHERIT
, R_OR32_GNU_VTINHERIT
},
209 { BFD_RELOC_VTABLE_ENTRY
, R_OR32_GNU_VTENTRY
},
212 static reloc_howto_type
*
213 bfd_elf32_bfd_reloc_type_lookup (abfd
, code
)
214 bfd
*abfd ATTRIBUTE_UNUSED
;
215 bfd_reloc_code_real_type code
;
219 for (i
= ARRAY_SIZE (or32_reloc_map
); i
--;)
221 if (or32_reloc_map
[i
].bfd_reloc_val
== code
)
222 return &elf_or32_howto_table
[or32_reloc_map
[i
].elf_reloc_val
];
228 /* Set the howto pointer for an OR32 ELF reloc. */
231 or32_info_to_howto_rel (abfd
, cache_ptr
, dst
)
232 bfd
*abfd ATTRIBUTE_UNUSED
;
234 Elf_Internal_Rela
*dst
;
238 r_type
= ELF32_R_TYPE (dst
->r_info
);
239 BFD_ASSERT (r_type
< (unsigned int) R_OR32_max
);
240 cache_ptr
->howto
= &elf_or32_howto_table
[r_type
];
243 /* Set the right machine number for an OR32 ELF file. */
246 or32_elf_object_p (abfd
)
249 (void) bfd_default_set_arch_mach (abfd
, bfd_arch_or32
, 0);
253 /* The final processing done just before writing out an OR32 ELF object file.
254 This gets the OR32 architecture right based on the machine number. */
257 or32_elf_final_write_processing (abfd
, linker
)
259 bfd_boolean linker ATTRIBUTE_UNUSED
;
264 switch (mach
= bfd_get_mach (abfd
))
267 case bfd_mach_arc_base:
268 val = E_OR32_MACH_BASE;
276 elf_elfheader (abfd
)->e_flags
&=~ EF_OR32_MACH
;
277 elf_elfheader (abfd
)->e_flags
|= val
;
280 bfd_reloc_status_type
281 or32_elf_32_reloc (abfd
, reloc_entry
, symbol
, data
, input_section
,
282 output_bfd
, error_message
)
284 arelent
*reloc_entry
;
287 asection
*input_section
;
289 char **error_message ATTRIBUTE_UNUSED
;
291 if (output_bfd
!= (bfd
*) NULL
)
294 bfd_size_type addr
= reloc_entry
->address
;
296 reloc_entry
->address
+= input_section
->output_offset
;
298 insn
= bfd_get_32 (abfd
, (bfd_byte
*) data
+ addr
);
299 insn
+= symbol
->section
->output_section
->vma
;
300 insn
+= symbol
->section
->output_offset
;
301 insn
+= symbol
->value
;
302 bfd_put_32 (abfd
, insn
, (bfd_byte
*) data
+ addr
);
307 return bfd_reloc_continue
;
310 bfd_reloc_status_type
311 or32_elf_16_reloc (abfd
, reloc_entry
, symbol
, data
, input_section
,
312 output_bfd
, error_message
)
314 arelent
*reloc_entry
;
317 asection
*input_section
;
319 char **error_message ATTRIBUTE_UNUSED
;
321 if (output_bfd
!= (bfd
*) NULL
)
324 bfd_size_type addr
= reloc_entry
->address
;
326 reloc_entry
->address
+= input_section
->output_offset
;
328 insn
= bfd_get_16 (abfd
, (bfd_byte
*) data
+ addr
);
329 insn
+= symbol
->section
->output_section
->vma
;
330 insn
+= symbol
->section
->output_offset
;
331 insn
+= symbol
->value
;
332 bfd_put_16 (abfd
, insn
, (bfd_byte
*) data
+ addr
);
337 return bfd_reloc_continue
;
340 bfd_reloc_status_type
341 or32_elf_8_reloc (abfd
, reloc_entry
, symbol
, data
, input_section
,
342 output_bfd
, error_message
)
343 bfd
*abfd ATTRIBUTE_UNUSED
;
344 arelent
*reloc_entry
;
347 asection
*input_section
;
349 char **error_message ATTRIBUTE_UNUSED
;
351 if (output_bfd
!= (bfd
*) NULL
)
354 bfd_size_type addr
= reloc_entry
->address
;
356 reloc_entry
->address
+= input_section
->output_offset
;
358 insn
= bfd_get_8 (abfd
, (bfd_byte
*) data
+ addr
);
359 insn
+= symbol
->section
->output_section
->vma
;
360 insn
+= symbol
->section
->output_offset
;
361 insn
+= symbol
->value
;
362 bfd_put_8 (abfd
, insn
, (bfd_byte
*) data
+ addr
);
367 return bfd_reloc_continue
;
370 /* Do a R_OR32_CONSTH relocation. This has to be done in combination
371 with a R_OR32_CONST reloc, because there is a carry from the LO16 to
372 the HI16. Here we just save the information we need; we do the
373 actual relocation when we see the LO16. OR32 ELF requires that the
374 LO16 immediately follow the HI16. As a GNU extension, we permit an
375 arbitrary number of HI16 relocs to be associated with a single LO16
376 reloc. This extension permits gcc to output the HI and LO relocs
377 itself. This code is copied from the elf32-mips.c. */
381 struct or32_consth
*next
;
386 /* FIXME: This should not be a static variable. */
388 static struct or32_consth
*or32_consth_list
;
390 bfd_reloc_status_type
391 or32_elf_consth_reloc (abfd
, reloc_entry
, symbol
, data
, input_section
,
392 output_bfd
, error_message
)
393 bfd
*abfd ATTRIBUTE_UNUSED
;
394 arelent
*reloc_entry
;
397 asection
*input_section
;
399 char **error_message ATTRIBUTE_UNUSED
;
401 bfd_reloc_status_type ret
;
403 struct or32_consth
*n
;
407 if (bfd_is_und_section (symbol
->section
)
408 && output_bfd
== (bfd
*) NULL
)
409 ret
= bfd_reloc_undefined
;
411 if (bfd_is_com_section (symbol
->section
))
414 relocation
= symbol
->value
;
416 relocation
+= symbol
->section
->output_section
->vma
;
417 relocation
+= symbol
->section
->output_offset
;
418 relocation
+= reloc_entry
->addend
;
420 if (reloc_entry
->address
> bfd_get_section_limit (abfd
, input_section
))
421 return bfd_reloc_outofrange
;
423 /* Save the information, and let LO16 do the actual relocation. */
424 n
= (struct or32_consth
*) bfd_malloc (sizeof *n
);
426 return bfd_reloc_outofrange
;
427 n
->addr
= (bfd_byte
*) data
+ reloc_entry
->address
;
428 n
->addend
= relocation
;
429 n
->next
= or32_consth_list
;
430 or32_consth_list
= n
;
432 if (output_bfd
!= (bfd
*) NULL
)
433 reloc_entry
->address
+= input_section
->output_offset
;
438 /* Do a R_OR32_CONST relocation. This is a straightforward 16 bit
439 inplace relocation; this function exists in order to do the
440 R_OR32_CONSTH relocation described above. */
442 bfd_reloc_status_type
443 or32_elf_const_reloc (abfd
, reloc_entry
, symbol
, data
, input_section
,
444 output_bfd
, error_message
)
446 arelent
*reloc_entry
;
449 asection
*input_section
;
451 char **error_message
;
453 if (or32_consth_list
!= NULL
)
455 struct or32_consth
*l
;
457 l
= or32_consth_list
;
463 struct or32_consth
*next
;
465 /* Do the HI16 relocation. Note that we actually don't need
466 to know anything about the LO16 itself, except where to
467 find the low 16 bits of the addend needed by the LO16. */
468 insn
= bfd_get_32 (abfd
, l
->addr
);
469 vallo
= (bfd_get_32 (abfd
, (bfd_byte
*) data
+ reloc_entry
->address
)
471 val
= ((insn
& 0xffff) << 16) + vallo
;
474 insn
= (insn
&~ 0xffff) | ((val
>> 16) & 0xffff);
475 bfd_put_32 (abfd
, insn
, l
->addr
);
482 or32_consth_list
= NULL
;
485 if (output_bfd
!= (bfd
*) NULL
)
487 unsigned long insn
, tmp
;
488 bfd_size_type addr
= reloc_entry
->address
;
490 reloc_entry
->address
+= input_section
->output_offset
;
492 insn
= bfd_get_32 (abfd
, (bfd_byte
*) data
+ addr
);
493 tmp
= insn
& 0x0000ffff;
494 tmp
+= symbol
->section
->output_section
->vma
;
495 tmp
+= symbol
->section
->output_offset
;
496 tmp
+= symbol
->value
;
497 insn
= (insn
& 0xffff0000) | (tmp
& 0x0000ffff);
498 bfd_put_32 (abfd
, insn
, (bfd_byte
*) data
+ addr
);
503 /* Now do the LO16 reloc in the usual way. */
504 return bfd_elf_generic_reloc (abfd
, reloc_entry
, symbol
, data
,
505 input_section
, output_bfd
, error_message
);
508 bfd_reloc_status_type
509 or32_elf_jumptarg_reloc (abfd
, reloc_entry
, symbol
, data
, input_section
,
510 output_bfd
, error_message
)
512 arelent
*reloc_entry
;
513 asymbol
*symbol ATTRIBUTE_UNUSED
;
515 asection
*input_section
;
517 char **error_message ATTRIBUTE_UNUSED
;
519 if (output_bfd
!= (bfd
*) NULL
)
521 unsigned long insn
, tmp
;
522 bfd_size_type addr
= reloc_entry
->address
;
524 reloc_entry
->address
+= input_section
->output_offset
;
526 insn
= bfd_get_32 (abfd
, (bfd_byte
*) data
+ addr
);
527 tmp
= insn
| 0xfc000000;
528 tmp
-= (input_section
->output_offset
>> 2);
529 insn
= (insn
& 0xfc000000) | (tmp
& 0x03ffffff);
530 bfd_put_32 (abfd
, insn
, (bfd_byte
*) data
+ addr
);
535 return bfd_reloc_continue
;
538 #define TARGET_LITTLE_SYM bfd_elf32_or32_little_vec
539 #define TARGET_LITTLE_NAME "elf32-littleor32"
540 #define TARGET_BIG_SYM bfd_elf32_or32_big_vec
541 #define TARGET_BIG_NAME "elf32-or32"
542 #define ELF_ARCH bfd_arch_or32
543 #define ELF_MACHINE_CODE EM_OR32
544 #define ELF_MAXPAGESIZE 0x1000
546 #define elf_info_to_howto 0
547 #define elf_info_to_howto_rel or32_info_to_howto_rel
548 #define elf_backend_object_p or32_elf_object_p
549 #define elf_backend_final_write_processing \
550 or32_elf_final_write_processing
552 #include "elf32-target.h"