131183Speter/* OR32-specific support for 32-bit ELF
292686Sdarrenr   Copyright 2002, 2004 Free Software Foundation, Inc.
392686Sdarrenr   Contributed by Ivan Guzvinec  <ivang@opencores.org>
492686Sdarrenr
592686Sdarrenr   This file is part of BFD, the Binary File Descriptor library.
692686Sdarrenr
792686Sdarrenr   This program is free software; you can redistribute it and/or modify
892686Sdarrenr   it under the terms of the GNU General Public License as published by
992686Sdarrenr   the Free Software Foundation; either version 2 of the License, or
1092686Sdarrenr   (at your option) any later version.
1192686Sdarrenr
1231183Speter   This program is distributed in the hope that it will be useful,
1331183Speter   but WITHOUT ANY WARRANTY; without even the implied warranty of
14145510Sdarrenr   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15145510Sdarrenr   GNU General Public License for more details.
16145510Sdarrenr
1731183Speter   You should have received a copy of the GNU General Public License
1892686Sdarrenr   along with this program; if not, write to the Free Software
1931183Speter   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
2031183Speter
21145510Sdarrenr#include "bfd.h"
2231183Speter#include "sysdep.h"
2331183Speter#include "libbfd.h"
24145510Sdarrenr#include "elf-bfd.h"
25#include "elf/or32.h"
26#include "libiberty.h"
27
28static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
29  PARAMS ((bfd *, bfd_reloc_code_real_type));
30static void or32_info_to_howto_rel
31  PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
32static bfd_boolean or32_elf_object_p
33  PARAMS ((bfd *));
34static void or32_elf_final_write_processing
35  PARAMS ((bfd *, bfd_boolean));
36static bfd_reloc_status_type or32_elf_32_reloc
37  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
38static bfd_reloc_status_type or32_elf_16_reloc
39  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
40static bfd_reloc_status_type or32_elf_8_reloc
41  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
42static bfd_reloc_status_type or32_elf_const_reloc
43  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
44static bfd_reloc_status_type or32_elf_consth_reloc
45  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
46static bfd_reloc_status_type or32_elf_jumptarg_reloc
47  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
48
49/* Try to minimize the amount of space occupied by relocation tables
50   on the ROM (not that the ROM won't be swamped by other ELF overhead).  */
51#define USE_REL	1
52
53static reloc_howto_type elf_or32_howto_table[] =
54{
55  /* This reloc does nothing.  */
56  HOWTO (R_OR32_NONE,		/* type */
57	 0,			/* rightshift */
58	 2,			/* size (0 = byte, 1 = short, 2 = long) */
59	 32,			/* bitsize */
60	 FALSE,			/* pc_relative */
61	 0,			/* bitpos */
62	 complain_overflow_bitfield, /* complain_on_overflow */
63	 bfd_elf_generic_reloc,	/* special_function */
64	 "R_OR32_NONE",		/* name */
65	 FALSE,			/* partial_inplace */
66	 0,			/* src_mask */
67	 0,			/* dst_mask */
68	 FALSE),		/* pcrel_offset */
69
70  /* A standard 32 bit relocation.  */
71  HOWTO (R_OR32_32,		/* type */
72	 0,	                /* rightshift */
73	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
74	 32,	                /* bitsize */
75	 FALSE,	                /* pc_relative */
76	 0,	                /* bitpos */
77	 complain_overflow_bitfield, /* complain_on_overflow */
78	 or32_elf_32_reloc, 	/* special_function */
79	 "R_OR32_32",		/* name */
80	 FALSE,	                /* partial_inplace */
81	 0xffffffff,	        /* src_mask */
82	 0xffffffff,   		/* dst_mask */
83	 FALSE),                /* pcrel_offset */
84
85  /* A standard 16 bit relocation.  */
86  HOWTO (R_OR32_16,		/* type */
87	 0,	                /* rightshift */
88	 1,	                /* size (0 = byte, 1 = short, 2 = long) */
89	 16,	                /* bitsize */
90	 FALSE,	                /* pc_relative */
91	 0,	                /* bitpos */
92	 complain_overflow_bitfield, /* complain_on_overflow */
93	 or32_elf_16_reloc, 	/* special_function */
94	 "R_OR32_16",		/* name */
95	 FALSE,	                /* partial_inplace */
96	 0x0000ffff,	        /* src_mask */
97	 0x0000ffff,   		/* dst_mask */
98	 FALSE),                /* pcrel_offset */
99
100  /* A standard 8 bit relocation.  */
101  HOWTO (R_OR32_8,		/* type */
102	 0,	                /* rightshift */
103	 0,	                /* size (0 = byte, 1 = short, 2 = long) */
104	 8,	                /* bitsize */
105	 FALSE,	                /* pc_relative */
106	 0,	                /* bitpos */
107	 complain_overflow_bitfield, /* complain_on_overflow */
108	 or32_elf_8_reloc, 	/* special_function */
109	 "R_OR32_8",		/* name */
110	 FALSE,	                /* partial_inplace */
111	 0x000000ff,	        /* src_mask */
112	 0x000000ff,   		/* dst_mask */
113	 FALSE),                /* pcrel_offset */
114
115  /* A standard low 16 bit relocation.  */
116  HOWTO (R_OR32_CONST,		/* type */
117	 0,			/* rightshift */
118	 2,			/* size (0 = byte, 1 = short, 2 = long) */
119	 16,			/* bitsize */
120	 FALSE,			/* pc_relative */
121	 0,			/* bitpos */
122	 complain_overflow_dont, /* complain_on_overflow */
123	 or32_elf_const_reloc,	/* special_function */
124	 "R_OR32_CONST",	/* name */
125	 FALSE,			/* partial_inplace */
126	 0x0000ffff,		/* src_mask */
127	 0x0000ffff,		/* dst_mask */
128	 FALSE),		/* pcrel_offset */
129
130  /* A standard high 16 bit relocation.  */
131  HOWTO (R_OR32_CONSTH,		/* type */
132	 16,			/* rightshift */
133	 2,			/* size (0 = byte, 1 = short, 2 = long) */
134	 16,			/* bitsize */
135	 TRUE,			/* pc_relative */
136	 0,			/* bitpos */
137	 complain_overflow_dont, /* complain_on_overflow */
138	 or32_elf_consth_reloc,	/* special_function */
139	 "R_OR32_CONSTH",	/* name */
140	 FALSE,			/* partial_inplace */
141	 0xffff0000,		/* src_mask */
142	 0x0000ffff,		/* dst_mask */
143	 FALSE),		/* pcrel_offset */
144
145  /* A standard branch relocation.  */
146  HOWTO (R_OR32_JUMPTARG,	/* type */
147	 2,			/* rightshift */
148	 2,			/* size (0 = byte, 1 = short, 2 = long) */
149	 28,			/* bitsize */
150	 TRUE,			/* pc_relative */
151	 0,			/* bitpos */
152	 complain_overflow_signed, /* complain_on_overflow */
153	 or32_elf_jumptarg_reloc,/* special_function */
154	 "R_OR32_JUMPTARG",	/* name */
155	 FALSE,			/* partial_inplace */
156	 0,			/* src_mask */
157	 0x03ffffff,		/* dst_mask */
158	 TRUE), 		/* pcrel_offset */
159
160  /* GNU extension to record C++ vtable hierarchy.  */
161  HOWTO (R_OR32_GNU_VTINHERIT, /* type */
162         0,                     /* rightshift */
163         2,                     /* size (0 = byte, 1 = short, 2 = long) */
164         0,                     /* bitsize */
165         FALSE,                 /* pc_relative */
166         0,                     /* bitpos */
167         complain_overflow_dont, /* complain_on_overflow */
168         NULL,                  /* special_function */
169         "R_OR32_GNU_VTINHERIT", /* name */
170         FALSE,                 /* partial_inplace */
171         0,                     /* src_mask */
172         0,                     /* dst_mask */
173         FALSE),                /* pcrel_offset */
174
175  /* GNU extension to record C++ vtable member usage.  */
176  HOWTO (R_OR32_GNU_VTENTRY,     /* type */
177         0,                     /* rightshift */
178         2,                     /* size (0 = byte, 1 = short, 2 = long) */
179         0,                     /* bitsize */
180         FALSE,                 /* pc_relative */
181         0,                     /* bitpos */
182         complain_overflow_dont, /* complain_on_overflow */
183         _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
184         "R_OR32_GNU_VTENTRY",   /* name */
185         FALSE,                 /* partial_inplace */
186         0,                     /* src_mask */
187         0,                     /* dst_mask */
188         FALSE),                /* pcrel_offset */
189};
190
191/* Map BFD reloc types to OR32 ELF reloc types.  */
192
193struct or32_reloc_map
194{
195  bfd_reloc_code_real_type  bfd_reloc_val;
196  unsigned char             elf_reloc_val;
197};
198
199static const struct or32_reloc_map or32_reloc_map[] =
200{
201  { BFD_RELOC_NONE, R_OR32_NONE },
202  { BFD_RELOC_32, R_OR32_32 },
203  { BFD_RELOC_16, R_OR32_16 },
204  { BFD_RELOC_8, R_OR32_8 },
205  { BFD_RELOC_LO16, R_OR32_CONST },
206  { BFD_RELOC_HI16, R_OR32_CONSTH },
207  { BFD_RELOC_32_GOT_PCREL, R_OR32_JUMPTARG },
208  { BFD_RELOC_VTABLE_INHERIT, R_OR32_GNU_VTINHERIT },
209  { BFD_RELOC_VTABLE_ENTRY, R_OR32_GNU_VTENTRY },
210};
211
212static reloc_howto_type *
213bfd_elf32_bfd_reloc_type_lookup (abfd, code)
214     bfd *abfd ATTRIBUTE_UNUSED;
215     bfd_reloc_code_real_type code;
216{
217  unsigned int i;
218
219  for (i = ARRAY_SIZE (or32_reloc_map); i--;)
220    {
221      if (or32_reloc_map[i].bfd_reloc_val == code)
222	return &elf_or32_howto_table[or32_reloc_map[i].elf_reloc_val];
223    }
224
225  return NULL;
226}
227
228/* Set the howto pointer for an OR32 ELF reloc.  */
229
230static void
231or32_info_to_howto_rel (abfd, cache_ptr, dst)
232     bfd *abfd ATTRIBUTE_UNUSED;
233     arelent *cache_ptr;
234     Elf_Internal_Rela *dst;
235{
236  unsigned int r_type;
237
238  r_type = ELF32_R_TYPE (dst->r_info);
239  BFD_ASSERT (r_type < (unsigned int) R_OR32_max);
240  cache_ptr->howto = &elf_or32_howto_table[r_type];
241}
242
243/* Set the right machine number for an OR32 ELF file.  */
244
245static bfd_boolean
246or32_elf_object_p (abfd)
247     bfd *abfd;
248{
249  (void) bfd_default_set_arch_mach (abfd, bfd_arch_or32, 0);
250  return TRUE;
251}
252
253/* The final processing done just before writing out an OR32 ELF object file.
254   This gets the OR32 architecture right based on the machine number.  */
255
256static void
257or32_elf_final_write_processing (abfd, linker)
258     bfd *abfd;
259     bfd_boolean linker ATTRIBUTE_UNUSED;
260{
261  int mach;
262  unsigned long val;
263
264  switch (mach = bfd_get_mach (abfd))
265    {
266    /*
267    case bfd_mach_arc_base:
268      val = E_OR32_MACH_BASE;
269      break;
270    */
271    default:
272      val = 0;
273      return;
274    }
275
276  elf_elfheader (abfd)->e_flags &=~ EF_OR32_MACH;
277  elf_elfheader (abfd)->e_flags |= val;
278}
279
280bfd_reloc_status_type
281or32_elf_32_reloc (abfd, reloc_entry, symbol, data, input_section,
282		   output_bfd, error_message)
283     bfd *abfd;
284     arelent *reloc_entry;
285     asymbol *symbol;
286     PTR data;
287     asection *input_section;
288     bfd *output_bfd;
289     char **error_message ATTRIBUTE_UNUSED;
290{
291  if (output_bfd != (bfd *) NULL)
292    {
293      unsigned long insn;
294      bfd_size_type addr = reloc_entry->address;
295
296      reloc_entry->address += input_section->output_offset;
297
298      insn = bfd_get_32 (abfd, (bfd_byte *) data + addr);
299      insn += symbol->section->output_section->vma;
300      insn += symbol->section->output_offset;
301      insn += symbol->value;
302      bfd_put_32 (abfd, insn, (bfd_byte *) data + addr);
303
304      return bfd_reloc_ok;
305    }
306
307  return bfd_reloc_continue;
308}
309
310bfd_reloc_status_type
311or32_elf_16_reloc (abfd, reloc_entry, symbol, data, input_section,
312		   output_bfd, error_message)
313     bfd *abfd;
314     arelent *reloc_entry;
315     asymbol *symbol;
316     PTR data;
317     asection *input_section;
318     bfd *output_bfd;
319     char **error_message ATTRIBUTE_UNUSED;
320{
321  if (output_bfd != (bfd *) NULL)
322    {
323      unsigned short insn;
324      bfd_size_type addr = reloc_entry->address;
325
326      reloc_entry->address += input_section->output_offset;
327
328      insn = bfd_get_16 (abfd, (bfd_byte *) data + addr);
329      insn += symbol->section->output_section->vma;
330      insn += symbol->section->output_offset;
331      insn += symbol->value;
332      bfd_put_16 (abfd, insn, (bfd_byte *) data + addr);
333
334      return bfd_reloc_ok;
335    }
336
337  return bfd_reloc_continue;
338}
339
340bfd_reloc_status_type
341or32_elf_8_reloc (abfd, reloc_entry, symbol, data, input_section,
342		  output_bfd, error_message)
343     bfd *abfd ATTRIBUTE_UNUSED;
344     arelent *reloc_entry;
345     asymbol *symbol;
346     PTR data;
347     asection *input_section;
348     bfd *output_bfd;
349     char **error_message ATTRIBUTE_UNUSED;
350{
351  if (output_bfd != (bfd *) NULL)
352    {
353      unsigned char insn;
354      bfd_size_type addr = reloc_entry->address;
355
356      reloc_entry->address += input_section->output_offset;
357
358      insn = bfd_get_8 (abfd, (bfd_byte *) data + addr);
359      insn += symbol->section->output_section->vma;
360      insn += symbol->section->output_offset;
361      insn += symbol->value;
362      bfd_put_8 (abfd, insn, (bfd_byte *) data + addr);
363
364      return bfd_reloc_ok;
365    }
366
367  return bfd_reloc_continue;
368}
369
370/* Do a R_OR32_CONSTH relocation.  This has to be done in combination
371   with a R_OR32_CONST reloc, because there is a carry from the LO16 to
372   the HI16.  Here we just save the information we need; we do the
373   actual relocation when we see the LO16.  OR32 ELF requires that the
374   LO16 immediately follow the HI16.  As a GNU extension, we permit an
375   arbitrary number of HI16 relocs to be associated with a single LO16
376   reloc.  This extension permits gcc to output the HI and LO relocs
377   itself. This code is copied from the elf32-mips.c.  */
378
379struct or32_consth
380{
381  struct or32_consth *next;
382  bfd_byte *addr;
383  bfd_vma addend;
384};
385
386/* FIXME: This should not be a static variable.  */
387
388static struct or32_consth *or32_consth_list;
389
390bfd_reloc_status_type
391or32_elf_consth_reloc (abfd, reloc_entry, symbol, data, input_section,
392		       output_bfd, error_message)
393     bfd *abfd ATTRIBUTE_UNUSED;
394     arelent *reloc_entry;
395     asymbol *symbol;
396     PTR data;
397     asection *input_section;
398     bfd *output_bfd;
399     char **error_message ATTRIBUTE_UNUSED;
400{
401  bfd_reloc_status_type ret;
402  bfd_vma relocation;
403  struct or32_consth *n;
404
405  ret = bfd_reloc_ok;
406
407  if (bfd_is_und_section (symbol->section)
408      && output_bfd == (bfd *) NULL)
409    ret = bfd_reloc_undefined;
410
411  if (bfd_is_com_section (symbol->section))
412    relocation = 0;
413  else
414    relocation = symbol->value;
415
416  relocation += symbol->section->output_section->vma;
417  relocation += symbol->section->output_offset;
418  relocation += reloc_entry->addend;
419
420  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
421    return bfd_reloc_outofrange;
422
423  /* Save the information, and let LO16 do the actual relocation.  */
424  n = (struct or32_consth *) bfd_malloc (sizeof *n);
425  if (n == NULL)
426    return bfd_reloc_outofrange;
427  n->addr = (bfd_byte *) data + reloc_entry->address;
428  n->addend = relocation;
429  n->next = or32_consth_list;
430  or32_consth_list = n;
431
432  if (output_bfd != (bfd *) NULL)
433    reloc_entry->address += input_section->output_offset;
434
435  return ret;
436}
437
438/* Do a R_OR32_CONST relocation.  This is a straightforward 16 bit
439   inplace relocation; this function exists in order to do the
440   R_OR32_CONSTH relocation described above.  */
441
442bfd_reloc_status_type
443or32_elf_const_reloc (abfd, reloc_entry, symbol, data, input_section,
444		      output_bfd, error_message)
445     bfd *abfd;
446     arelent *reloc_entry;
447     asymbol *symbol;
448     PTR data;
449     asection *input_section;
450     bfd *output_bfd;
451     char **error_message;
452{
453  if (or32_consth_list != NULL)
454    {
455      struct or32_consth *l;
456
457      l = or32_consth_list;
458      while (l != NULL)
459	{
460	  unsigned long insn;
461	  unsigned long val;
462          unsigned long vallo;
463	  struct or32_consth *next;
464
465	  /* Do the HI16 relocation.  Note that we actually don't need
466	     to know anything about the LO16 itself, except where to
467	     find the low 16 bits of the addend needed by the LO16.  */
468	  insn = bfd_get_32 (abfd, l->addr);
469	  vallo = (bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address)
470		   & 0xffff);
471	  val = ((insn & 0xffff) << 16) + vallo;
472	  val += l->addend;
473
474	  insn = (insn &~ 0xffff) | ((val >> 16) & 0xffff);
475	  bfd_put_32 (abfd, insn, l->addr);
476
477	  next = l->next;
478	  free (l);
479	  l = next;
480	}
481
482      or32_consth_list = NULL;
483    }
484
485  if (output_bfd != (bfd *) NULL)
486    {
487      unsigned long insn, tmp;
488      bfd_size_type addr = reloc_entry->address;
489
490      reloc_entry->address += input_section->output_offset;
491
492      insn = bfd_get_32 (abfd, (bfd_byte *) data + addr);
493      tmp = insn & 0x0000ffff;
494      tmp += symbol->section->output_section->vma;
495      tmp += symbol->section->output_offset;
496      tmp += symbol->value;
497      insn = (insn & 0xffff0000) | (tmp & 0x0000ffff);
498      bfd_put_32 (abfd, insn, (bfd_byte *) data + addr);
499
500      return bfd_reloc_ok;
501    }
502
503  /* Now do the LO16 reloc in the usual way.  */
504  return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
505				input_section, output_bfd, error_message);
506}
507
508bfd_reloc_status_type
509or32_elf_jumptarg_reloc (abfd, reloc_entry, symbol, data, input_section,
510			 output_bfd, error_message)
511     bfd *abfd;
512     arelent *reloc_entry;
513     asymbol *symbol ATTRIBUTE_UNUSED;
514     PTR data;
515     asection *input_section;
516     bfd *output_bfd;
517     char **error_message ATTRIBUTE_UNUSED;
518{
519  if (output_bfd != (bfd *) NULL)
520    {
521      unsigned long insn, tmp;
522      bfd_size_type addr = reloc_entry->address;
523
524      reloc_entry->address += input_section->output_offset;
525
526      insn = bfd_get_32 (abfd, (bfd_byte *) data + addr);
527      tmp = insn | 0xfc000000;
528      tmp -= (input_section->output_offset >> 2);
529      insn = (insn & 0xfc000000) | (tmp & 0x03ffffff);
530      bfd_put_32 (abfd, insn, (bfd_byte *) data + addr);
531
532      return bfd_reloc_ok;
533    }
534
535  return bfd_reloc_continue;
536}
537
538#define TARGET_LITTLE_SYM	bfd_elf32_or32_little_vec
539#define TARGET_LITTLE_NAME	"elf32-littleor32"
540#define TARGET_BIG_SYM		bfd_elf32_or32_big_vec
541#define TARGET_BIG_NAME		"elf32-or32"
542#define ELF_ARCH		bfd_arch_or32
543#define ELF_MACHINE_CODE	EM_OR32
544#define ELF_MAXPAGESIZE		0x1000
545
546#define elf_info_to_howto	0
547#define elf_info_to_howto_rel	or32_info_to_howto_rel
548#define elf_backend_object_p	or32_elf_object_p
549#define elf_backend_final_write_processing \
550				or32_elf_final_write_processing
551
552#include "elf32-target.h"
553