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>
4
5   This file is part of BFD, the Binary File Descriptor library.
6
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.
11
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.
16
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.  */
20
21#include "bfd.h"
22#include "sysdep.h"
23#include "libbfd.h"
24#include "elf-bfd.h"
25#include "elf/or32.h"
26#include "libiberty.h"
27
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).  */
30#define USE_REL	1
31
32/* Set the right machine number for an OR32 ELF file.  */
33
34static bfd_boolean
35or32_elf_object_p (bfd *abfd)
36{
37  (void) bfd_default_set_arch_mach (abfd, bfd_arch_or32, 0);
38  return TRUE;
39}
40
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.  */
43
44static void
45or32_elf_final_write_processing (bfd *abfd,
46				 bfd_boolean linker ATTRIBUTE_UNUSED)
47{
48  elf_elfheader (abfd)->e_flags &=~ EF_OR32_MACH;
49}
50
51static bfd_reloc_status_type
52or32_elf_32_reloc (bfd *abfd,
53		   arelent *reloc_entry,
54		   asymbol *symbol,
55		   void * data,
56		   asection *input_section,
57		   bfd *output_bfd,
58		   char **error_message ATTRIBUTE_UNUSED)
59{
60  if (output_bfd != NULL)
61    {
62      unsigned long insn;
63      bfd_size_type addr = reloc_entry->address;
64
65      reloc_entry->address += input_section->output_offset;
66
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);
72
73      return bfd_reloc_ok;
74    }
75
76  return bfd_reloc_continue;
77}
78
79static bfd_reloc_status_type
80or32_elf_16_reloc (bfd *abfd,
81		   arelent *reloc_entry,
82		   asymbol *symbol,
83		   void * data,
84		   asection *input_section,
85		   bfd *output_bfd,
86		   char **error_message ATTRIBUTE_UNUSED)
87{
88  if (output_bfd != NULL)
89    {
90      unsigned short insn;
91      bfd_size_type addr = reloc_entry->address;
92
93      reloc_entry->address += input_section->output_offset;
94
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);
100
101      return bfd_reloc_ok;
102    }
103
104  return bfd_reloc_continue;
105}
106
107static bfd_reloc_status_type
108or32_elf_8_reloc (bfd *abfd ATTRIBUTE_UNUSED,
109		  arelent *reloc_entry,
110		  asymbol *symbol,
111		  void * data,
112		  asection *input_section,
113		  bfd *output_bfd,
114		  char **error_message ATTRIBUTE_UNUSED)
115{
116  if (output_bfd != NULL)
117    {
118      unsigned char insn;
119      bfd_size_type addr = reloc_entry->address;
120
121      reloc_entry->address += input_section->output_offset;
122
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);
128
129      return bfd_reloc_ok;
130    }
131
132  return bfd_reloc_continue;
133}
134
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.  */
143
144struct or32_consth
145{
146  struct or32_consth *next;
147  bfd_byte *addr;
148  bfd_vma addend;
149};
150
151/* FIXME: This should not be a static variable.  */
152
153static struct or32_consth *or32_consth_list;
154
155static bfd_reloc_status_type
156or32_elf_consth_reloc (bfd *abfd ATTRIBUTE_UNUSED,
157		       arelent *reloc_entry,
158		       asymbol *symbol,
159		       void * data,
160		       asection *input_section,
161		       bfd *output_bfd,
162		       char **error_message ATTRIBUTE_UNUSED)
163{
164  bfd_reloc_status_type ret;
165  bfd_vma relocation;
166  struct or32_consth *n;
167
168  ret = bfd_reloc_ok;
169
170  if (bfd_is_und_section (symbol->section)
171      && output_bfd == NULL)
172    ret = bfd_reloc_undefined;
173
174  if (bfd_is_com_section (symbol->section))
175    relocation = 0;
176  else
177    relocation = symbol->value;
178
179  relocation += symbol->section->output_section->vma;
180  relocation += symbol->section->output_offset;
181  relocation += reloc_entry->addend;
182
183  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
184    return bfd_reloc_outofrange;
185
186  /* Save the information, and let LO16 do the actual relocation.  */
187  n = bfd_malloc (sizeof *n);
188  if (n == NULL)
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;
194
195  if (output_bfd != NULL)
196    reloc_entry->address += input_section->output_offset;
197
198  return ret;
199}
200
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.  */
204
205static bfd_reloc_status_type
206or32_elf_const_reloc (bfd *abfd,
207		      arelent *reloc_entry,
208		      asymbol *symbol,
209		      void * data,
210		      asection *input_section,
211		      bfd *output_bfd,
212		      char **error_message)
213{
214  if (or32_consth_list != NULL)
215    {
216      struct or32_consth *l;
217
218      l = or32_consth_list;
219      while (l != NULL)
220	{
221	  unsigned long insn;
222	  unsigned long val;
223          unsigned long vallo;
224	  struct or32_consth *next;
225
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)
231		   & 0xffff);
232	  val = ((insn & 0xffff) << 16) + vallo;
233	  val += l->addend;
234
235	  insn = (insn &~ 0xffff) | ((val >> 16) & 0xffff);
236	  bfd_put_32 (abfd, insn, l->addr);
237
238	  next = l->next;
239	  free (l);
240	  l = next;
241	}
242
243      or32_consth_list = NULL;
244    }
245
246  if (output_bfd != NULL)
247    {
248      unsigned long insn, tmp;
249      bfd_size_type addr = reloc_entry->address;
250
251      reloc_entry->address += input_section->output_offset;
252
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);
260
261      return bfd_reloc_ok;
262    }
263
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);
267}
268
269static bfd_reloc_status_type
270or32_elf_jumptarg_reloc (bfd *abfd,
271			 arelent *reloc_entry,
272			 asymbol *symbol ATTRIBUTE_UNUSED,
273			 void * data,
274			 asection *input_section,
275			 bfd *output_bfd,
276			 char **error_message ATTRIBUTE_UNUSED)
277{
278  if (output_bfd != NULL)
279    {
280      unsigned long insn, tmp;
281      bfd_size_type addr = reloc_entry->address;
282
283      reloc_entry->address += input_section->output_offset;
284
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);
290
291      return bfd_reloc_ok;
292    }
293
294  return bfd_reloc_continue;
295}
296
297static reloc_howto_type elf_or32_howto_table[] =
298{
299  /* This reloc does nothing.  */
300  HOWTO (R_OR32_NONE,		/* type */
301	 0,			/* rightshift */
302	 2,			/* size (0 = byte, 1 = short, 2 = long) */
303	 32,			/* bitsize */
304	 FALSE,			/* pc_relative */
305	 0,			/* bitpos */
306	 complain_overflow_bitfield, /* complain_on_overflow */
307	 bfd_elf_generic_reloc,	/* special_function */
308	 "R_OR32_NONE",		/* name */
309	 FALSE,			/* partial_inplace */
310	 0,			/* src_mask */
311	 0,			/* dst_mask */
312	 FALSE),		/* pcrel_offset */
313
314  /* A standard 32 bit relocation.  */
315  HOWTO (R_OR32_32,		/* type */
316	 0,	                /* rightshift */
317	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
318	 32,	                /* bitsize */
319	 FALSE,	                /* pc_relative */
320	 0,	                /* bitpos */
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 */
328
329  /* A standard 16 bit relocation.  */
330  HOWTO (R_OR32_16,		/* type */
331	 0,	                /* rightshift */
332	 1,	                /* size (0 = byte, 1 = short, 2 = long) */
333	 16,	                /* bitsize */
334	 FALSE,	                /* pc_relative */
335	 0,	                /* bitpos */
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 */
343
344  /* A standard 8 bit relocation.  */
345  HOWTO (R_OR32_8,		/* type */
346	 0,	                /* rightshift */
347	 0,	                /* size (0 = byte, 1 = short, 2 = long) */
348	 8,	                /* bitsize */
349	 FALSE,	                /* pc_relative */
350	 0,	                /* bitpos */
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 */
358
359  /* A standard low 16 bit relocation.  */
360  HOWTO (R_OR32_CONST,		/* type */
361	 0,			/* rightshift */
362	 2,			/* size (0 = byte, 1 = short, 2 = long) */
363	 16,			/* bitsize */
364	 FALSE,			/* pc_relative */
365	 0,			/* bitpos */
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 */
373
374  /* A standard high 16 bit relocation.  */
375  HOWTO (R_OR32_CONSTH,		/* type */
376	 16,			/* rightshift */
377	 2,			/* size (0 = byte, 1 = short, 2 = long) */
378	 16,			/* bitsize */
379	 TRUE,			/* pc_relative */
380	 0,			/* bitpos */
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 */
388
389  /* A standard branch relocation.  */
390  HOWTO (R_OR32_JUMPTARG,	/* type */
391	 2,			/* rightshift */
392	 2,			/* size (0 = byte, 1 = short, 2 = long) */
393	 28,			/* bitsize */
394	 TRUE,			/* pc_relative */
395	 0,			/* bitpos */
396	 complain_overflow_signed, /* complain_on_overflow */
397	 or32_elf_jumptarg_reloc,/* special_function */
398	 "R_OR32_JUMPTARG",	/* name */
399	 FALSE,			/* partial_inplace */
400	 0,			/* src_mask */
401	 0x03ffffff,		/* dst_mask */
402	 TRUE), 		/* pcrel_offset */
403
404  /* GNU extension to record C++ vtable hierarchy.  */
405  HOWTO (R_OR32_GNU_VTINHERIT, /* type */
406         0,                     /* rightshift */
407         2,                     /* size (0 = byte, 1 = short, 2 = long) */
408         0,                     /* bitsize */
409         FALSE,                 /* pc_relative */
410         0,                     /* bitpos */
411         complain_overflow_dont, /* complain_on_overflow */
412         NULL,                  /* special_function */
413         "R_OR32_GNU_VTINHERIT", /* name */
414         FALSE,                 /* partial_inplace */
415         0,                     /* src_mask */
416         0,                     /* dst_mask */
417         FALSE),                /* pcrel_offset */
418
419  /* GNU extension to record C++ vtable member usage.  */
420  HOWTO (R_OR32_GNU_VTENTRY,     /* type */
421         0,                     /* rightshift */
422         2,                     /* size (0 = byte, 1 = short, 2 = long) */
423         0,                     /* bitsize */
424         FALSE,                 /* pc_relative */
425         0,                     /* bitpos */
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 */
430         0,                     /* src_mask */
431         0,                     /* dst_mask */
432         FALSE),                /* pcrel_offset */
433};
434
435/* Map BFD reloc types to OR32 ELF reloc types.  */
436
437struct or32_reloc_map
438{
439  bfd_reloc_code_real_type  bfd_reloc_val;
440  unsigned char             elf_reloc_val;
441};
442
443static const struct or32_reloc_map or32_reloc_map[] =
444{
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 },
454};
455
456static reloc_howto_type *
457bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
458				 bfd_reloc_code_real_type code)
459{
460  unsigned int i;
461
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];
465
466  return NULL;
467}
468
469/* Set the howto pointer for an OR32 ELF reloc.  */
470
471static void
472or32_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
473			arelent *cache_ptr,
474			Elf_Internal_Rela *dst)
475{
476  unsigned int r_type;
477
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];
481}
482
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
490
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
496
497#include "elf32-target.h"
498