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