1/* ARC-specific support for 32-bit ELF
2   Copyright 1994, 1995, 1997, 1999, 2001, 2002
3   Free Software Foundation, Inc.
4   Contributed by Doug Evans (dje@cygnus.com).
5
6   This file is part of BFD, the Binary File Descriptor library.
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
21
22#include "bfd.h"
23#include "sysdep.h"
24#include "libbfd.h"
25#include "elf-bfd.h"
26#include "elf/arc.h"
27#include "libiberty.h"
28
29static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
30  PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
31static void arc_info_to_howto_rel
32  PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
33static bfd_boolean arc_elf_object_p
34  PARAMS ((bfd *));
35static void arc_elf_final_write_processing
36  PARAMS ((bfd *, bfd_boolean));
37static bfd_reloc_status_type arc_elf_b22_pcrel
38  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
39
40/* Try to minimize the amount of space occupied by relocation tables
41   on the ROM (not that the ROM won't be swamped by other ELF overhead).  */
42
43#define USE_REL	1
44
45static reloc_howto_type elf_arc_howto_table[] =
46{
47  /* This reloc does nothing.  */
48  HOWTO (R_ARC_NONE,		/* type  */
49	 0,			/* rightshift  */
50	 2,			/* size (0 = byte, 1 = short, 2 = long)  */
51	 32,			/* bitsize  */
52	 FALSE,			/* pc_relative  */
53	 0,			/* bitpos  */
54	 complain_overflow_bitfield, /* complain_on_overflow  */
55	 bfd_elf_generic_reloc,	/* special_function  */
56	 "R_ARC_NONE",		/* name  */
57	 TRUE,			/* partial_inplace  */
58	 0,			/* src_mask  */
59	 0,			/* dst_mask  */
60	 FALSE),		/* pcrel_offset  */
61
62  /* A standard 32 bit relocation.  */
63  HOWTO (R_ARC_32,		/* type  */
64	 0,			/* rightshift  */
65	 2,			/* size (0 = byte, 1 = short, 2 = long)  */
66	 32,			/* bitsize  */
67	 FALSE,			/* pc_relative  */
68	 0,			/* bitpos  */
69	 complain_overflow_bitfield, /* complain_on_overflow  */
70	 bfd_elf_generic_reloc,	/* special_function  */
71	 "R_ARC_32",		/* name  */
72	 TRUE,			/* partial_inplace  */
73	 0xffffffff,		/* src_mask  */
74	 0xffffffff,		/* dst_mask  */
75	 FALSE),		/* pcrel_offset  */
76
77  /* A 26 bit absolute branch, right shifted by 2.  */
78  HOWTO (R_ARC_B26,		/* type  */
79	 2,			/* rightshift  */
80	 2,			/* size (0 = byte, 1 = short, 2 = long)  */
81	 26,			/* bitsize  */
82	 FALSE,			/* pc_relative  */
83	 0,			/* bitpos  */
84	 complain_overflow_bitfield, /* complain_on_overflow  */
85	 bfd_elf_generic_reloc,	/* special_function  */
86	 "R_ARC_B26",		/* name  */
87	 TRUE,			/* partial_inplace  */
88	 0x00ffffff,		/* src_mask  */
89	 0x00ffffff,		/* dst_mask  */
90	 FALSE),		/* pcrel_offset  */
91
92  /* A relative 22 bit branch; bits 21-2 are stored in bits 26-7.  */
93  HOWTO (R_ARC_B22_PCREL,	/* type  */
94	 2,			/* rightshift  */
95	 2,			/* size (0 = byte, 1 = short, 2 = long)  */
96	 22,			/* bitsize  */
97	 TRUE,			/* pc_relative  */
98	 7,			/* bitpos  */
99	 complain_overflow_signed, /* complain_on_overflow  */
100	 arc_elf_b22_pcrel,	/* special_function  */
101	 "R_ARC_B22_PCREL",	/* name  */
102	 TRUE,			/* partial_inplace  */
103	 0x07ffff80,		/* src_mask  */
104	 0x07ffff80,		/* dst_mask  */
105	 FALSE),		/* pcrel_offset  */
106};
107
108/* Map BFD reloc types to ARC ELF reloc types.  */
109
110struct arc_reloc_map
111{
112  bfd_reloc_code_real_type bfd_reloc_val;
113  unsigned char elf_reloc_val;
114};
115
116static const struct arc_reloc_map arc_reloc_map[] =
117{
118  { BFD_RELOC_NONE, R_ARC_NONE, },
119  { BFD_RELOC_32, R_ARC_32 },
120  { BFD_RELOC_CTOR, R_ARC_32 },
121  { BFD_RELOC_ARC_B26, R_ARC_B26 },
122  { BFD_RELOC_ARC_B22_PCREL, R_ARC_B22_PCREL },
123};
124
125static reloc_howto_type *
126bfd_elf32_bfd_reloc_type_lookup (abfd, code)
127     bfd *abfd ATTRIBUTE_UNUSED;
128     bfd_reloc_code_real_type code;
129{
130  unsigned int i;
131
132  for (i = ARRAY_SIZE (arc_reloc_map); i--;)
133    if (arc_reloc_map[i].bfd_reloc_val == code)
134      return elf_arc_howto_table + arc_reloc_map[i].elf_reloc_val;
135
136  return NULL;
137}
138
139/* Set the howto pointer for an ARC ELF reloc.  */
140
141static void
142arc_info_to_howto_rel (abfd, cache_ptr, dst)
143     bfd *abfd ATTRIBUTE_UNUSED;
144     arelent *cache_ptr;
145     Elf_Internal_Rela *dst;
146{
147  unsigned int r_type;
148
149  r_type = ELF32_R_TYPE (dst->r_info);
150  BFD_ASSERT (r_type < (unsigned int) R_ARC_max);
151  cache_ptr->howto = &elf_arc_howto_table[r_type];
152}
153
154/* Set the right machine number for an ARC ELF file.  */
155
156static bfd_boolean
157arc_elf_object_p (abfd)
158     bfd *abfd;
159{
160  unsigned int mach = bfd_mach_arc_6;
161
162  if (elf_elfheader(abfd)->e_machine == EM_ARC)
163    {
164      unsigned long arch = elf_elfheader (abfd)->e_flags & EF_ARC_MACH;
165
166      switch (arch)
167	{
168	case E_ARC_MACH_ARC5:
169	  mach = bfd_mach_arc_5;
170	  break;
171	default:
172	case E_ARC_MACH_ARC6:
173	  mach = bfd_mach_arc_6;
174	  break;
175	case E_ARC_MACH_ARC7:
176	  mach = bfd_mach_arc_7;
177	  break;
178	case E_ARC_MACH_ARC8:
179	  mach = bfd_mach_arc_8;
180	  break;
181	}
182    }
183  return bfd_default_set_arch_mach (abfd, bfd_arch_arc, mach);
184}
185
186/* The final processing done just before writing out an ARC ELF object file.
187   This gets the ARC architecture right based on the machine number.  */
188
189static void
190arc_elf_final_write_processing (abfd, linker)
191     bfd *abfd;
192     bfd_boolean linker ATTRIBUTE_UNUSED;
193{
194  unsigned long val;
195
196  switch (bfd_get_mach (abfd))
197    {
198    case bfd_mach_arc_5:
199      val = E_ARC_MACH_ARC5;
200      break;
201    default:
202    case bfd_mach_arc_6:
203      val = E_ARC_MACH_ARC6;
204      break;
205    case bfd_mach_arc_7:
206      val = E_ARC_MACH_ARC7;
207      break;
208    case bfd_mach_arc_8:
209      val = E_ARC_MACH_ARC8;
210      break;
211    }
212  elf_elfheader (abfd)->e_flags &=~ EF_ARC_MACH;
213  elf_elfheader (abfd)->e_flags |= val;
214}
215
216bfd_reloc_status_type
217arc_elf_b22_pcrel (abfd, reloc_entry, symbol, data, input_section,
218		   output_bfd, error_message)
219     bfd * abfd;
220     arelent * reloc_entry;
221     asymbol * symbol;
222     PTR data;
223     asection * input_section;
224     bfd * output_bfd;
225     char ** error_message;
226{
227  /* If linking, back up the final symbol address by the address of the
228     reloc.  This cannot be accomplished by setting the pcrel_offset
229     field to TRUE, as bfd_install_relocation will detect this and refuse
230     to install the offset in the first place, but bfd_perform_relocation
231     will still insist on removing it.  */
232  if (output_bfd == (bfd *) NULL)
233    reloc_entry->addend -= reloc_entry->address;
234
235  /* Fall through to the default elf reloc handler.  */
236  return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
237				input_section, output_bfd, error_message);
238}
239
240#define TARGET_LITTLE_SYM bfd_elf32_littlearc_vec
241#define TARGET_LITTLE_NAME "elf32-littlearc"
242#define TARGET_BIG_SYM bfd_elf32_bigarc_vec
243#define TARGET_BIG_NAME	"elf32-bigarc"
244#define ELF_ARCH bfd_arch_arc
245#define ELF_MACHINE_CODE EM_ARC
246#define ELF_MAXPAGESIZE	0x1000
247
248#define elf_info_to_howto 0
249#define elf_info_to_howto_rel arc_info_to_howto_rel
250#define elf_backend_object_p arc_elf_object_p
251#define elf_backend_final_write_processing arc_elf_final_write_processing
252
253#include "elf32-target.h"
254