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