* elf32-d30v.c (bfd_elf_d30v_reloc): Don't modify section
[external/binutils.git] / bfd / elf32-d30v.c
1 /* D30V-specific support for 32-bit ELF
2    Copyright (C) 1997, 98, 99, 2000 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 void d30v_info_to_howto_rela
31   PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
32 static bfd_reloc_status_type bfd_elf_d30v_reloc PARAMS ((
33      bfd *abfd,
34      arelent *reloc_entry,
35      asymbol *symbol,
36      PTR data,
37      asection *input_section,
38      bfd *output_bfd,
39      char **error_message));
40 static bfd_reloc_status_type bfd_elf_d30v_reloc_21 PARAMS ((
41      bfd *abfd,
42      arelent *reloc_entry,
43      asymbol *symbol,
44      PTR data,
45      asection *input_section,
46      bfd *output_bfd,
47      char **error_message));
48
49 enum reloc_type
50 {
51   R_D30V_NONE = 0,
52   R_D30V_6,
53   R_D30V_9_PCREL,
54   R_D30V_9_PCREL_R,
55   R_D30V_15,
56   R_D30V_15_PCREL,
57   R_D30V_15_PCREL_R,
58   R_D30V_21,
59   R_D30V_21_PCREL,
60   R_D30V_21_PCREL_R,
61   R_D30V_32,
62   R_D30V_32_PCREL,
63   R_D30V_32_NORMAL,
64   R_D30V_max
65 };
66
67 static reloc_howto_type elf_d30v_howto_table[] =
68 {
69   /* This reloc does nothing.  */
70   HOWTO (R_D30V_NONE,           /* type */
71          0,                     /* rightshift */
72          2,                     /* size (0 = byte, 1 = short, 2 = long) */
73          32,                    /* bitsize */
74          false,                 /* pc_relative */
75          0,                     /* bitpos */
76          complain_overflow_bitfield, /* complain_on_overflow */
77          bfd_elf_generic_reloc, /* special_function */
78          "R_D30V_NONE",         /* name */
79          false,                 /* partial_inplace */
80          0,                     /* src_mask */
81          0,                     /* dst_mask */
82          false),                /* pcrel_offset */
83
84   /* A 6 bit absolute relocation */
85   HOWTO (R_D30V_6,              /* type */
86          0,                     /* rightshift */
87          2,                     /* size (0 = byte, 1 = short, 2 = long) */
88          6,                     /* bitsize */
89          false,                 /* pc_relative */
90          0,                     /* bitpos */
91          complain_overflow_bitfield, /* complain_on_overflow */
92          bfd_elf_generic_reloc, /* special_function */
93          "R_D30V_6",            /* name */
94          false,                 /* partial_inplace */
95          0x3f,                  /* src_mask */
96          0x3f,                  /* dst_mask */
97          false),                /* pcrel_offset */
98
99   /* A relative 9 bit relocation, right shifted by 3 */
100   HOWTO (R_D30V_9_PCREL,        /* type */
101          3,                     /* rightshift */
102          2,                     /* size (0 = byte, 1 = short, 2 = long) */
103          6,                     /* bitsize */
104          true,                  /* pc_relative */
105          0,                     /* bitpos */
106          complain_overflow_signed, /* complain_on_overflow */
107          bfd_elf_d30v_reloc_21, /* special_function */
108          "R_D30V_9_PCREL",      /* name */
109          false,                 /* partial_inplace */
110          0x3f,                  /* src_mask */
111          0x3f,                  /* dst_mask */
112          true),                 /* pcrel_offset */
113
114   /* A relative 9 bit relocation, right shifted by 3 */
115   HOWTO (R_D30V_9_PCREL_R,      /* type */
116          3,                     /* rightshift */
117          2,                     /* size (0 = byte, 1 = short, 2 = long) */
118          6,                     /* bitsize */
119          true,                  /* pc_relative */
120          0,                     /* bitpos */
121          complain_overflow_signed, /* complain_on_overflow */
122          bfd_elf_d30v_reloc_21, /* special_function */
123          "R_D30V_9_PCREL_R",    /* name */
124          false,                 /* partial_inplace */
125          0x3f,                  /* src_mask */
126          0x3f,                  /* dst_mask */
127          true),                 /* pcrel_offset */
128
129   /* An absolute 15 bit relocation, right shifted by 3 */
130   HOWTO (R_D30V_15,             /* type */
131          3,                     /* rightshift */
132          2,                     /* size (0 = byte, 1 = short, 2 = long) */
133          12,                    /* bitsize */
134          false,                 /* pc_relative */
135          0,                     /* bitpos */
136          complain_overflow_signed, /* complain_on_overflow */
137          bfd_elf_generic_reloc, /* special_function */
138          "R_D30V_15",           /* name */
139          false,                 /* partial_inplace */
140          0xfff,                 /* src_mask */
141          0xfff,                 /* dst_mask */
142          false),                /* pcrel_offset */
143
144   /* A relative 15 bit relocation, right shifted by 3 */
145   HOWTO (R_D30V_15_PCREL,       /* type */
146          3,                     /* rightshift */
147          2,                     /* size (0 = byte, 1 = short, 2 = long) */
148          12,                    /* bitsize */
149          true,                  /* pc_relative */
150          0,                     /* bitpos */
151          complain_overflow_signed, /* complain_on_overflow */
152          bfd_elf_d30v_reloc_21, /* special_function */
153          "R_D30V_15_PCREL",     /* name */
154          false,                 /* partial_inplace */
155          0xfff,                 /* src_mask */
156          0xfff,                 /* dst_mask */
157          true),                 /* pcrel_offset */
158
159   /* A relative 15 bit relocation, right shifted by 3 */
160   HOWTO (R_D30V_15_PCREL_R,     /* type */
161          3,                     /* rightshift */
162          2,                     /* size (0 = byte, 1 = short, 2 = long) */
163          12,                    /* bitsize */
164          true,                  /* pc_relative */
165          0,                     /* bitpos */
166          complain_overflow_signed, /* complain_on_overflow */
167          bfd_elf_d30v_reloc_21, /* special_function */
168          "R_D30V_15_PCREL_R",   /* name */
169          false,                 /* partial_inplace */
170          0xfff,                 /* src_mask */
171          0xfff,                 /* dst_mask */
172          true),                 /* pcrel_offset */
173
174   /* An absolute 21 bit relocation, right shifted by 3 */
175   HOWTO (R_D30V_21,             /* type */
176          3,                     /* rightshift */
177          2,                     /* size (0 = byte, 1 = short, 2 = long) */
178          18,                    /* bitsize */
179          false,                 /* pc_relative */
180          0,                     /* bitpos */
181          complain_overflow_signed, /* complain_on_overflow */
182          bfd_elf_generic_reloc, /* special_function */
183          "R_D30V_21",           /* name */
184          false,                 /* partial_inplace */
185          0x3ffff,               /* src_mask */
186          0x3ffff,               /* dst_mask */
187          false),                /* pcrel_offset */
188
189   /* A relative 21 bit relocation, right shifted by 3 */
190   HOWTO (R_D30V_21_PCREL,       /* type */
191          3,                     /* rightshift */
192          2,                     /* size (0 = byte, 1 = short, 2 = long) */
193          18,                    /* bitsize */
194          true,                  /* pc_relative */
195          0,                     /* bitpos */
196          complain_overflow_signed, /* complain_on_overflow */
197          bfd_elf_d30v_reloc_21, /* special_function */
198          "R_D30V_21_PCREL",     /* name */
199          false,                 /* partial_inplace */
200          0x3ffff,               /* src_mask */
201          0x3ffff,               /* dst_mask */
202          true),                 /* pcrel_offset */
203
204   /* A relative 21 bit relocation, right shifted by 3, in the Right container */
205   HOWTO (R_D30V_21_PCREL_R,     /* type */
206          3,                     /* rightshift */
207          2,                     /* size (0 = byte, 1 = short, 2 = long) */
208          18,                    /* bitsize */
209          true,                  /* pc_relative */
210          0,                     /* bitpos */
211          complain_overflow_signed, /* complain_on_overflow */
212          bfd_elf_d30v_reloc_21, /* special_function */
213          "R_D30V_21_PCREL_R",   /* name */
214          false,                 /* partial_inplace */
215          0x3ffff,               /* src_mask */
216          0x3ffff,               /* dst_mask */
217          true),                 /* pcrel_offset */
218
219   /* A D30V 32 bit absolute relocation */
220   HOWTO (R_D30V_32,             /* type */
221          0,                     /* rightshift */
222          4,                     /* size (0 = byte, 1 = short, 2 = long) */
223          32,                    /* bitsize */
224          false,                 /* pc_relative */
225          0,                     /* bitpos */
226          complain_overflow_bitfield, /* complain_on_overflow */
227          bfd_elf_d30v_reloc,    /* special_function */
228          "R_D30V_32",           /* name */
229          false,                 /* partial_inplace */
230          0xffffffff,            /* src_mask */
231          0xffffffff,            /* dst_mask */
232          false),                /* pcrel_offset */
233
234   /* A relative 32 bit relocation */
235   HOWTO (R_D30V_32_PCREL,       /* type */
236          0,                     /* rightshift */
237          4,                     /* size (0 = byte, 1 = short, 2 = long) */
238          32,                    /* bitsize */
239          true,                  /* pc_relative */
240          0,                     /* bitpos */
241          complain_overflow_signed, /* complain_on_overflow */
242          bfd_elf_d30v_reloc,    /* special_function */
243          "R_D30V_32_PCREL",     /* name */
244          false,                 /* partial_inplace */
245          0xffffffff,            /* src_mask */
246          0xffffffff,            /* dst_mask */
247          true),                 /* pcrel_offset */
248
249   /* A regular 32 bit absolute relocation */
250   HOWTO (R_D30V_32_NORMAL,              /* type */
251          0,                     /* rightshift */
252          2,                     /* size (0 = byte, 1 = short, 2 = long) */
253          32,                    /* bitsize */
254          false,                 /* pc_relative */
255          0,                     /* bitpos */
256          complain_overflow_bitfield, /* complain_on_overflow */
257          bfd_elf_generic_reloc, /* special_function */
258          "R_D30V_32_NORMAL",            /* name */
259          false,                 /* partial_inplace */
260          0xffffffff,            /* src_mask */
261          0xffffffff,            /* dst_mask */
262          false),                /* pcrel_offset */
263
264 };
265
266 #define MAX32 ((bfd_signed_vma) 0x7fffffff)
267 #define MIN32 (- MAX32 - 1)
268
269 static bfd_reloc_status_type
270 bfd_elf_d30v_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message)
271      bfd *abfd;
272      arelent *reloc_entry;
273      asymbol *symbol;
274      PTR data;
275      asection *input_section;
276      bfd *output_bfd;
277      char **error_message;
278 {
279   bfd_signed_vma relocation;
280   bfd_vma in1, in2, num;
281   bfd_vma tmp_addr = 0;
282   bfd_reloc_status_type r;
283   asection *reloc_target_output_section;
284   bfd_size_type addr = reloc_entry->address;
285   bfd_reloc_status_type flag = bfd_reloc_ok;
286   bfd_vma output_base = 0;
287   reloc_howto_type *howto = reloc_entry->howto;
288   int make_absolute = 0;
289
290   if (output_bfd != (bfd *) NULL)
291     {
292       /* Partial linking -- do nothing.  */
293       reloc_entry->address += input_section->output_offset;
294       return bfd_reloc_ok;
295     }
296
297   r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
298                              input_section, output_bfd, error_message);
299   if (r != bfd_reloc_continue)
300     return r; 
301
302   /* a hacked-up version of bfd_perform_reloc() follows */
303  if (bfd_is_und_section (symbol->section)
304       && (symbol->flags & BSF_WEAK) == 0
305       && output_bfd == (bfd *) NULL)
306     flag = bfd_reloc_undefined;
307
308   /* Is the address of the relocation really within the section?  */
309   if (reloc_entry->address > input_section->_cooked_size)
310     return bfd_reloc_outofrange;
311
312   /* Work out which section the relocation is targetted at and the
313      initial relocation command value.  */
314
315   /* Get symbol value.  (Common symbols are special.)  */
316   if (bfd_is_com_section (symbol->section))
317     relocation = 0;
318   else
319     relocation = symbol->value;
320
321   reloc_target_output_section = symbol->section->output_section;
322
323   /* Convert input-section-relative symbol value to absolute.  */
324   output_base = reloc_target_output_section->vma;
325   relocation += output_base + symbol->section->output_offset;
326
327   /* Add in supplied addend.  */
328   relocation += reloc_entry->addend;
329
330   /* Here the variable relocation holds the final address of the
331      symbol we are relocating against, plus any addend.  */
332
333   if (howto->pc_relative == true)
334     {
335       tmp_addr = input_section->output_section->vma + input_section->output_offset 
336         + reloc_entry->address;
337       relocation -= tmp_addr;
338     }
339   
340   in1 = bfd_get_32 (abfd, (bfd_byte *) data + addr);
341   in2 = bfd_get_32 (abfd, (bfd_byte *) data + addr + 4);
342
343   /* extract the addend */
344   num = ((in2 & 0x3FFFF)
345          | ((in2 & 0xFF00000) >> 2)
346          | ((in1 & 0x3F) << 26));
347   in1 &= 0xFFFFFFC0;
348   in2 = 0x80000000;
349   
350   relocation += num;
351
352   if (howto->pc_relative == true && howto->bitsize == 32)
353     {
354       /* The D30V has a PC that doesn't wrap and PC-relative jumps are
355          signed, so a PC-relative jump can't be more than +/- 2^31 bytes.
356          If one exceeds this, change it to an absolute jump.  */
357       if (relocation > MAX32 || relocation < MIN32)
358         {
359           relocation = (relocation + tmp_addr) & 0xffffffff;
360           make_absolute = 1;
361         }
362     }
363   
364   in1 |= (relocation >> 26) & 0x3F;     /* top 6 bits */
365   in2 |= ((relocation & 0x03FC0000) << 2);  /* next 8 bits */ 
366   in2 |= relocation & 0x0003FFFF;               /* bottom 18 bits */
367   
368   /* change a PC-relative instruction to its absolute equivalent */
369   /* with this simple hack */
370   if (make_absolute)
371     in1 |= 0x00100000;
372
373   bfd_put_32 (abfd, in1, (bfd_byte *) data + addr);
374   bfd_put_32 (abfd, in2, (bfd_byte *) data + addr + 4);
375   
376   return flag;
377 }   
378
379
380 static bfd_reloc_status_type
381 bfd_elf_d30v_reloc_21 (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message)
382      bfd *abfd;
383      arelent *reloc_entry;
384      asymbol *symbol;
385      PTR data;
386      asection *input_section;
387      bfd *output_bfd;
388      char **error_message;
389 {
390   bfd_vma relocation;
391   bfd_vma in1, num;
392   bfd_reloc_status_type r;
393   asection *reloc_target_output_section;
394   bfd_size_type addr = reloc_entry->address;
395   bfd_reloc_status_type flag = bfd_reloc_ok;
396   bfd_vma output_base = 0;
397   reloc_howto_type *howto = reloc_entry->howto;
398   int mask, max;
399
400   if (output_bfd != (bfd *) NULL)
401     {
402       /* Partial linking -- do nothing.  */
403       reloc_entry->address += input_section->output_offset;
404       return bfd_reloc_ok;
405     }
406   
407   r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
408                              input_section, output_bfd, error_message);
409   if (r != bfd_reloc_continue)
410     return r; 
411
412   /* a hacked-up version of bfd_perform_reloc() follows */
413  if (bfd_is_und_section (symbol->section)
414       && (symbol->flags & BSF_WEAK) == 0
415       && output_bfd == (bfd *) NULL)
416     flag = bfd_reloc_undefined;
417
418   /* Is the address of the relocation really within the section?  */
419   if (reloc_entry->address > input_section->_cooked_size)
420     return bfd_reloc_outofrange;
421
422   /* Work out which section the relocation is targetted at and the
423      initial relocation command value.  */
424
425   /* Get symbol value.  (Common symbols are special.)  */
426   if (bfd_is_com_section (symbol->section))
427     relocation = 0;
428   else
429     relocation = symbol->value;
430
431   reloc_target_output_section = symbol->section->output_section;
432
433   /* Convert input-section-relative symbol value to absolute.  */
434   output_base = reloc_target_output_section->vma;
435   relocation += output_base + symbol->section->output_offset;
436
437   /* Add in supplied addend.  */
438   relocation += reloc_entry->addend;
439
440   /* Here the variable relocation holds the final address of the
441      symbol we are relocating against, plus any addend.  */
442
443   if (howto->pc_relative == true)
444     {
445       relocation -= (input_section->output_section->vma
446                      + input_section->output_offset);
447       if (howto->pcrel_offset == true)
448         relocation -= reloc_entry->address;
449     }
450
451   in1 = bfd_get_32 (abfd, (bfd_byte *) data + addr);
452
453   mask =  (1 << howto->bitsize) - 1;
454   if (howto->bitsize == 6)
455     mask <<= 12;
456   max = (1 << (howto->bitsize + 2)) - 1;
457
458   /* extract the addend */
459   num = in1 & mask;  /* 18 bits */
460   if (howto->bitsize == 6)
461     num >>= 12;
462   num <<= 3; /* shift left 3 */
463   in1 &= ~mask;  /* mask out addend */
464
465   relocation += num;
466   if (howto->type == R_D30V_21_PCREL_R || howto->type == R_D30V_15_PCREL_R ||
467       howto->type == R_D30V_9_PCREL_R )
468     {
469       relocation += 4;
470     }
471
472   if ((int)relocation < 0 )
473     {
474       if (~(int)relocation > max)
475         flag = bfd_reloc_overflow;
476     }
477   else
478     {
479       if ((int)relocation > max)
480         flag = bfd_reloc_overflow;
481     }
482   relocation >>= 3; 
483   if (howto->bitsize == 6)
484     in1 |= ((relocation & (mask >> 12)) << 12);
485   else
486     in1 |= relocation & mask;
487
488   bfd_put_32 (abfd, in1, (bfd_byte *) data + addr);
489   
490   return flag;
491 }   
492
493 /* Map BFD reloc types to D30V ELF reloc types.  */
494
495 struct d30v_reloc_map
496 {
497   bfd_reloc_code_real_type bfd_reloc_val;
498   unsigned char elf_reloc_val;
499 };
500
501
502 static const struct d30v_reloc_map d30v_reloc_map[] =
503 {
504   { BFD_RELOC_NONE, R_D30V_NONE, },
505   { BFD_RELOC_D30V_6, R_D30V_6 },
506   { BFD_RELOC_D30V_9_PCREL, R_D30V_9_PCREL },
507   { BFD_RELOC_D30V_9_PCREL_R, R_D30V_9_PCREL_R },
508   { BFD_RELOC_D30V_15, R_D30V_15 },
509   { BFD_RELOC_D30V_15_PCREL, R_D30V_15_PCREL },
510   { BFD_RELOC_D30V_15_PCREL_R, R_D30V_15_PCREL_R },
511   { BFD_RELOC_D30V_21, R_D30V_21 },
512   { BFD_RELOC_D30V_21_PCREL, R_D30V_21_PCREL },
513   { BFD_RELOC_D30V_21_PCREL_R, R_D30V_21_PCREL_R },
514   { BFD_RELOC_D30V_32, R_D30V_32 },
515   { BFD_RELOC_D30V_32_PCREL, R_D30V_32_PCREL },
516   { BFD_RELOC_32, R_D30V_32_NORMAL },
517 };
518
519 static reloc_howto_type *
520 bfd_elf32_bfd_reloc_type_lookup (abfd, code)
521      bfd *abfd ATTRIBUTE_UNUSED;
522      bfd_reloc_code_real_type code;
523 {
524   unsigned int i;
525
526   for (i = 0;
527        i < sizeof (d30v_reloc_map) / sizeof (struct d30v_reloc_map);
528        i++)
529     {
530       if (d30v_reloc_map[i].bfd_reloc_val == code)
531         return &elf_d30v_howto_table[d30v_reloc_map[i].elf_reloc_val];
532     }
533
534   return NULL;
535 }
536
537 /* Set the howto pointer for an D30V ELF reloc (type REL).  */
538
539 static void
540 d30v_info_to_howto_rel (abfd, cache_ptr, dst)
541      bfd *abfd ATTRIBUTE_UNUSED;
542      arelent *cache_ptr;
543      Elf32_Internal_Rel *dst;
544 {
545   unsigned int r_type;
546
547   r_type = ELF32_R_TYPE (dst->r_info);
548   BFD_ASSERT (r_type < (unsigned int) R_D30V_max);
549   cache_ptr->howto = &elf_d30v_howto_table[r_type];
550 }
551
552 /* Set the howto pointer for an D30V ELF reloc (type RELA).  */
553
554 static void
555 d30v_info_to_howto_rela (abfd, cache_ptr, dst)
556      bfd *abfd ATTRIBUTE_UNUSED;
557      arelent *cache_ptr;
558      Elf32_Internal_Rela *dst;
559 {
560   unsigned int r_type;
561
562   r_type = ELF32_R_TYPE (dst->r_info);
563   BFD_ASSERT (r_type < (unsigned int) R_D30V_max);
564   cache_ptr->howto = &elf_d30v_howto_table[r_type];
565 }
566
567 #define ELF_ARCH                bfd_arch_d30v
568 #define ELF_MACHINE_CODE        EM_CYGNUS_D30V
569 #define ELF_MAXPAGESIZE         0x1000
570
571 #define TARGET_BIG_SYM          bfd_elf32_d30v_vec
572 #define TARGET_BIG_NAME         "elf32-d30v"
573
574 #define elf_info_to_howto       d30v_info_to_howto_rela
575 #define elf_info_to_howto_rel   d30v_info_to_howto_rel
576 #define elf_backend_object_p    0
577 #define elf_backend_final_write_processing      0
578
579 #include "elf32-target.h"