Consolidate Gary Funck's two ChangeLog entries.
[deliverable/binutils-gdb.git] / bfd / elf32-openrisc.c
CommitLineData
b3baf5d0 1/* OpenRISC-specific support for 32-bit ELF.
07adf181
AM
2 Copyright 2001, 2002, 2003, 2004, 2005, 2006
3 Free Software Foundation, Inc.
b3baf5d0
NC
4 Contributed by Johan Rydberg, jrydberg@opencores.org
5
47b0e7ad 6 This file is part of BFD, the Binary File Descriptor library.
b3baf5d0 7
47b0e7ad
NC
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
b3baf5d0 12
47b0e7ad
NC
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
b3baf5d0 17
47b0e7ad
NC
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
21 USA. */
b3baf5d0
NC
22
23#include "bfd.h"
24#include "sysdep.h"
25#include "libbfd.h"
26#include "elf-bfd.h"
27#include "elf/openrisc.h"
28#include "libiberty.h"
29
b3baf5d0 30static reloc_howto_type openrisc_elf_howto_table[] =
47b0e7ad 31{
b3baf5d0
NC
32 /* This reloc does nothing. */
33 HOWTO (R_OPENRISC_NONE, /* type */
34 0, /* rightshift */
35 2, /* size (0 = byte, 1 = short, 2 = long) */
36 32, /* bitsize */
b34976b6 37 FALSE, /* pc_relative */
b3baf5d0
NC
38 0, /* bitpos */
39 complain_overflow_bitfield, /* complain_on_overflow */
40 bfd_elf_generic_reloc, /* special_function */
41 "R_OPENRISC_NONE", /* name */
b34976b6 42 FALSE, /* partial_inplace */
b3baf5d0
NC
43 0, /* src_mask */
44 0, /* dst_mask */
b34976b6 45 FALSE), /* pcrel_offset */
b3baf5d0
NC
46
47 /* A PC relative 26 bit relocation, right shifted by 2. */
48 HOWTO (R_OPENRISC_INSN_REL_26, /* type */
49 2, /* rightshift */
50 2, /* size (0 = byte, 1 = short, 2 = long) */
51 26, /* bitsize */
b34976b6 52 TRUE, /* pc_relative */
b3baf5d0
NC
53 0, /* bitpos */
54 complain_overflow_signed, /* complain_on_overflow */
55 bfd_elf_generic_reloc, /* special_function */
56 "R_OPENRISC_INSN_REL_26", /* name */
b34976b6 57 FALSE, /* partial_inplace */
b3baf5d0
NC
58 0x00000000, /* src_mask */
59 0x03ffffff, /* dst_mask */
b34976b6 60 FALSE), /* pcrel_offset */
b3baf5d0
NC
61
62 /* A absolute 26 bit relocation, right shifted by 2. */
63 HOWTO (R_OPENRISC_INSN_ABS_26, /* type */
64 2, /* rightshift */
65 2, /* size (0 = byte, 1 = short, 2 = long) */
66 26, /* bitsize */
b34976b6 67 FALSE, /* pc_relative */
b3baf5d0
NC
68 0, /* bitpos */
69 complain_overflow_signed, /* complain_on_overflow */
70 bfd_elf_generic_reloc, /* special_function */
71 "R_OPENRISC_INSN_ABS_26", /* name */
b34976b6 72 FALSE, /* partial_inplace */
b3baf5d0
NC
73 0x00000000, /* src_mask */
74 0x03ffffff, /* dst_mask */
b34976b6 75 FALSE), /* pcrel_offset */
b3baf5d0
NC
76
77 HOWTO (R_OPENRISC_LO_16_IN_INSN, /* type */
78 0, /* rightshift */
c7e40348 79 1, /* size (0 = byte, 1 = short, 2 = long) */
b3baf5d0 80 16, /* bitsize */
b34976b6 81 FALSE, /* pc_relative */
b3baf5d0 82 0, /* bitpos */
c7e40348 83 complain_overflow_dont, /* complain_on_overflow */
b3baf5d0
NC
84 bfd_elf_generic_reloc, /* special_function */
85 "R_OPENRISC_LO_16_IN_INSN", /* name */
b34976b6 86 FALSE, /* partial_inplace */
c7e40348 87 0, /* src_mask */
b3baf5d0 88 0x0000ffff, /* dst_mask */
b34976b6 89 FALSE), /* pcrel_offset */
b3baf5d0
NC
90
91 HOWTO (R_OPENRISC_HI_16_IN_INSN, /* type */
92 16, /* rightshift */
c7e40348 93 1, /* size (0 = byte, 1 = short, 2 = long) */
b3baf5d0 94 16, /* bitsize */
b34976b6 95 FALSE, /* pc_relative */
b3baf5d0 96 0, /* bitpos */
c7e40348 97 complain_overflow_dont, /* complain_on_overflow */
b3baf5d0
NC
98 bfd_elf_generic_reloc, /* special_function */
99 "R_OPENRISC_HI_16_IN_INSN", /* name */
b34976b6 100 FALSE, /* partial_inplace */
c7e40348 101 0, /* src_mask */
b3baf5d0 102 0x0000ffff, /* dst_mask */
b34976b6 103 FALSE), /* pcrel_offset */
b3baf5d0
NC
104
105 /* An 8 bit absolute relocation. */
106 HOWTO (R_OPENRISC_8, /* type */
107 0, /* rightshift */
108 0, /* size (0 = byte, 1 = short, 2 = long) */
109 8, /* bitsize */
b34976b6 110 FALSE, /* pc_relative */
b3baf5d0
NC
111 0, /* bitpos */
112 complain_overflow_bitfield, /* complain_on_overflow */
113 bfd_elf_generic_reloc, /* special_function */
114 "R_OPENRISC_8", /* name */
b34976b6 115 TRUE, /* partial_inplace */
b3baf5d0
NC
116 0x0000, /* src_mask */
117 0x00ff, /* dst_mask */
b34976b6 118 FALSE), /* pcrel_offset */
b3baf5d0
NC
119
120 /* A 16 bit absolute relocation. */
121 HOWTO (R_OPENRISC_16, /* type */
122 0, /* rightshift */
123 1, /* size (0 = byte, 1 = short, 2 = long) */
124 16, /* bitsize */
b34976b6 125 FALSE, /* pc_relative */
b3baf5d0
NC
126 0, /* bitpos */
127 complain_overflow_bitfield, /* complain_on_overflow */
128 bfd_elf_generic_reloc, /* special_function */
129 "R_OPENRISC_16", /* name */
b34976b6 130 TRUE, /* partial_inplace */
b3baf5d0
NC
131 0x00000000, /* src_mask */
132 0x0000ffff, /* dst_mask */
b34976b6 133 FALSE), /* pcrel_offset */
b3baf5d0
NC
134
135 /* A 32 bit absolute relocation. */
136 HOWTO (R_OPENRISC_32, /* type */
137 0, /* rightshift */
138 2, /* size (0 = byte, 1 = short, 2 = long) */
139 32, /* bitsize */
b34976b6 140 FALSE, /* pc_relative */
b3baf5d0
NC
141 0, /* bitpos */
142 complain_overflow_bitfield, /* complain_on_overflow */
143 bfd_elf_generic_reloc, /* special_function */
144 "R_OPENRISC_32", /* name */
b34976b6 145 TRUE, /* partial_inplace */
b3baf5d0
NC
146 0x00000000, /* src_mask */
147 0xffffffff, /* dst_mask */
b34976b6 148 FALSE), /* pcrel_offset */
b3baf5d0 149
47b0e7ad 150 /* GNU extension to record C++ vtable hierarchy. */
b3baf5d0
NC
151 HOWTO (R_OPENRISC_GNU_VTINHERIT, /* type */
152 0, /* rightshift */
153 2, /* size (0 = byte, 1 = short, 2 = long) */
154 0, /* bitsize */
b34976b6 155 FALSE, /* pc_relative */
b3baf5d0
NC
156 0, /* bitpos */
157 complain_overflow_dont, /* complain_on_overflow */
158 NULL, /* special_function */
159 "R_OPENRISC_GNU_VTINHERIT", /* name */
b34976b6 160 FALSE, /* partial_inplace */
b3baf5d0
NC
161 0, /* src_mask */
162 0, /* dst_mask */
b34976b6 163 FALSE), /* pcrel_offset */
b3baf5d0 164
47b0e7ad 165 /* GNU extension to record C++ vtable member usage. */
b3baf5d0
NC
166 HOWTO (R_OPENRISC_GNU_VTENTRY, /* type */
167 0, /* rightshift */
168 2, /* size (0 = byte, 1 = short, 2 = long) */
169 0, /* bitsize */
b34976b6 170 FALSE, /* pc_relative */
b3baf5d0
NC
171 0, /* bitpos */
172 complain_overflow_dont, /* complain_on_overflow */
173 _bfd_elf_rel_vtable_reloc_fn, /* special_function */
174 "R_OPENRISC_GNU_VTENTRY", /* name */
b34976b6 175 FALSE, /* partial_inplace */
b3baf5d0
NC
176 0, /* src_mask */
177 0, /* dst_mask */
b34976b6 178 FALSE), /* pcrel_offset */
b3baf5d0
NC
179};
180
181/* Map BFD reloc types to OpenRISC ELF reloc types. */
182
183struct openrisc_reloc_map
47b0e7ad
NC
184{
185 bfd_reloc_code_real_type bfd_reloc_val;
186 unsigned int openrisc_reloc_val;
187};
b3baf5d0
NC
188
189static const struct openrisc_reloc_map openrisc_reloc_map[] =
47b0e7ad
NC
190{
191 { BFD_RELOC_NONE, R_OPENRISC_NONE },
192 { BFD_RELOC_32, R_OPENRISC_32 },
193 { BFD_RELOC_16, R_OPENRISC_16 },
194 { BFD_RELOC_8, R_OPENRISC_8 },
195 { BFD_RELOC_OPENRISC_REL_26,R_OPENRISC_INSN_REL_26 },
196 { BFD_RELOC_OPENRISC_ABS_26,R_OPENRISC_INSN_ABS_26 },
b3baf5d0 197 { BFD_RELOC_HI16, R_OPENRISC_HI_16_IN_INSN },
47b0e7ad
NC
198 { BFD_RELOC_LO16, R_OPENRISC_LO_16_IN_INSN },
199 { BFD_RELOC_VTABLE_INHERIT, R_OPENRISC_GNU_VTINHERIT },
200 { BFD_RELOC_VTABLE_ENTRY, R_OPENRISC_GNU_VTENTRY }
201};
b3baf5d0
NC
202
203static reloc_howto_type *
47b0e7ad
NC
204openrisc_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
205 bfd_reloc_code_real_type code)
b3baf5d0
NC
206{
207 unsigned int i;
208
209 for (i = ARRAY_SIZE (openrisc_reloc_map); --i;)
210 if (openrisc_reloc_map[i].bfd_reloc_val == code)
211 return & openrisc_elf_howto_table[openrisc_reloc_map[i].
212 openrisc_reloc_val];
213
214 return NULL;
215}
216
217/* Set the howto pointer for an OpenRISC ELF reloc. */
218
219static void
47b0e7ad
NC
220openrisc_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED,
221 arelent * cache_ptr,
222 Elf_Internal_Rela * dst)
b3baf5d0
NC
223{
224 unsigned int r_type;
225
226 r_type = ELF32_R_TYPE (dst->r_info);
227 BFD_ASSERT (r_type < (unsigned int) R_OPENRISC_max);
228 cache_ptr->howto = & openrisc_elf_howto_table[r_type];
229}
230
231/* Perform a single relocation. By default we use the standard BFD
232 routines, but a few relocs, we have to do them ourselves. */
233
234static bfd_reloc_status_type
47b0e7ad
NC
235openrisc_final_link_relocate (reloc_howto_type *howto,
236 bfd *input_bfd,
237 asection *input_section,
238 bfd_byte *contents,
239 Elf_Internal_Rela *rel,
240 bfd_vma relocation)
b3baf5d0
NC
241{
242 bfd_reloc_status_type r = bfd_reloc_ok;
243
244 switch (howto->type)
245 {
246 case R_OPENRISC_LO_16_IN_INSN:
247 relocation &= 0xffff;
248 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
249 contents, rel->r_offset,
250 relocation, rel->r_addend);
251 break;
252
253 default:
254 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
255 contents, rel->r_offset,
256 relocation, rel->r_addend);
257 }
258
259 return r;
260}
261
262/* Relocate an OpenRISC ELF section.
b3baf5d0
NC
263
264 The RELOCATE_SECTION function is called by the new ELF backend linker
265 to handle the relocations for a section.
266
267 The relocs are always passed as Rela structures; if the section
268 actually uses Rel structures, the r_addend field will always be
269 zero.
270
271 This function is responsible for adjusting the section contents as
1049f94e 272 necessary, and (if using Rela relocs and generating a relocatable
b3baf5d0
NC
273 output file) adjusting the reloc addend as necessary.
274
275 This function does not have to worry about setting the reloc
276 address or the reloc symbol index.
277
278 LOCAL_SYMS is a pointer to the swapped in local symbols.
279
280 LOCAL_SECTIONS is an array giving the section in the input file
281 corresponding to the st_shndx field of each local symbol.
282
283 The global hash table entry for the global symbols can be found
284 via elf_sym_hashes (input_bfd).
285
1049f94e 286 When generating relocatable output, this function must handle
b3baf5d0
NC
287 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
288 going to be the section symbol corresponding to the output
289 section, which means that the addend must be adjusted
290 accordingly. */
291
b34976b6 292static bfd_boolean
47b0e7ad
NC
293openrisc_elf_relocate_section (bfd *output_bfd,
294 struct bfd_link_info *info,
295 bfd *input_bfd,
296 asection *input_section,
297 bfd_byte *contents,
298 Elf_Internal_Rela *relocs,
299 Elf_Internal_Sym *local_syms,
300 asection **local_sections)
b3baf5d0
NC
301{
302 Elf_Internal_Shdr *symtab_hdr;
303 struct elf_link_hash_entry **sym_hashes;
304 Elf_Internal_Rela *rel;
305 Elf_Internal_Rela *relend;
306
1049f94e 307 if (info->relocatable)
b34976b6 308 return TRUE;
b491616a 309
b3baf5d0
NC
310 symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
311 sym_hashes = elf_sym_hashes (input_bfd);
312 relend = relocs + input_section->reloc_count;
313
314 for (rel = relocs; rel < relend; rel++)
315 {
316 reloc_howto_type *howto;
317 unsigned long r_symndx;
318 Elf_Internal_Sym *sym;
319 asection *sec;
320 struct elf_link_hash_entry *h;
321 bfd_vma relocation;
322 bfd_reloc_status_type r;
323 const char *name = NULL;
324 int r_type;
325
326 r_type = ELF32_R_TYPE (rel->r_info);
327 r_symndx = ELF32_R_SYM (rel->r_info);
328
329 if (r_type == R_OPENRISC_GNU_VTINHERIT
330 || r_type == R_OPENRISC_GNU_VTENTRY)
331 continue;
332
b3baf5d0
NC
333 if ((unsigned int) r_type >
334 (sizeof openrisc_elf_howto_table / sizeof (reloc_howto_type)))
335 abort ();
336
337 /* This is a final link. */
338 howto = openrisc_elf_howto_table + ELF32_R_TYPE (rel->r_info);
339 h = NULL;
340 sym = NULL;
341 sec = NULL;
342
343 if (r_symndx < symtab_hdr->sh_info)
344 {
345 sym = local_syms + r_symndx;
346 sec = local_sections[r_symndx];
8517fae7 347 relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
b3baf5d0
NC
348
349 name = bfd_elf_string_from_elf_section
350 (input_bfd, symtab_hdr->sh_link, sym->st_name);
351 name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
352 }
353 else
354 {
59c2e50f 355 bfd_boolean unresolved_reloc, warned;
b3baf5d0 356
b2a8e766
AM
357 RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
358 r_symndx, symtab_hdr, sym_hashes,
359 h, sec, relocation,
360 unresolved_reloc, warned);
b3baf5d0
NC
361 }
362
363 r = openrisc_final_link_relocate (howto, input_bfd, input_section,
364 contents, rel, relocation);
365
366 if (r != bfd_reloc_ok)
367 {
47b0e7ad 368 const char *msg = NULL;
b3baf5d0
NC
369
370 switch (r)
371 {
372 case bfd_reloc_overflow:
373 r = info->callbacks->reloc_overflow
dfeffb9f
L
374 (info, (h ? &h->root : NULL), name, howto->name,
375 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
b3baf5d0
NC
376 break;
377
378 case bfd_reloc_undefined:
379 r = info->callbacks->undefined_symbol
b34976b6 380 (info, name, input_bfd, input_section, rel->r_offset, TRUE);
b3baf5d0
NC
381 break;
382
383 case bfd_reloc_outofrange:
384 msg = _("internal error: out of range error");
385 break;
386
387 case bfd_reloc_notsupported:
388 msg = _("internal error: unsupported relocation error");
389 break;
390
391 case bfd_reloc_dangerous:
392 msg = _("internal error: dangerous relocation");
393 break;
394
395 default:
396 msg = _("internal error: unknown error");
397 break;
398 }
399
400 if (msg)
401 r = info->callbacks->warning
402 (info, msg, name, input_bfd, input_section, rel->r_offset);
403
404 if (!r)
b34976b6 405 return FALSE;
b3baf5d0
NC
406 }
407 }
408
b34976b6 409 return TRUE;
b3baf5d0
NC
410}
411
412/* Return the section that should be marked against GC for a given
413 relocation. */
414
415static asection *
47b0e7ad 416openrisc_elf_gc_mark_hook (asection *sec,
07adf181 417 struct bfd_link_info *info,
47b0e7ad
NC
418 Elf_Internal_Rela *rel,
419 struct elf_link_hash_entry *h,
420 Elf_Internal_Sym *sym)
b3baf5d0 421{
07adf181
AM
422 if (h != NULL)
423 switch (ELF32_R_TYPE (rel->r_info))
424 {
425 case R_OPENRISC_GNU_VTINHERIT:
426 case R_OPENRISC_GNU_VTENTRY:
427 return NULL;
428 }
429
430 return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
b3baf5d0
NC
431}
432
433/* Look through the relocs for a section during the first phase.
434 Since we don't do .gots or .plts, we just need to consider the
435 virtual table relocs for gc. */
436
b34976b6 437static bfd_boolean
47b0e7ad
NC
438openrisc_elf_check_relocs (bfd *abfd,
439 struct bfd_link_info *info,
440 asection *sec,
441 const Elf_Internal_Rela *relocs)
b3baf5d0
NC
442{
443 Elf_Internal_Shdr *symtab_hdr;
444 struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
445 const Elf_Internal_Rela *rel;
446 const Elf_Internal_Rela *rel_end;
447
1049f94e 448 if (info->relocatable)
b34976b6 449 return TRUE;
b3baf5d0
NC
450
451 symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
452 sym_hashes = elf_sym_hashes (abfd);
453 sym_hashes_end =
454 sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
455 if (!elf_bad_symtab (abfd))
456 sym_hashes_end -= symtab_hdr->sh_info;
457
458 rel_end = relocs + sec->reloc_count;
459 for (rel = relocs; rel < rel_end; rel++)
460 {
461 struct elf_link_hash_entry *h;
462 unsigned long r_symndx;
463
464 r_symndx = ELF32_R_SYM (rel->r_info);
465 if (r_symndx < symtab_hdr->sh_info)
466 h = NULL;
467 else
973a3492
L
468 {
469 h = sym_hashes[r_symndx - symtab_hdr->sh_info];
470 while (h->root.type == bfd_link_hash_indirect
471 || h->root.type == bfd_link_hash_warning)
472 h = (struct elf_link_hash_entry *) h->root.u.i.link;
473 }
b3baf5d0
NC
474
475 switch (ELF32_R_TYPE (rel->r_info))
476 {
477 /* This relocation describes the C++ object vtable hierarchy.
478 Reconstruct it for later use during GC. */
479 case R_OPENRISC_GNU_VTINHERIT:
c152c796 480 if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
b34976b6 481 return FALSE;
b3baf5d0
NC
482 break;
483
484 /* This relocation describes which C++ vtable entries are actually
485 used. Record for later use during GC. */
486 case R_OPENRISC_GNU_VTENTRY:
c152c796 487 if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
b34976b6 488 return FALSE;
b3baf5d0
NC
489 break;
490 }
491 }
492
b34976b6 493 return TRUE;
b3baf5d0
NC
494}
495
496/* Set the right machine number. */
497
b34976b6 498static bfd_boolean
47b0e7ad 499openrisc_elf_object_p (bfd *abfd)
b3baf5d0 500{
47b0e7ad 501 bfd_default_set_arch_mach (abfd, bfd_arch_openrisc, 0);
b34976b6 502 return TRUE;
b3baf5d0
NC
503}
504
505/* Store the machine number in the flags field. */
506
507static void
47b0e7ad
NC
508openrisc_elf_final_write_processing (bfd *abfd,
509 bfd_boolean linker ATTRIBUTE_UNUSED)
b3baf5d0
NC
510{
511 unsigned long val;
512
513 switch (bfd_get_mach (abfd))
514 {
515 default:
516 val = 0;
517 break;
518 }
519
520 elf_elfheader (abfd)->e_flags &= ~0xf;
521 elf_elfheader (abfd)->e_flags |= val;
522}
523
524
525#define ELF_ARCH bfd_arch_openrisc
526#define ELF_MACHINE_CODE EM_OPENRISC
c11cc227 527#define ELF_MACHINE_ALT1 EM_OPENRISC_OLD
b3baf5d0
NC
528#define ELF_MAXPAGESIZE 0x1000
529
530#define TARGET_BIG_SYM bfd_elf32_openrisc_vec
531#define TARGET_BIG_NAME "elf32-openrisc"
532
533#define elf_info_to_howto_rel NULL
534#define elf_info_to_howto openrisc_info_to_howto_rela
535#define elf_backend_relocate_section openrisc_elf_relocate_section
536#define elf_backend_gc_mark_hook openrisc_elf_gc_mark_hook
b3baf5d0
NC
537#define elf_backend_check_relocs openrisc_elf_check_relocs
538
539#define elf_backend_can_gc_sections 1
b491616a 540#define elf_backend_rela_normal 1
b3baf5d0
NC
541
542#define bfd_elf32_bfd_reloc_type_lookup openrisc_reloc_type_lookup
543
544#define elf_backend_object_p openrisc_elf_object_p
545#define elf_backend_final_write_processing openrisc_elf_final_write_processing
546
547#include "elf32-target.h"
This page took 0.560373 seconds and 4 git commands to generate.