0a49885a76748e29ea107eca199e10c6b9473324
[external/binutils.git] / bfd / elf32-crx.c
1 /* BFD back-end for National Semiconductor's CRX ELF
2    Copyright 2004 Free Software Foundation, Inc.
3    Written by Tomer Levi, NSC, Israel.
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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
20
21 #include "bfd.h"
22 #include "sysdep.h"
23 #include "bfdlink.h"
24 #include "libbfd.h"
25 #include "elf-bfd.h"
26 #include "elf/crx.h"
27
28 static reloc_howto_type *elf_crx_reloc_type_lookup
29   (bfd *, bfd_reloc_code_real_type);
30 static void elf_crx_info_to_howto
31   (bfd *, arelent *, Elf_Internal_Rela *);
32 static bfd_boolean elf32_crx_relax_delete_bytes
33   (struct bfd_link_info *, bfd *, asection *, bfd_vma, int);
34 static bfd_reloc_status_type crx_elf_final_link_relocate
35   (reloc_howto_type *, bfd *, bfd *, asection *,
36    bfd_byte *, bfd_vma, bfd_vma, bfd_vma,
37    struct bfd_link_info *, asection *, int);
38 static bfd_boolean elf32_crx_relocate_section
39   (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
40    Elf_Internal_Rela *, Elf_Internal_Sym *, asection **);
41 static asection * elf32_crx_gc_mark_hook
42   (asection *, struct bfd_link_info *, Elf_Internal_Rela *,
43    struct elf_link_hash_entry *, Elf_Internal_Sym *);
44 static bfd_boolean elf32_crx_gc_sweep_hook
45   (bfd *, struct bfd_link_info *, asection *,
46    const Elf_Internal_Rela *);
47 static bfd_boolean elf32_crx_relax_section
48   (bfd *, asection *, struct bfd_link_info *, bfd_boolean *);
49 static bfd_byte * elf32_crx_get_relocated_section_contents
50   (bfd *, struct bfd_link_info *, struct bfd_link_order *,
51    bfd_byte *, bfd_boolean, asymbol **);
52
53 /* crx_reloc_map array maps BFD relocation enum into a CRGAS relocation type.  */
54
55 struct crx_reloc_map
56 {
57   bfd_reloc_code_real_type bfd_reloc_enum; /* BFD relocation enum.  */
58   unsigned short crx_reloc_type;           /* CRX relocation type.  */
59 };
60
61 static const struct crx_reloc_map crx_reloc_map[R_CRX_MAX] =
62 {
63   {BFD_RELOC_NONE,          R_CRX_NONE},
64   {BFD_RELOC_CRX_REL4,      R_CRX_REL4},
65   {BFD_RELOC_CRX_REL8,      R_CRX_REL8},
66   {BFD_RELOC_CRX_REL8_CMP,  R_CRX_REL8_CMP},
67   {BFD_RELOC_CRX_REL16,     R_CRX_REL16},
68   {BFD_RELOC_CRX_REL24,     R_CRX_REL24},
69   {BFD_RELOC_CRX_REL32,     R_CRX_REL32},
70   {BFD_RELOC_CRX_REGREL12,  R_CRX_REGREL12},
71   {BFD_RELOC_CRX_REGREL22,  R_CRX_REGREL22},
72   {BFD_RELOC_CRX_REGREL28,  R_CRX_REGREL28},
73   {BFD_RELOC_CRX_REGREL32,  R_CRX_REGREL32},
74   {BFD_RELOC_CRX_ABS16,     R_CRX_ABS16},
75   {BFD_RELOC_CRX_ABS32,     R_CRX_ABS32},
76   {BFD_RELOC_CRX_NUM8,      R_CRX_NUM8},
77   {BFD_RELOC_CRX_NUM16,     R_CRX_NUM16},
78   {BFD_RELOC_CRX_NUM32,     R_CRX_NUM32},
79   {BFD_RELOC_CRX_IMM16,     R_CRX_IMM16},
80   {BFD_RELOC_CRX_IMM32,     R_CRX_IMM32},
81   {BFD_RELOC_CRX_SWITCH8,   R_CRX_SWITCH8},
82   {BFD_RELOC_CRX_SWITCH16,  R_CRX_SWITCH16},
83   {BFD_RELOC_CRX_SWITCH32,  R_CRX_SWITCH32}
84 };
85
86 static reloc_howto_type crx_elf_howto_table[] =
87 {
88   HOWTO (R_CRX_NONE,            /* type */
89          0,                     /* rightshift */
90          2,                     /* size */
91          32,                    /* bitsize */
92          FALSE,                 /* pc_relative */
93          0,                     /* bitpos */
94          complain_overflow_dont,/* complain_on_overflow */
95          bfd_elf_generic_reloc, /* special_function */
96          "R_CRX_NONE",          /* name */
97          FALSE,                 /* partial_inplace */
98          0,                     /* src_mask */
99          0,                     /* dst_mask */
100          FALSE),                /* pcrel_offset */
101
102   HOWTO (R_CRX_REL4,            /* type */
103          1,                     /* rightshift */
104          0,                     /* size */
105          4,                     /* bitsize */
106          TRUE,                  /* pc_relative */
107          0,                     /* bitpos */
108          complain_overflow_bitfield,/* complain_on_overflow */
109          bfd_elf_generic_reloc, /* special_function */
110          "R_CRX_REL4",          /* name */
111          FALSE,                 /* partial_inplace */
112          0xf,                   /* src_mask */
113          0xf,                   /* dst_mask */
114          FALSE),                /* pcrel_offset */
115
116   HOWTO (R_CRX_REL8,            /* type */
117          1,                     /* rightshift */
118          0,                     /* size */
119          8,                     /* bitsize */
120          TRUE,                  /* pc_relative */
121          0,                     /* bitpos */
122          complain_overflow_bitfield,/* complain_on_overflow */
123          bfd_elf_generic_reloc, /* special_function */
124          "R_CRX_REL8",          /* name */
125          FALSE,                 /* partial_inplace */
126          0xff,                  /* src_mask */
127          0xff,                  /* dst_mask */
128          FALSE),                /* pcrel_offset */
129
130   HOWTO (R_CRX_REL8_CMP,        /* type */
131          1,                     /* rightshift */
132          0,                     /* size */
133          8,                     /* bitsize */
134          TRUE,                  /* pc_relative */
135          0,                     /* bitpos */
136          complain_overflow_bitfield,/* complain_on_overflow */
137          bfd_elf_generic_reloc, /* special_function */
138          "R_CRX_REL8_CMP",      /* name */
139          FALSE,                 /* partial_inplace */
140          0xff,                  /* src_mask */
141          0xff,                  /* dst_mask */
142          FALSE),                /* pcrel_offset */
143
144   HOWTO (R_CRX_REL16,           /* type */
145          1,                     /* rightshift */
146          1,                     /* size */
147          16,                    /* bitsize */
148          TRUE,                  /* pc_relative */
149          0,                     /* bitpos */
150          complain_overflow_bitfield,/* complain_on_overflow */
151          bfd_elf_generic_reloc, /* special_function */
152          "R_CRX_REL16",         /* name */
153          FALSE,                 /* partial_inplace */
154          0xffff,                /* src_mask */
155          0xffff,                /* dst_mask */
156          FALSE),                /* pcrel_offset */
157
158   HOWTO (R_CRX_REL24,           /* type */
159          1,                     /* rightshift */
160          2,                     /* size */
161          24,                    /* bitsize */
162          TRUE,                  /* pc_relative */
163          0,                     /* bitpos */
164          complain_overflow_bitfield,/* complain_on_overflow */
165          bfd_elf_generic_reloc, /* special_function */
166          "R_CRX_REL24",         /* name */
167          FALSE,                 /* partial_inplace */
168          0xffffff,              /* src_mask */
169          0xffffff,              /* dst_mask */
170          FALSE),                /* pcrel_offset */
171
172   HOWTO (R_CRX_REL32,           /* type */
173          1,                     /* rightshift */
174          2,                     /* size */
175          32,                    /* bitsize */
176          TRUE,                  /* pc_relative */
177          0,                     /* bitpos */
178          complain_overflow_bitfield,/* complain_on_overflow */
179          bfd_elf_generic_reloc, /* special_function */
180          "R_CRX_REL32",         /* name */
181          FALSE,                 /* partial_inplace */
182          0xffffffff,            /* src_mask */
183          0xffffffff,            /* dst_mask */
184          FALSE),                /* pcrel_offset */
185
186   HOWTO (R_CRX_REGREL12,        /* type */
187          0,                     /* rightshift */
188          1,                     /* size */
189          12,                    /* bitsize */
190          FALSE,                 /* pc_relative */
191          0,                     /* bitpos */
192          complain_overflow_bitfield,/* complain_on_overflow */
193          bfd_elf_generic_reloc, /* special_function */
194          "R_CRX_REGREL12",      /* name */
195          FALSE,                 /* partial_inplace */
196          0xfff,                 /* src_mask */
197          0xfff,                 /* dst_mask */
198          FALSE),                /* pcrel_offset */
199
200   HOWTO (R_CRX_REGREL22,        /* type */
201          0,                     /* rightshift */
202          2,                     /* size */
203          22,                    /* bitsize */
204          FALSE,                 /* pc_relative */
205          0,                     /* bitpos */
206          complain_overflow_bitfield,/* complain_on_overflow */
207          bfd_elf_generic_reloc, /* special_function */
208          "R_CRX_REGREL22",      /* name */
209          FALSE,                 /* partial_inplace */
210          0x3fffff,              /* src_mask */
211          0x3fffff,              /* dst_mask */
212          FALSE),                /* pcrel_offset */
213
214   HOWTO (R_CRX_REGREL28,        /* type */
215          0,                     /* rightshift */
216          2,                     /* size */
217          28,                    /* bitsize */
218          FALSE,                 /* pc_relative */
219          0,                     /* bitpos */
220          complain_overflow_bitfield,/* complain_on_overflow */
221          bfd_elf_generic_reloc, /* special_function */
222          "R_CRX_REGREL28",      /* name */
223          FALSE,                 /* partial_inplace */
224          0xfffffff,             /* src_mask */
225          0xfffffff,             /* dst_mask */
226          FALSE),                /* pcrel_offset */
227
228   HOWTO (R_CRX_REGREL32,        /* type */
229          0,                     /* rightshift */
230          2,                     /* size */
231          32,                    /* bitsize */
232          FALSE,                 /* pc_relative */
233          0,                     /* bitpos */
234          complain_overflow_bitfield,/* complain_on_overflow */
235          bfd_elf_generic_reloc, /* special_function */
236          "R_CRX_REGREL32",      /* name */
237          FALSE,                 /* partial_inplace */
238          0xffffffff,            /* src_mask */
239          0xffffffff,            /* dst_mask */
240          FALSE),                /* pcrel_offset */
241
242   HOWTO (R_CRX_ABS16,           /* type */
243          0,                     /* rightshift */
244          1,                     /* size */
245          16,                    /* bitsize */
246          FALSE,                 /* pc_relative */
247          0,                     /* bitpos */
248          complain_overflow_bitfield,/* complain_on_overflow */
249          bfd_elf_generic_reloc, /* special_function */
250          "R_CRX_ABS16",         /* name */
251          FALSE,                 /* partial_inplace */
252          0xffff,                /* src_mask */
253          0xffff,                /* dst_mask */
254          FALSE),                /* pcrel_offset */
255
256   HOWTO (R_CRX_ABS32,           /* type */
257          0,                     /* rightshift */
258          2,                     /* size */
259          32,                    /* bitsize */
260          FALSE,                 /* pc_relative */
261          0,                     /* bitpos */
262          complain_overflow_bitfield,/* complain_on_overflow */
263          bfd_elf_generic_reloc, /* special_function */
264          "R_CRX_ABS32",         /* name */
265          FALSE,                 /* partial_inplace */
266          0xffffffff,            /* src_mask */
267          0xffffffff,            /* dst_mask */
268          FALSE),                /* pcrel_offset */
269
270   HOWTO (R_CRX_NUM8,            /* type */
271          0,                     /* rightshift */
272          0,                     /* size */
273          8,                     /* bitsize */
274          FALSE,                 /* pc_relative */
275          0,                     /* bitpos */
276          complain_overflow_bitfield,/* complain_on_overflow */
277          bfd_elf_generic_reloc, /* special_function */
278          "R_CRX_NUM8",          /* name */
279          FALSE,                 /* partial_inplace */
280          0xff,                  /* src_mask */
281          0xff,                  /* dst_mask */
282          FALSE),                /* pcrel_offset */
283
284   HOWTO (R_CRX_NUM16,           /* type */
285          0,                     /* rightshift */
286          1,                     /* size */
287          16,                    /* bitsize */
288          FALSE,                 /* pc_relative */
289          0,                     /* bitpos */
290          complain_overflow_bitfield,/* complain_on_overflow */
291          bfd_elf_generic_reloc, /* special_function */
292          "R_CRX_NUM16",         /* name */
293          FALSE,                 /* partial_inplace */
294          0xffff,                /* src_mask */
295          0xffff,                /* dst_mask */
296          FALSE),                /* pcrel_offset */
297
298   HOWTO (R_CRX_NUM32,           /* type */
299          0,                     /* rightshift */
300          2,                     /* size */
301          32,                    /* bitsize */
302          FALSE,                 /* pc_relative */
303          0,                     /* bitpos */
304          complain_overflow_bitfield,/* complain_on_overflow */
305          bfd_elf_generic_reloc, /* special_function */
306          "R_CRX_NUM32",         /* name */
307          FALSE,                 /* partial_inplace */
308          0xffffffff,            /* src_mask */
309          0xffffffff,            /* dst_mask */
310          FALSE),                /* pcrel_offset */
311
312   HOWTO (R_CRX_IMM16,           /* type */
313          0,                     /* rightshift */
314          1,                     /* size */
315          16,                    /* bitsize */
316          FALSE,                 /* pc_relative */
317          0,                     /* bitpos */
318          complain_overflow_bitfield,/* complain_on_overflow */
319          bfd_elf_generic_reloc, /* special_function */
320          "R_CRX_IMM16",         /* name */
321          FALSE,                 /* partial_inplace */
322          0xffff,                /* src_mask */
323          0xffff,                /* dst_mask */
324          FALSE),                /* pcrel_offset */
325
326   HOWTO (R_CRX_IMM32,           /* type */
327          0,                     /* rightshift */
328          2,                     /* size */
329          32,                    /* bitsize */
330          FALSE,                 /* pc_relative */
331          0,                     /* bitpos */
332          complain_overflow_bitfield,/* complain_on_overflow */
333          bfd_elf_generic_reloc, /* special_function */
334          "R_CRX_IMM32",         /* name */
335          FALSE,                 /* partial_inplace */
336          0xffffffff,            /* src_mask */
337          0xffffffff,            /* dst_mask */
338          FALSE),                /* pcrel_offset */
339  
340   /* An 8 bit switch table entry.  This is generated for an expression
341      such as ``.byte L1 - L2''.  The offset holds the difference
342      between the reloc address and L2.  */
343   HOWTO (R_CRX_SWITCH8,         /* type */
344          0,                     /* rightshift */
345          0,                     /* size (0 = byte, 1 = short, 2 = long) */
346          8,                     /* bitsize */
347          FALSE,                 /* pc_relative */
348          0,                     /* bitpos */
349          complain_overflow_unsigned, /* complain_on_overflow */
350          bfd_elf_generic_reloc, /* special_function */
351          "R_CRX_SWITCH8",       /* name */
352          FALSE,                 /* partial_inplace */
353          0xff,                  /* src_mask */
354          0xff,                  /* dst_mask */
355          TRUE),                 /* pcrel_offset */
356
357   /* A 16 bit switch table entry.  This is generated for an expression
358      such as ``.word L1 - L2''.  The offset holds the difference
359      between the reloc address and L2.  */
360   HOWTO (R_CRX_SWITCH16,        /* type */
361          0,                     /* rightshift */
362          1,                     /* size (0 = byte, 1 = short, 2 = long) */
363          16,                    /* bitsize */
364          FALSE,                 /* pc_relative */
365          0,                     /* bitpos */
366          complain_overflow_unsigned, /* complain_on_overflow */
367          bfd_elf_generic_reloc, /* special_function */
368          "R_CRX_SWITCH16",      /* name */
369          FALSE,                 /* partial_inplace */
370          0xffff,                /* src_mask */
371          0xffff,                /* dst_mask */
372          TRUE),                 /* pcrel_offset */
373
374   /* A 32 bit switch table entry.  This is generated for an expression
375      such as ``.long L1 - L2''.  The offset holds the difference
376      between the reloc address and L2.  */
377   HOWTO (R_CRX_SWITCH32,        /* type */
378          0,                     /* rightshift */
379          2,                     /* size (0 = byte, 1 = short, 2 = long) */
380          32,                    /* bitsize */
381          FALSE,                 /* pc_relative */
382          0,                     /* bitpos */
383          complain_overflow_unsigned, /* complain_on_overflow */
384          bfd_elf_generic_reloc, /* special_function */
385          "R_CRX_SWITCH32",      /* name */
386          FALSE,                 /* partial_inplace */
387          0xffffffff,            /* src_mask */
388          0xffffffff,            /* dst_mask */
389          TRUE)                  /* pcrel_offset */
390 };
391
392 /* Retrieve a howto ptr using a BFD reloc_code.  */
393
394 static reloc_howto_type *
395 elf_crx_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
396                            bfd_reloc_code_real_type code)
397 {
398   unsigned int i;
399
400   for (i = 0; i < R_CRX_MAX; i++)
401     if (code == crx_reloc_map[i].bfd_reloc_enum)
402       return &crx_elf_howto_table[crx_reloc_map[i].crx_reloc_type];
403
404   printf ("This relocation Type is not supported -0x%x\n", code);
405   return 0;
406 }
407
408 /* Retrieve a howto ptr using an internal relocation entry.  */
409
410 static void
411 elf_crx_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr,
412                        Elf_Internal_Rela *dst)
413 {
414   unsigned int r_type = ELF32_R_TYPE (dst->r_info);
415   BFD_ASSERT (r_type < (unsigned int) R_CRX_MAX);
416   cache_ptr->howto = &crx_elf_howto_table[r_type];
417 }
418
419 /* Perform a relocation as part of a final link.  */
420
421 static bfd_reloc_status_type
422 crx_elf_final_link_relocate (reloc_howto_type *howto, bfd *input_bfd,
423                              bfd *output_bfd ATTRIBUTE_UNUSED,
424                              asection *input_section, bfd_byte *contents,
425                              bfd_vma offset, bfd_vma Rvalue, bfd_vma addend,
426                              struct bfd_link_info *info ATTRIBUTE_UNUSED,
427                              asection *sec ATTRIBUTE_UNUSED,
428                              int is_local ATTRIBUTE_UNUSED)
429 {
430   unsigned short r_type = howto->type;
431   bfd_byte *hit_data = contents + offset;
432   bfd_vma reloc_bits, check;
433
434   switch (r_type)
435     {
436      case R_CRX_IMM16:
437      case R_CRX_IMM32:
438      case R_CRX_ABS16:
439      case R_CRX_ABS32:
440      case R_CRX_REL8_CMP:
441      case R_CRX_REL16:
442      case R_CRX_REL24:
443      case R_CRX_REL32:
444      case R_CRX_REGREL12:
445      case R_CRX_REGREL22:
446      case R_CRX_REGREL28:
447      case R_CRX_REGREL32:
448        /* 'hit_data' is relative to the start of the instruction, not the
449           relocation offset. Advance it to account for the exact offset.  */
450        hit_data += 2;
451        break;
452
453      case R_CRX_REL4:
454        /* This relocation type is used only in 'Branch if Equal to 0'
455           instructions and requires special handling.  */
456        Rvalue -= 1;
457        break;
458
459      case R_CRX_NONE:
460        return bfd_reloc_ok;
461        break;
462
463      case R_CRX_SWITCH8:
464      case R_CRX_SWITCH16:
465      case R_CRX_SWITCH32:
466        /* We only care about the addend, where the difference between 
467           expressions is kept.  */
468        Rvalue = 0;
469        
470      default:
471        break;
472     }
473
474   if (howto->pc_relative)
475     {
476       /* Subtract the address of the section containing the location.  */
477       Rvalue -= (input_section->output_section->vma
478                  + input_section->output_offset);
479       /* Subtract the position of the location within the section.  */
480       Rvalue -= offset;
481     }
482
483   /* Add in supplied addend.  */
484   Rvalue += addend;
485
486   /* Complain if the bitfield overflows, whether it is considered
487      as signed or unsigned.  */
488   check = Rvalue >> howto->rightshift;
489
490   /* Assumes two's complement.  This expression avoids
491      overflow if howto->bitsize is the number of bits in
492      bfd_vma.  */
493   reloc_bits = (((1 << (howto->bitsize - 1)) - 1) << 1) | 1;
494
495   if (((bfd_vma) check & ~reloc_bits) != 0
496       && (((bfd_vma) check & ~reloc_bits)
497           != (-(bfd_vma) 1 & ~reloc_bits)))
498     {
499       /* The above right shift is incorrect for a signed
500          value.  See if turning on the upper bits fixes the
501          overflow.  */
502       if (howto->rightshift && (bfd_signed_vma) Rvalue < 0)
503         {
504           check |= ((bfd_vma) - 1
505                     & ~((bfd_vma) - 1
506                         >> howto->rightshift));
507           if (((bfd_vma) check & ~reloc_bits)
508               != (-(bfd_vma) 1 & ~reloc_bits))
509             return bfd_reloc_overflow;
510         }
511       else
512         return bfd_reloc_overflow;
513     }
514
515   /* Drop unwanted bits from the value we are relocating to.  */
516   Rvalue >>= (bfd_vma) howto->rightshift;
517
518   /* Apply dst_mask to select only relocatable part of the insn.  */
519   Rvalue &= howto->dst_mask;
520
521   switch (howto->size)
522     {
523      case 0:
524        if (r_type == R_CRX_REL4)
525          {
526            Rvalue <<= 4;
527            Rvalue |= (bfd_get_8 (input_bfd, hit_data) & 0x0f);
528          }
529
530        bfd_put_8 (input_bfd, (unsigned char) Rvalue, hit_data);
531        break;
532
533      case 1:
534        if (r_type == R_CRX_REGREL12)
535          Rvalue |= (bfd_get_16 (input_bfd, hit_data) & 0xf000);
536
537        bfd_put_16 (input_bfd, Rvalue, hit_data);
538        break;
539
540      case 2:
541        if (r_type == R_CRX_REL24
542            || r_type == R_CRX_REGREL22
543            || r_type == R_CRX_REGREL28)
544          Rvalue |= (((bfd_get_16 (input_bfd, hit_data) << 16) |
545                       bfd_get_16 (input_bfd, hit_data + 2)) & ~howto->dst_mask);
546
547        if (r_type == R_CRX_NUM32 || r_type == R_CRX_SWITCH32)
548          /* Relocation on DATA is purely little-endian, that is, for a
549             multi-byte datum, the lowest address in memory contains the
550             little end of the datum, that is, the least significant byte.
551             Therefore we use BFD's byte Putting functions.  */
552          bfd_put_32 (input_bfd, Rvalue, hit_data);
553        else
554          /* Relocation on INSTRUCTIONS is different : Instructions are
555             word-addressable, that is, each word itself is arranged according
556             to little-endian convention, whereas the words are arranged with
557             respect to one another in BIG ENDIAN fashion.
558             When there is an immediate value that spans a word boundary, it is
559             split in a big-endian way with respect to the words.  */
560          {
561            bfd_put_16 (input_bfd, (Rvalue >> 16) & 0xffff, hit_data);
562            bfd_put_16 (input_bfd, Rvalue & 0xffff, hit_data + 2);
563          }
564      break;
565
566      default:
567        return bfd_reloc_notsupported;
568     }
569
570   return bfd_reloc_ok;
571 }
572
573 /* Delete some bytes from a section while relaxing.  */
574
575 static bfd_boolean
576 elf32_crx_relax_delete_bytes (struct bfd_link_info *link_info, bfd *abfd, 
577                               asection *sec, bfd_vma addr, int count)
578 {
579   Elf_Internal_Shdr *symtab_hdr;
580   unsigned int sec_shndx;
581   bfd_byte *contents;
582   Elf_Internal_Rela *irel, *irelend;
583   Elf_Internal_Rela *irelalign;
584   bfd_vma toaddr;
585   Elf_Internal_Sym *isym;
586   Elf_Internal_Sym *isymend;
587   struct elf_link_hash_entry **sym_hashes;
588   struct elf_link_hash_entry **end_hashes;
589   struct elf_link_hash_entry **start_hashes;
590   unsigned int symcount;
591
592   sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
593
594   contents = elf_section_data (sec)->this_hdr.contents;
595
596   /* The deletion must stop at the next ALIGN reloc for an aligment
597      power larger than the number of bytes we are deleting.  */
598
599   irelalign = NULL;
600   toaddr = sec->size;
601
602   irel = elf_section_data (sec)->relocs;
603   irelend = irel + sec->reloc_count;
604
605   /* Actually delete the bytes.  */
606   memmove (contents + addr, contents + addr + count,
607            (size_t) (toaddr - addr - count));
608   sec->size -= count;
609
610   /* Adjust all the relocs.  */
611   for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
612     {
613       /* Get the new reloc address.  */
614       if ((irel->r_offset > addr
615            && irel->r_offset < toaddr))
616         irel->r_offset -= count;
617     }
618
619   /* Adjust the local symbols defined in this section.  */
620   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
621   isym = (Elf_Internal_Sym *) symtab_hdr->contents;
622   for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
623     {
624       if (isym->st_shndx == sec_shndx
625           && isym->st_value > addr
626           && isym->st_value < toaddr)
627         {
628           /* Adjust the addend of SWITCH relocations in this section, 
629              which reference this local symbol.  */
630           for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
631             {
632               unsigned long r_symndx;
633               Elf_Internal_Sym *rsym;
634               bfd_vma addsym, subsym;
635
636               /* Skip if not a SWITCH relocation.  */
637               if (ELF32_R_TYPE (irel->r_info) != (int) R_CRX_SWITCH8
638                   && ELF32_R_TYPE (irel->r_info) != (int) R_CRX_SWITCH16
639                   && ELF32_R_TYPE (irel->r_info) != (int) R_CRX_SWITCH32)
640                   continue;
641
642               r_symndx = ELF32_R_SYM (irel->r_info);
643               rsym = (Elf_Internal_Sym *) symtab_hdr->contents + r_symndx;
644
645               /* Skip if not the local adjusted symbol.  */
646               if (rsym != isym)
647                 continue;
648
649               addsym = isym->st_value;
650               subsym = addsym - irel->r_addend;
651
652               /* Fix the addend only when -->> (addsym > addr >= subsym).  */
653               if (subsym <= addr)
654                 irel->r_addend -= count;
655               else
656                 continue;
657             }
658
659           isym->st_value -= count;
660         }
661     }
662
663   /* Now adjust the global symbols defined in this section.  */
664   symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
665               - symtab_hdr->sh_info);
666   sym_hashes = start_hashes = elf_sym_hashes (abfd);
667   end_hashes = sym_hashes + symcount;
668
669   for (; sym_hashes < end_hashes; sym_hashes++)
670     {
671       struct elf_link_hash_entry *sym_hash = *sym_hashes;
672
673       /* The '--wrap SYMBOL' option is causing a pain when the object file, 
674          containing the definition of __wrap_SYMBOL, includes a direct 
675          call to SYMBOL as well. Since both __wrap_SYMBOL and SYMBOL reference 
676          the same symbol (which is __wrap_SYMBOL), but still exist as two 
677          different symbols in 'sym_hashes', we don't want to adjust 
678          the global symbol __wrap_SYMBOL twice.  
679          This check is only relevant when symbols are being wrapped.  */
680       if (link_info->wrap_hash != NULL)
681         {
682           struct elf_link_hash_entry **cur_sym_hashes;
683           
684           /* Loop only over the symbols whom been already checked.  */
685           for (cur_sym_hashes = start_hashes; cur_sym_hashes < sym_hashes; 
686                cur_sym_hashes++)
687             {
688               /* If the current symbol is identical to 'sym_hash', that means 
689                  the symbol was already adjusted (or at least checked).  */
690               if (*cur_sym_hashes == sym_hash)
691                 break;
692             }
693           /* Don't adjust the symbol again.  */
694           if (cur_sym_hashes < sym_hashes)
695             continue;
696         }
697
698       if ((sym_hash->root.type == bfd_link_hash_defined
699            || sym_hash->root.type == bfd_link_hash_defweak)
700           && sym_hash->root.u.def.section == sec
701           && sym_hash->root.u.def.value > addr
702           && sym_hash->root.u.def.value < toaddr)
703         sym_hash->root.u.def.value -= count;
704     }
705
706   return TRUE;
707 }
708
709 /* This is a version of bfd_generic_get_relocated_section_contents
710    which uses elf32_crx_relocate_section.  */
711
712 static bfd_byte *
713 elf32_crx_get_relocated_section_contents (bfd *output_bfd,
714                                           struct bfd_link_info *link_info,
715                                           struct bfd_link_order *link_order,
716                                           bfd_byte *data,
717                                           bfd_boolean relocatable,
718                                           asymbol **symbols)
719 {
720   Elf_Internal_Shdr *symtab_hdr;
721   asection *input_section = link_order->u.indirect.section;
722   bfd *input_bfd = input_section->owner;
723   asection **sections = NULL;
724   Elf_Internal_Rela *internal_relocs = NULL;
725   Elf_Internal_Sym *isymbuf = NULL;
726
727   /* We only need to handle the case of relaxing, or of having a
728      particular set of section contents, specially.  */
729   if (relocatable
730       || elf_section_data (input_section)->this_hdr.contents == NULL)
731     return bfd_generic_get_relocated_section_contents (output_bfd, link_info,
732                                                        link_order, data,
733                                                        relocatable,
734                                                        symbols);
735
736   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
737
738   memcpy (data, elf_section_data (input_section)->this_hdr.contents,
739           (size_t) input_section->size);
740
741   if ((input_section->flags & SEC_RELOC) != 0
742       && input_section->reloc_count > 0)
743     {
744       Elf_Internal_Sym *isym;
745       Elf_Internal_Sym *isymend;
746       asection **secpp;
747       bfd_size_type amt;
748
749       internal_relocs = (_bfd_elf_link_read_relocs
750                          (input_bfd, input_section, (PTR) NULL,
751                           (Elf_Internal_Rela *) NULL, FALSE));
752       if (internal_relocs == NULL)
753         goto error_return;
754
755       if (symtab_hdr->sh_info != 0)
756         {
757           isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
758           if (isymbuf == NULL)
759             isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
760                                             symtab_hdr->sh_info, 0,
761                                             NULL, NULL, NULL);
762           if (isymbuf == NULL)
763             goto error_return;
764         }
765
766       amt = symtab_hdr->sh_info;
767       amt *= sizeof (asection *);
768       sections = bfd_malloc (amt);
769       if (sections == NULL && amt != 0)
770         goto error_return;
771
772       isymend = isymbuf + symtab_hdr->sh_info;
773       for (isym = isymbuf, secpp = sections; isym < isymend; ++isym, ++secpp)
774         {
775           asection *isec;
776
777           if (isym->st_shndx == SHN_UNDEF)
778             isec = bfd_und_section_ptr;
779           else if (isym->st_shndx == SHN_ABS)
780             isec = bfd_abs_section_ptr;
781           else if (isym->st_shndx == SHN_COMMON)
782             isec = bfd_com_section_ptr;
783           else
784             isec = bfd_section_from_elf_index (input_bfd, isym->st_shndx);
785
786           *secpp = isec;
787         }
788
789       if (! elf32_crx_relocate_section (output_bfd, link_info, input_bfd,
790                                      input_section, data, internal_relocs,
791                                      isymbuf, sections))
792         goto error_return;
793
794       if (sections != NULL)
795         free (sections);
796       if (isymbuf != NULL
797           && symtab_hdr->contents != (unsigned char *) isymbuf)
798         free (isymbuf);
799       if (elf_section_data (input_section)->relocs != internal_relocs)
800         free (internal_relocs);
801     }
802
803   return data;
804
805  error_return:
806   if (sections != NULL)
807     free (sections);
808   if (isymbuf != NULL
809       && symtab_hdr->contents != (unsigned char *) isymbuf)
810     free (isymbuf);
811   if (internal_relocs != NULL
812       && elf_section_data (input_section)->relocs != internal_relocs)
813     free (internal_relocs);
814   return NULL;
815 }
816
817 /* Relocate a CRX ELF section.  */
818
819 static bfd_boolean
820 elf32_crx_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
821                             bfd *input_bfd, asection *input_section,
822                             bfd_byte *contents, Elf_Internal_Rela *relocs,
823                             Elf_Internal_Sym *local_syms,
824                             asection **local_sections)
825 {
826   Elf_Internal_Shdr *symtab_hdr;
827   struct elf_link_hash_entry **sym_hashes;
828   Elf_Internal_Rela *rel, *relend;
829
830   if (info->relocatable)
831     return TRUE;
832
833   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
834   sym_hashes = elf_sym_hashes (input_bfd);
835
836   rel = relocs;
837   relend = relocs + input_section->reloc_count;
838   for (; rel < relend; rel++)
839     {
840       int r_type;
841       reloc_howto_type *howto;
842       unsigned long r_symndx;
843       Elf_Internal_Sym *sym;
844       asection *sec;
845       struct elf_link_hash_entry *h;
846       bfd_vma relocation;
847       bfd_reloc_status_type r;
848
849       r_symndx = ELF32_R_SYM (rel->r_info);
850       r_type = ELF32_R_TYPE (rel->r_info);
851       howto = crx_elf_howto_table + (r_type);
852
853       h = NULL;
854       sym = NULL;
855       sec = NULL;
856       if (r_symndx < symtab_hdr->sh_info)
857         {
858           sym = local_syms + r_symndx;
859           sec = local_sections[r_symndx];
860           relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
861         }
862       else
863         {
864           bfd_boolean unresolved_reloc, warned;
865
866           RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
867                                    r_symndx, symtab_hdr, sym_hashes,
868                                    h, sec, relocation,
869                                    unresolved_reloc, warned);
870         }
871
872       r = crx_elf_final_link_relocate (howto, input_bfd, output_bfd,
873                                         input_section,
874                                         contents, rel->r_offset,
875                                         relocation, rel->r_addend,
876                                         info, sec, h == NULL);
877
878       if (r != bfd_reloc_ok)
879         {
880           const char *name;
881           const char *msg = (const char *) 0;
882
883           if (h != NULL)
884             name = h->root.root.string;
885           else
886             {
887               name = (bfd_elf_string_from_elf_section
888                       (input_bfd, symtab_hdr->sh_link, sym->st_name));
889               if (name == NULL || *name == '\0')
890                 name = bfd_section_name (input_bfd, sec);
891             }
892
893           switch (r)
894             {
895              case bfd_reloc_overflow:
896                if (!((*info->callbacks->reloc_overflow)
897                      (info, (h ? &h->root : NULL), name, howto->name,
898                       (bfd_vma) 0, input_bfd, input_section,
899                       rel->r_offset)))
900                  return FALSE;
901                break;
902
903              case bfd_reloc_undefined:
904                if (!((*info->callbacks->undefined_symbol)
905                      (info, name, input_bfd, input_section,
906                       rel->r_offset, TRUE)))
907                  return FALSE;
908                break;
909
910              case bfd_reloc_outofrange:
911                msg = _("internal error: out of range error");
912                goto common_error;
913
914              case bfd_reloc_notsupported:
915                msg = _("internal error: unsupported relocation error");
916                goto common_error;
917
918              case bfd_reloc_dangerous:
919                msg = _("internal error: dangerous error");
920                goto common_error;
921
922              default:
923                msg = _("internal error: unknown error");
924                /* Fall through.  */
925
926              common_error:
927                if (!((*info->callbacks->warning)
928                      (info, msg, name, input_bfd, input_section,
929                       rel->r_offset)))
930                  return FALSE;
931                break;
932             }
933         }
934     }
935
936   return TRUE;
937 }
938
939 /* This function handles relaxing for the CRX.
940
941    There's quite a few relaxing opportunites available on the CRX:
942
943         * bal/bcond:32 -> bal/bcond:16                             2 bytes
944         * bcond:16 -> bcond:8                                      2 bytes
945         * cmpbcond:24 -> cmpbcond:8                                2 bytes
946         * arithmetic imm32 -> arithmetic imm16                     2 bytes
947
948    Symbol- and reloc-reading infrastructure copied from elf-m10200.c.  */
949
950 static bfd_boolean
951 elf32_crx_relax_section (bfd *abfd, asection *sec,
952                          struct bfd_link_info *link_info, bfd_boolean *again)
953 {
954   Elf_Internal_Shdr *symtab_hdr;
955   Elf_Internal_Rela *internal_relocs;
956   Elf_Internal_Rela *irel, *irelend;
957   bfd_byte *contents = NULL;
958   Elf_Internal_Sym *isymbuf = NULL;
959
960   /* Assume nothing changes.  */
961   *again = FALSE;
962
963   /* We don't have to do anything for a relocatable link, if
964      this section does not have relocs, or if this is not a
965      code section.  */
966   if (link_info->relocatable
967       || (sec->flags & SEC_RELOC) == 0
968       || sec->reloc_count == 0
969       || (sec->flags & SEC_CODE) == 0)
970     return TRUE;
971
972   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
973
974   /* Get a copy of the native relocations.  */
975   internal_relocs = (_bfd_elf_link_read_relocs
976                      (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
977                       link_info->keep_memory));
978   if (internal_relocs == NULL)
979     goto error_return;
980
981   /* Walk through them looking for relaxing opportunities.  */
982   irelend = internal_relocs + sec->reloc_count;
983   for (irel = internal_relocs; irel < irelend; irel++)
984     {
985       bfd_vma symval;
986
987       /* If this isn't something that can be relaxed, then ignore
988          this reloc.  */
989       if (ELF32_R_TYPE (irel->r_info) != (int) R_CRX_REL32
990           && ELF32_R_TYPE (irel->r_info) != (int) R_CRX_REL16
991           && ELF32_R_TYPE (irel->r_info) != (int) R_CRX_REL24
992           && ELF32_R_TYPE (irel->r_info) != (int) R_CRX_IMM32)
993         continue;
994
995       /* Get the section contents if we haven't done so already.  */
996       if (contents == NULL)
997         {
998           /* Get cached copy if it exists.  */
999           if (elf_section_data (sec)->this_hdr.contents != NULL)
1000             contents = elf_section_data (sec)->this_hdr.contents;
1001           /* Go get them off disk.  */
1002           else if (!bfd_malloc_and_get_section (abfd, sec, &contents))
1003             goto error_return;
1004         }
1005
1006       /* Read this BFD's local symbols if we haven't done so already.  */
1007       if (isymbuf == NULL && symtab_hdr->sh_info != 0)
1008         {
1009           isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
1010           if (isymbuf == NULL)
1011             isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
1012                                             symtab_hdr->sh_info, 0,
1013                                             NULL, NULL, NULL);
1014           if (isymbuf == NULL)
1015             goto error_return;
1016         }
1017
1018       /* Get the value of the symbol referred to by the reloc.  */
1019       if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
1020         {
1021           /* A local symbol.  */
1022           Elf_Internal_Sym *isym;
1023           asection *sym_sec;
1024
1025           isym = isymbuf + ELF32_R_SYM (irel->r_info);
1026           if (isym->st_shndx == SHN_UNDEF)
1027             sym_sec = bfd_und_section_ptr;
1028           else if (isym->st_shndx == SHN_ABS)
1029             sym_sec = bfd_abs_section_ptr;
1030           else if (isym->st_shndx == SHN_COMMON)
1031             sym_sec = bfd_com_section_ptr;
1032           else
1033             sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
1034           symval = (isym->st_value
1035                     + sym_sec->output_section->vma
1036                     + sym_sec->output_offset);
1037         }
1038       else
1039         {
1040           unsigned long indx;
1041           struct elf_link_hash_entry *h;
1042
1043           /* An external symbol.  */
1044           indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
1045           h = elf_sym_hashes (abfd)[indx];
1046           BFD_ASSERT (h != NULL);
1047
1048           if (h->root.type != bfd_link_hash_defined
1049               && h->root.type != bfd_link_hash_defweak)
1050             /* This appears to be a reference to an undefined
1051                symbol.  Just ignore it--it will be caught by the
1052                regular reloc processing.  */
1053             continue;
1054
1055           symval = (h->root.u.def.value
1056                     + h->root.u.def.section->output_section->vma
1057                     + h->root.u.def.section->output_offset);
1058         }
1059
1060       /* For simplicity of coding, we are going to modify the section
1061          contents, the section relocs, and the BFD symbol table.  We
1062          must tell the rest of the code not to free up this
1063          information.  It would be possible to instead create a table
1064          of changes which have to be made, as is done in coff-mips.c;
1065          that would be more work, but would require less memory when
1066          the linker is run.  */
1067
1068       /* Try to turn a 32bit pc-relative branch/call into
1069          a 16bit pc-relative branch/call.  */
1070       if (ELF32_R_TYPE (irel->r_info) == (int) R_CRX_REL32)
1071         {
1072           bfd_vma value = symval;
1073
1074           /* Deal with pc-relative gunk.  */
1075           value -= (sec->output_section->vma + sec->output_offset);
1076           value -= irel->r_offset;
1077           value += irel->r_addend;
1078
1079           /* See if the value will fit in 16 bits, note the high value is
1080              0xfffe + 2 as the target will be two bytes closer if we are
1081              able to relax.  */
1082           if ((long) value < 0x10000 && (long) value > -0x10002)
1083             {
1084               unsigned short code;
1085
1086               /* Get the opcode.  */
1087               code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset);
1088
1089               /* Verify it's a 'bal'/'bcond' and fix the opcode.  */
1090               if ((code & 0xfff0) == 0x3170)
1091                 bfd_put_8 (abfd, 0x30, contents + irel->r_offset + 1);
1092               else if ((code & 0xf0ff) == 0x707f)
1093                 bfd_put_8 (abfd, 0x7e, contents + irel->r_offset);
1094               else
1095                 continue;
1096
1097               /* Note that we've changed the relocs, section contents, etc.  */
1098               elf_section_data (sec)->relocs = internal_relocs;
1099               elf_section_data (sec)->this_hdr.contents = contents;
1100               symtab_hdr->contents = (unsigned char *) isymbuf;
1101
1102               /* Fix the relocation's type.  */
1103               irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
1104                                            R_CRX_REL16);
1105
1106               /* Delete two bytes of data.  */
1107               if (!elf32_crx_relax_delete_bytes (link_info, abfd, sec,
1108                                                    irel->r_offset + 2, 2))
1109                 goto error_return;
1110
1111               /* That will change things, so, we should relax again.
1112                  Note that this is not required, and it may be slow.  */
1113               *again = TRUE;
1114             }
1115         }
1116
1117       /* Try to turn a 16bit pc-relative branch into an
1118          8bit pc-relative branch.  */
1119       if (ELF32_R_TYPE (irel->r_info) == (int) R_CRX_REL16)
1120         {
1121           bfd_vma value = symval;
1122
1123           /* Deal with pc-relative gunk.  */
1124           value -= (sec->output_section->vma + sec->output_offset);
1125           value -= irel->r_offset;
1126           value += irel->r_addend;
1127
1128           /* See if the value will fit in 8 bits, note the high value is
1129              0xfc + 2 as the target will be two bytes closer if we are
1130              able to relax.  */
1131           if ((long) value < 0xfe && (long) value > -0x100)
1132             {
1133               unsigned short code;
1134
1135               /* Get the opcode.  */
1136               code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset);
1137
1138               /* Verify it's a 'bcond' opcode.  */
1139               if ((code & 0xf0ff) != 0x707e)
1140                 continue;
1141
1142               /* Note that we've changed the relocs, section contents, etc.  */
1143               elf_section_data (sec)->relocs = internal_relocs;
1144               elf_section_data (sec)->this_hdr.contents = contents;
1145               symtab_hdr->contents = (unsigned char *) isymbuf;
1146
1147               /* Fix the relocation's type.  */
1148               irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
1149                                            R_CRX_REL8);
1150
1151               /* Delete two bytes of data.  */
1152               if (!elf32_crx_relax_delete_bytes (link_info, abfd, sec,
1153                                                    irel->r_offset + 2, 2))
1154                 goto error_return;
1155
1156               /* That will change things, so, we should relax again.
1157                  Note that this is not required, and it may be slow.  */
1158               *again = TRUE;
1159             }
1160         }
1161
1162       /* Try to turn a 24bit pc-relative cmp&branch into
1163          an 8bit pc-relative cmp&branch.  */
1164       if (ELF32_R_TYPE (irel->r_info) == (int) R_CRX_REL24)
1165         {
1166           bfd_vma value = symval;
1167
1168           /* Deal with pc-relative gunk.  */
1169           value -= (sec->output_section->vma + sec->output_offset);
1170           value -= irel->r_offset;
1171           value += irel->r_addend;
1172
1173           /* See if the value will fit in 8 bits, note the high value is
1174              0x7e + 2 as the target will be two bytes closer if we are
1175              able to relax.  */
1176           if ((long) value < 0x100 && (long) value > -0x100)
1177             {
1178               unsigned short code;
1179
1180               /* Get the opcode.  */
1181               code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset);
1182
1183               /* Verify it's a 'cmp&branch' opcode.  */
1184               if ((code & 0xfff0) != 0x3180 && (code & 0xfff0) != 0x3190
1185                && (code & 0xfff0) != 0x31a0 && (code & 0xfff0) != 0x31c0
1186                && (code & 0xfff0) != 0x31d0 && (code & 0xfff0) != 0x31e0
1187                /* Or a Co-processor branch ('bcop').  */
1188                && (code & 0xfff0) != 0x3010 && (code & 0xfff0) != 0x3110)
1189                 continue;
1190
1191               /* Note that we've changed the relocs, section contents, etc.  */
1192               elf_section_data (sec)->relocs = internal_relocs;
1193               elf_section_data (sec)->this_hdr.contents = contents;
1194               symtab_hdr->contents = (unsigned char *) isymbuf;
1195
1196               /* Fix the opcode.  */
1197               bfd_put_8 (abfd, 0x30, contents + irel->r_offset + 1);
1198
1199               /* Fix the relocation's type.  */
1200               irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
1201                                            R_CRX_REL8_CMP);
1202
1203               /* Delete two bytes of data.  */
1204               if (!elf32_crx_relax_delete_bytes (link_info, abfd, sec,
1205                                                    irel->r_offset + 4, 2))
1206                 goto error_return;
1207
1208               /* That will change things, so, we should relax again.
1209                  Note that this is not required, and it may be slow.  */
1210               *again = TRUE;
1211             }
1212         }
1213
1214       /* Try to turn a 32bit immediate address into
1215          a 16bit immediate address.  */
1216       if (ELF32_R_TYPE (irel->r_info) == (int) R_CRX_IMM32)
1217         {
1218           bfd_vma value = symval;
1219
1220           /* See if the value will fit in 16 bits.  */
1221           if ((long) value < 0x7fff && (long) value > -0x8000)
1222             {
1223               unsigned short code;
1224
1225               /* Get the opcode.  */
1226               code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset);
1227
1228               /* Verify it's a 'arithmetic double'.  */
1229               if ((code & 0xf0f0) != 0x20f0)
1230                 continue;
1231
1232               /* Note that we've changed the relocs, section contents, etc.  */
1233               elf_section_data (sec)->relocs = internal_relocs;
1234               elf_section_data (sec)->this_hdr.contents = contents;
1235               symtab_hdr->contents = (unsigned char *) isymbuf;
1236
1237               /* Fix the opcode.  */
1238               bfd_put_8 (abfd, (code & 0xff) - 0x10, contents + irel->r_offset);
1239
1240               /* Fix the relocation's type.  */
1241               irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
1242                                            R_CRX_IMM16);
1243
1244               /* Delete two bytes of data.  */
1245               if (!elf32_crx_relax_delete_bytes (link_info, abfd, sec,
1246                                                    irel->r_offset + 2, 2))
1247                 goto error_return;
1248
1249               /* That will change things, so, we should relax again.
1250                  Note that this is not required, and it may be slow.  */
1251               *again = TRUE;
1252             }
1253         }
1254     }
1255
1256   if (isymbuf != NULL
1257       && symtab_hdr->contents != (unsigned char *) isymbuf)
1258     {
1259       if (! link_info->keep_memory)
1260         free (isymbuf);
1261       else
1262         {
1263           /* Cache the symbols for elf_link_input_bfd.  */
1264           symtab_hdr->contents = (unsigned char *) isymbuf;
1265         }
1266     }
1267
1268   if (contents != NULL
1269       && elf_section_data (sec)->this_hdr.contents != contents)
1270     {
1271       if (! link_info->keep_memory)
1272         free (contents);
1273       else
1274         {
1275           /* Cache the section contents for elf_link_input_bfd.  */
1276           elf_section_data (sec)->this_hdr.contents = contents;
1277         }
1278     }
1279
1280   if (internal_relocs != NULL
1281       && elf_section_data (sec)->relocs != internal_relocs)
1282     free (internal_relocs);
1283
1284   return TRUE;
1285
1286  error_return:
1287   if (isymbuf != NULL
1288       && symtab_hdr->contents != (unsigned char *) isymbuf)
1289     free (isymbuf);
1290   if (contents != NULL
1291       && elf_section_data (sec)->this_hdr.contents != contents)
1292     free (contents);
1293   if (internal_relocs != NULL
1294       && elf_section_data (sec)->relocs != internal_relocs)
1295     free (internal_relocs);
1296
1297   return FALSE;
1298 }
1299
1300 static asection *
1301 elf32_crx_gc_mark_hook (asection *sec,
1302                         struct bfd_link_info *info ATTRIBUTE_UNUSED,
1303                         Elf_Internal_Rela *rel ATTRIBUTE_UNUSED,
1304                         struct elf_link_hash_entry *h,
1305                         Elf_Internal_Sym *sym)
1306 {
1307   if (h == NULL)
1308     return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
1309
1310   switch (h->root.type)
1311     {
1312     case bfd_link_hash_defined:
1313     case bfd_link_hash_defweak:
1314       return h->root.u.def.section;
1315
1316     case bfd_link_hash_common:
1317       return h->root.u.c.p->section;
1318
1319     default:
1320       return NULL;
1321     }
1322 }
1323
1324 /* Update the got entry reference counts for the section being removed.  */
1325
1326 static bfd_boolean
1327 elf32_crx_gc_sweep_hook (bfd *abfd ATTRIBUTE_UNUSED,
1328                          struct bfd_link_info *info ATTRIBUTE_UNUSED,
1329                          asection *sec ATTRIBUTE_UNUSED,
1330                          const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED)
1331 {
1332   /* We don't support garbage collection of GOT and PLT relocs yet.  */
1333   return TRUE;
1334 }
1335
1336 /* Definitions for setting CRX target vector.  */
1337 #define TARGET_LITTLE_SYM               bfd_elf32_crx_vec
1338 #define TARGET_LITTLE_NAME              "elf32-crx"
1339 #define ELF_ARCH                        bfd_arch_crx
1340 #define ELF_MACHINE_CODE                EM_CRX
1341 #define ELF_MAXPAGESIZE                 0x1
1342 #define elf_symbol_leading_char         '_'
1343
1344 #define bfd_elf32_bfd_reloc_type_lookup elf_crx_reloc_type_lookup
1345 #define elf_info_to_howto               elf_crx_info_to_howto
1346 #define elf_info_to_howto_rel           0
1347 #define elf_backend_relocate_section    elf32_crx_relocate_section
1348 #define bfd_elf32_bfd_relax_section     elf32_crx_relax_section
1349 #define bfd_elf32_bfd_get_relocated_section_contents \
1350                                 elf32_crx_get_relocated_section_contents
1351 #define elf_backend_gc_mark_hook        elf32_crx_gc_mark_hook
1352 #define elf_backend_gc_sweep_hook       elf32_crx_gc_sweep_hook
1353 #define elf_backend_can_gc_sections     1
1354 #define elf_backend_rela_normal         1
1355
1356 #include "elf32-target.h"