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