Tue Feb 18 17:22:59 1997 Martin M. Hunt <hunt@pizza.cygnus.com>
[external/binutils.git] / bfd / elf32-d30v.c
1 /* D30V-specific support for 32-bit ELF
2    Copyright (C) 1997 Free Software Foundation, Inc.
3    Contributed by Martin Hunt (hunt@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
26 static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
27   PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
28 static void d30v_info_to_howto_rel
29   PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *));
30 static bfd_reloc_status_type bfd_elf_d30v_reloc PARAMS ((
31      bfd *abfd,
32      arelent *reloc_entry,
33      asymbol *symbol,
34      PTR data,
35      asection *input_section,
36      bfd *output_bfd,
37      char **error_message));
38
39 /* Use REL instead of RELA to save space */
40 #define USE_REL
41
42 enum reloc_type
43 {
44   R_D30V_NONE = 0,
45   R_D30V_6,
46   R_D30V_15,
47   R_D30V_15_PCREL,
48   R_D30V_21,
49   R_D30V_21_PCREL,
50   R_D30V_32,
51   R_D30V_32_PCREL,
52   R_D30V_32_NORMAL,
53   R_D30V_max
54 };
55
56 static reloc_howto_type elf_d30v_howto_table[] =
57 {
58   /* This reloc does nothing.  */
59   HOWTO (R_D30V_NONE,           /* type */
60          0,                     /* rightshift */
61          2,                     /* size (0 = byte, 1 = short, 2 = long) */
62          32,                    /* bitsize */
63          false,                 /* pc_relative */
64          0,                     /* bitpos */
65          complain_overflow_bitfield, /* complain_on_overflow */
66          bfd_elf_generic_reloc, /* special_function */
67          "R_D30V_NONE",         /* name */
68          false,                 /* partial_inplace */
69          0,                     /* src_mask */
70          0,                     /* dst_mask */
71          false),                /* pcrel_offset */
72
73   /* A 6 bit absolute relocation */
74   HOWTO (R_D30V_6,              /* type */
75          0,                     /* rightshift */
76          2,                     /* size (0 = byte, 1 = short, 2 = long) */
77          6,                     /* bitsize */
78          false,                 /* pc_relative */
79          0,                     /* bitpos */
80          complain_overflow_bitfield, /* complain_on_overflow */
81          bfd_elf_generic_reloc, /* special_function */
82          "R_D30V_6",            /* name */
83          false,                 /* partial_inplace */
84          0x3f,                  /* src_mask */
85          0x3f,                  /* dst_mask */
86          false),                /* pcrel_offset */
87
88   /* An absolute 15 bit relocation, right shifted by 3 */
89   HOWTO (R_D30V_15,             /* type */
90          3,                     /* rightshift */
91          2,                     /* size (0 = byte, 1 = short, 2 = long) */
92          15,                    /* bitsize */
93          false,                 /* pc_relative */
94          0,                     /* bitpos */
95          complain_overflow_signed, /* complain_on_overflow */
96          bfd_elf_generic_reloc, /* special_function */
97          "R_D30V_15",           /* name */
98          false,                 /* partial_inplace */
99          0xfff,                 /* src_mask */
100          0xfff,                 /* dst_mask */
101          false),                /* pcrel_offset */
102
103   /* A relative 15 bit relocation, right shifted by 3 */
104   HOWTO (R_D30V_15_PCREL,       /* type */
105          3,                     /* rightshift */
106          2,                     /* size (0 = byte, 1 = short, 2 = long) */
107          15,                    /* bitsize */
108          true,                  /* pc_relative */
109          0,                     /* bitpos */
110          complain_overflow_signed, /* complain_on_overflow */
111          bfd_elf_generic_reloc, /* special_function */
112          "R_D30V_15_PCREL",     /* name */
113          false,                 /* partial_inplace */
114          0xfff,                 /* src_mask */
115          0xfff,                 /* dst_mask */
116          true),                 /* pcrel_offset */
117
118   /* An absolute 21 bit relocation, right shifted by 3 */
119   HOWTO (R_D30V_21_PCREL,       /* type */
120          3,                     /* rightshift */
121          2,                     /* size (0 = byte, 1 = short, 2 = long) */
122          21,                    /* bitsize */
123          false,                 /* pc_relative */
124          0,                     /* bitpos */
125          complain_overflow_signed, /* complain_on_overflow */
126          bfd_elf_generic_reloc, /* special_function */
127          "R_D30V_21",           /* name */
128          false,                 /* partial_inplace */
129          0x3ffff,               /* src_mask */
130          0x3ffff,               /* dst_mask */
131          false),                /* pcrel_offset */
132
133   /* A relative 21 bit relocation, right shifted by 3 */
134   HOWTO (R_D30V_21_PCREL,       /* type */
135          3,                     /* rightshift */
136          2,                     /* size (0 = byte, 1 = short, 2 = long) */
137          21,                    /* bitsize */
138          true,                  /* pc_relative */
139          0,                     /* bitpos */
140          complain_overflow_signed, /* complain_on_overflow */
141          bfd_elf_generic_reloc, /* special_function */
142          "R_D30V_21_PCREL",     /* name */
143          false,                 /* partial_inplace */
144          0x3ffff,               /* src_mask */
145          0x3ffff,               /* dst_mask */
146          true),                 /* pcrel_offset */
147
148   /* A D30V 32 bit absolute relocation */
149   HOWTO (R_D30V_32,             /* type */
150          0,                     /* rightshift */
151          4,                     /* size (0 = byte, 1 = short, 2 = long) */
152          32,                    /* bitsize */
153          false,                 /* pc_relative */
154          0,                     /* bitpos */
155          complain_overflow_bitfield, /* complain_on_overflow */
156          bfd_elf_d30v_reloc,    /* special_function */
157          "R_D30V_32",           /* name */
158          false,                 /* partial_inplace */
159          0xffffffff,            /* src_mask */
160          0xffffffff,            /* dst_mask */
161          false),                /* pcrel_offset */
162
163   /* A relative 32 bit relocation */
164   HOWTO (R_D30V_32_PCREL,       /* type */
165          0,                     /* rightshift */
166          4,                     /* size (0 = byte, 1 = short, 2 = long) */
167          32,                    /* bitsize */
168          true,                  /* pc_relative */
169          0,                     /* bitpos */
170          complain_overflow_signed, /* complain_on_overflow */
171          bfd_elf_d30v_reloc,    /* special_function */
172          "R_D30V_32_PCREL",     /* name */
173          false,                 /* partial_inplace */
174          0xffffffff,            /* src_mask */
175          0xffffffff,            /* dst_mask */
176          true),                 /* pcrel_offset */
177
178   /* A regular 32 bit absolute relocation */
179   HOWTO (R_D30V_32_NORMAL,              /* type */
180          0,                     /* rightshift */
181          4,                     /* size (0 = byte, 1 = short, 2 = long) */
182          32,                    /* bitsize */
183          false,                 /* pc_relative */
184          0,                     /* bitpos */
185          complain_overflow_bitfield, /* complain_on_overflow */
186          bfd_elf_generic_reloc, /* special_function */
187          "R_D30V_32_NORMAL",            /* name */
188          false,                 /* partial_inplace */
189          0xffffffff,            /* src_mask */
190          0xffffffff,            /* dst_mask */
191          false),                /* pcrel_offset */
192
193 };
194
195 static bfd_reloc_status_type
196 bfd_elf_d30v_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message)
197      bfd *abfd;
198      arelent *reloc_entry;
199      asymbol *symbol;
200      PTR data;
201      asection *input_section;
202      bfd *output_bfd;
203      char **error_message;
204 {
205   bfd_vma relocation;
206   bfd_vma in1, in2;
207   bfd_reloc_status_type r;
208   asection *reloc_target_output_section;
209   bfd_size_type addr = reloc_entry->address;
210   bfd_reloc_status_type flag = bfd_reloc_ok;
211   bfd_vma output_base = 0;
212   reloc_howto_type *howto = reloc_entry->howto;
213
214   r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
215                              input_section, output_bfd, error_message);
216   if (r != bfd_reloc_continue)
217     return r; 
218
219   /* a hacked-up version of bfd_perform_reloc() follows */
220
221   /* Is the address of the relocation really within the section?  */
222   if (reloc_entry->address > input_section->_cooked_size)
223     return bfd_reloc_outofrange;
224
225   /* Work out which section the relocation is targetted at and the
226      initial relocation command value.  */
227
228   /* Get symbol value.  (Common symbols are special.)  */
229   if (bfd_is_com_section (symbol->section))
230     relocation = 0;
231   else
232     relocation = symbol->value;
233
234
235   reloc_target_output_section = symbol->section->output_section;
236
237   /* Convert input-section-relative symbol value to absolute.  */
238   if (output_bfd)
239     output_base = 0;
240   else
241     output_base = reloc_target_output_section->vma;
242
243   relocation += output_base + symbol->section->output_offset;
244
245   /* Add in supplied addend.  */
246   relocation += reloc_entry->addend;
247
248   /* Here the variable relocation holds the final address of the
249      symbol we are relocating against, plus any addend.  */
250
251   if (howto->pc_relative == true)
252     {
253       relocation -= input_section->output_section->vma + input_section->output_offset;
254
255       if (howto->pcrel_offset == true)
256         relocation -= reloc_entry->address;
257     }
258
259   if (output_bfd != (bfd *) NULL)
260     {
261       /* This is a partial relocation, and we want to apply the relocation
262          to the reloc entry rather than the raw data. Modify the reloc
263          inplace to reflect what we now know.  */
264       reloc_entry->addend = relocation;
265       reloc_entry->address += input_section->output_offset;
266       return flag;
267     }
268   else
269     reloc_entry->addend = 0;
270   
271   in1 = bfd_get_32 (abfd, (bfd_byte *) data + addr);
272   in2 = bfd_get_32 (abfd, (bfd_byte *) data + addr + 4);
273
274   printf("D30V 32-bit reloc at addr 0x%lx  insn=0x%08x%08x\n",(long)relocation, (int)in1, (int)in2);
275   bfd_put_32 (abfd, in1, (bfd_byte *) data + addr);
276   bfd_put_32 (abfd, in2, (bfd_byte *) data + addr + 4);
277   
278   return flag;
279 }   
280
281 /* Map BFD reloc types to D30V ELF reloc types.  */
282
283 struct d30v_reloc_map
284 {
285   unsigned char bfd_reloc_val;
286   unsigned char elf_reloc_val;
287 };
288
289
290 static const struct d30v_reloc_map d30v_reloc_map[] =
291 {
292   { BFD_RELOC_NONE, R_D30V_NONE, },
293   { BFD_RELOC_D30V_6, R_D30V_6 },
294   { BFD_RELOC_D30V_15, R_D30V_15 },
295   { BFD_RELOC_D30V_15_PCREL, R_D30V_15_PCREL },
296   { BFD_RELOC_D30V_21, R_D30V_21 },
297   { BFD_RELOC_D30V_21_PCREL, R_D30V_21_PCREL },
298   { BFD_RELOC_D30V_32, R_D30V_32 },
299   { BFD_RELOC_D30V_32_PCREL, R_D30V_32_PCREL },
300   { BFD_RELOC_32, R_D30V_32_NORMAL },
301 };
302
303 static reloc_howto_type *
304 bfd_elf32_bfd_reloc_type_lookup (abfd, code)
305      bfd *abfd;
306      bfd_reloc_code_real_type code;
307 {
308   unsigned int i;
309
310   for (i = 0;
311        i < sizeof (d30v_reloc_map) / sizeof (struct d30v_reloc_map);
312        i++)
313     {
314       if (d30v_reloc_map[i].bfd_reloc_val == code)
315         return &elf_d30v_howto_table[d30v_reloc_map[i].elf_reloc_val];
316     }
317
318   return NULL;
319 }
320
321 /* Set the howto pointer for an D30V ELF reloc.  */
322
323 static void
324 d30v_info_to_howto_rel (abfd, cache_ptr, dst)
325      bfd *abfd;
326      arelent *cache_ptr;
327      Elf32_Internal_Rel *dst;
328 {
329   unsigned int r_type;
330
331   r_type = ELF32_R_TYPE (dst->r_info);
332   BFD_ASSERT (r_type < (unsigned int) R_D30V_max);
333   cache_ptr->howto = &elf_d30v_howto_table[r_type];
334 }
335
336 #define ELF_ARCH                bfd_arch_d30v
337 #define ELF_MACHINE_CODE        EM_CYGNUS_D30V
338 #define ELF_MAXPAGESIZE         0x1000
339
340 #define TARGET_BIG_SYM          bfd_elf32_d30v_vec
341 #define TARGET_BIG_NAME         "elf32-d30v"
342
343 #define elf_info_to_howto       0
344 #define elf_info_to_howto_rel   d30v_info_to_howto_rel
345 #define elf_backend_object_p    0
346 #define elf_backend_final_write_processing      0
347
348 #include "elf32-target.h"