* aout-arm.c, aout-target.h, aoutx.h, archive.c, armnetbsd.c,
[external/binutils.git] / bfd / elf32-dlx.c
1 /* DLX specific support for 32-bit ELF
2    Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
3
4    This file is part of BFD, the Binary File Descriptor library.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20 #include "bfd.h"
21 #include "sysdep.h"
22 #include "libbfd.h"
23 #include "elf-bfd.h"
24 #include "elf/dlx.h"
25
26 int    set_dlx_skip_hi16_flag PARAMS ((int));
27
28 static bfd_boolean elf32_dlx_check_relocs
29   PARAMS ((bfd *, struct bfd_link_info *, asection *,
30            const Elf_Internal_Rela *));
31 static void elf32_dlx_info_to_howto
32   PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
33 static void elf32_dlx_info_to_howto_rel
34   PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
35 static bfd_reloc_status_type elf32_dlx_relocate16
36   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
37 static bfd_reloc_status_type elf32_dlx_relocate26
38   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
39 static reloc_howto_type *elf32_dlx_reloc_type_lookup
40   PARAMS ((bfd *, bfd_reloc_code_real_type));
41 static bfd_reloc_status_type _bfd_dlx_elf_hi16_reloc
42   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
43 static reloc_howto_type * dlx_rtype_to_howto
44   PARAMS ((unsigned int));
45
46
47 #define USE_REL 1
48
49 #define bfd_elf32_bfd_reloc_type_lookup elf32_dlx_reloc_type_lookup
50 #define elf_info_to_howto               elf32_dlx_info_to_howto
51 #define elf_info_to_howto_rel           elf32_dlx_info_to_howto_rel
52 #define elf_backend_check_relocs        elf32_dlx_check_relocs
53
54 static reloc_howto_type dlx_elf_howto_table[]=
55   {
56     /* No relocation.  */
57     HOWTO (R_DLX_NONE,            /* type */
58            0,                     /* rightshift */
59            0,                     /* size (0 = byte, 1 = short, 2 = long) */
60            0,                     /* bitsize */
61            FALSE,                 /* pc_relative */
62            0,                     /* bitpos */
63            complain_overflow_dont,/* complain_on_overflow */
64            bfd_elf_generic_reloc, /* special_function */
65            "R_DLX_NONE",          /* name */
66            FALSE,                 /* partial_inplace */
67            0,                     /* src_mask */
68            0,                     /* dst_mask */
69            FALSE),                /* pcrel_offset */
70
71     /* 8 bit relocation.  */
72     HOWTO (R_DLX_RELOC_8,         /* type */
73            0,                     /* rightshift */
74            0,                     /* size (0 = byte, 1 = short, 2 = long) */
75            8,                     /* bitsize */
76            FALSE,                 /* pc_relative */
77            0,                     /* bitpos */
78            complain_overflow_dont,/* complain_on_overflow */
79            bfd_elf_generic_reloc, /* special_function */
80            "R_DLX_RELOC_8",       /* name */
81            TRUE,                  /* partial_inplace */
82            0xff,                  /* src_mask */
83            0xff,                  /* dst_mask */
84            FALSE),                /* pcrel_offset */
85
86     /* 16 bit relocation.  */
87     HOWTO (R_DLX_RELOC_16,        /* type */
88            0,                     /* rightshift */
89            1,                     /* size (0 = byte, 1 = short, 2 = long) */
90            16,                    /* bitsize */
91            FALSE,                 /* pc_relative */
92            0,                     /* bitpos */
93            complain_overflow_dont,/* complain_on_overflow */
94            bfd_elf_generic_reloc, /* special_function */
95            "R_DLX_RELOC_16",      /* name */
96            TRUE,                  /* partial_inplace */
97            0xffff,                /* src_mask */
98            0xffff,                /* dst_mask */
99            FALSE),                /* pcrel_offset */
100
101     /* 32 bit relocation.  */
102     HOWTO (R_DLX_RELOC_32,        /* type */
103            0,                     /* rightshift */
104            2,                     /* size (0 = byte, 1 = short, 2 = long) */
105            32,                    /* bitsize */
106            FALSE,                 /* pc_relative */
107            0,                     /* bitpos */
108            complain_overflow_dont,/* complain_on_overflow */
109            bfd_elf_generic_reloc, /* special_function */
110            "R_DLX_RELOC_32",      /* name */
111            TRUE,                  /* partial_inplace */
112            0xffffffff,            /* src_mask */
113            0xffffffff,            /* dst_mask */
114            FALSE),                /* pcrel_offset */
115
116     /* GNU extension to record C++ vtable hierarchy */
117     HOWTO (R_DLX_GNU_VTINHERIT,   /* type */
118            0,                     /* rightshift */
119            2,                     /* size (0 = byte, 1 = short, 2 = long) */
120            0,                     /* bitsize */
121            FALSE,                 /* pc_relative */
122            0,                     /* bitpos */
123            complain_overflow_dont,/* complain_on_overflow */
124            NULL,                  /* special_function */
125            "R_DLX_GNU_VTINHERIT", /* name */
126            FALSE,                 /* partial_inplace */
127            0,                     /* src_mask */
128            0,                     /* dst_mask */
129            FALSE),                /* pcrel_offset */
130
131     /* GNU extension to record C++ vtable member usage */
132     HOWTO (R_DLX_GNU_VTENTRY,     /* type */
133            0,                     /* rightshift */
134            2,                     /* size (0 = byte, 1 = short, 2 = long) */
135            0,                     /* bitsize */
136            FALSE,                 /* pc_relative */
137            0,                     /* bitpos */
138            complain_overflow_dont,/* complain_on_overflow */
139            _bfd_elf_rel_vtable_reloc_fn,/* special_function */
140            "R_DLX_GNU_VTENTRY",   /* name */
141            FALSE,                 /* partial_inplace */
142            0,                     /* src_mask */
143            0,                     /* dst_mask */
144            FALSE)                 /* pcrel_offset */
145   };
146
147 /* 16 bit offset for pc-relative branches.  */
148 static reloc_howto_type elf_dlx_gnu_rel16_s2 =
149 HOWTO (R_DLX_RELOC_16_PCREL,  /* type */
150        0,                     /* rightshift */
151        1,                     /* size (0 = byte, 1 = short, 2 = long) */
152        16,                    /* bitsize */
153        TRUE,                  /* pc_relative */
154        0,                     /* bitpos */
155        complain_overflow_signed, /* complain_on_overflow */
156        elf32_dlx_relocate16,  /* special_function */
157        "R_DLX_RELOC_16_PCREL",/* name */
158        TRUE,                  /* partial_inplace */
159        0xffff,                /* src_mask */
160        0xffff,                /* dst_mask */
161        TRUE);                 /* pcrel_offset */
162
163 /* 26 bit offset for pc-relative branches.  */
164 static reloc_howto_type elf_dlx_gnu_rel26_s2 =
165 HOWTO (R_DLX_RELOC_26_PCREL,  /* type */
166        0,                     /* rightshift */
167        2,                     /* size (0 = byte, 1 = short, 2 = long) */
168        26,                    /* bitsize */
169        TRUE,                  /* pc_relative */
170        0,                     /* bitpos */
171        complain_overflow_dont,/* complain_on_overflow */
172        elf32_dlx_relocate26,  /* special_function */
173        "R_DLX_RELOC_26_PCREL",/* name */
174        TRUE,                  /* partial_inplace */
175        0xffff,                /* src_mask */
176        0xffff,                /* dst_mask */
177        TRUE);                 /* pcrel_offset */
178
179 /* High 16 bits of symbol value.  */
180 static reloc_howto_type elf_dlx_reloc_16_hi =
181 HOWTO (R_DLX_RELOC_16_HI,     /* type */
182        16,                    /* rightshift */
183        2,                     /* size (0 = byte, 1 = short, 2 = long) */
184        32,                    /* bitsize */
185        FALSE,                 /* pc_relative */
186        0,                     /* bitpos */
187        complain_overflow_dont, /* complain_on_overflow */
188        _bfd_dlx_elf_hi16_reloc,/* special_function */
189        "R_DLX_RELOC_16_HI",   /* name */
190        TRUE,                  /* partial_inplace */
191        0xFFFF,                /* src_mask */
192        0xffff,                /* dst_mask */
193        FALSE);                /* pcrel_offset */
194
195   /* Low 16 bits of symbol value.  */
196 static reloc_howto_type elf_dlx_reloc_16_lo =
197 HOWTO (R_DLX_RELOC_16_LO,     /* type */
198        0,                     /* rightshift */
199        1,                     /* size (0 = byte, 1 = short, 2 = long) */
200        16,                    /* bitsize */
201        FALSE,                 /* pc_relative */
202        0,                     /* bitpos */
203        complain_overflow_dont,/* complain_on_overflow */
204        bfd_elf_generic_reloc, /* special_function */
205        "R_DLX_RELOC_16_LO",   /* name */
206        TRUE,                  /* partial_inplace */
207        0xffff,                /* src_mask */
208        0xffff,                /* dst_mask */
209        FALSE);                /* pcrel_offset */
210
211
212 /* The gas default behavior is not to preform the %hi modifier so that the
213    GNU assembler can have the lower 16 bits offset placed in the insn, BUT
214    we do like the gas to indicate it is %hi reloc type so when we in the link
215    loader phase we can have the corrected hi16 vale replace the buggous lo16
216    value that was placed there by gas.  */
217
218 static int skip_dlx_elf_hi16_reloc = 0;
219
220 int
221 set_dlx_skip_hi16_flag (flag)
222      int flag;
223 {
224   skip_dlx_elf_hi16_reloc = flag;
225   return flag;
226 }
227
228 static bfd_reloc_status_type
229 _bfd_dlx_elf_hi16_reloc (abfd, reloc_entry, symbol, data,
230                          input_section, output_bfd, error_message)
231      bfd *abfd;
232      arelent *reloc_entry;
233      asymbol *symbol;
234      PTR data;
235      asection *input_section;
236      bfd *output_bfd;
237      char **error_message;
238 {
239   bfd_reloc_status_type ret;
240   bfd_vma relocation;
241
242   /* If the skip flag is set then we simply do the generic relocating, this
243      is more of a hack for dlx gas/gld, so we do not need to do the %hi/%lo
244      fixup like mips gld did.   */
245   if (skip_dlx_elf_hi16_reloc)
246     return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
247                           input_section, output_bfd, error_message);
248
249   /* If we're relocating, and this an external symbol, we don't want
250      to change anything.  */
251   if (output_bfd != (bfd *) NULL
252       && (symbol->flags & BSF_SECTION_SYM) == 0
253       && reloc_entry->addend == 0)
254     {
255       reloc_entry->address += input_section->output_offset;
256       return bfd_reloc_ok;
257     }
258
259   ret = bfd_reloc_ok;
260
261   if (bfd_is_und_section (symbol->section)
262       && output_bfd == (bfd *) NULL)
263     ret = bfd_reloc_undefined;
264
265   relocation = (bfd_is_com_section (symbol->section)) ? 0 : symbol->value;
266   relocation += symbol->section->output_section->vma;
267   relocation += symbol->section->output_offset;
268   relocation += reloc_entry->addend;
269   relocation += bfd_get_16 (abfd, (bfd_byte *)data + reloc_entry->address);
270
271   if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
272     return bfd_reloc_outofrange;
273
274   bfd_put_16 (abfd, (short)((relocation >> 16) & 0xFFFF),
275               (bfd_byte *)data + reloc_entry->address);
276
277   return ret;
278 }
279
280 /* ELF relocs are against symbols.  If we are producing relocatable
281    output, and the reloc is against an external symbol, and nothing
282    has given us any additional addend, the resulting reloc will also
283    be against the same symbol.  In such a case, we don't want to
284    change anything about the way the reloc is handled, since it will
285    all be done at final link time.  Rather than put special case code
286    into bfd_perform_relocation, all the reloc types use this howto
287    function.  It just short circuits the reloc if producing
288    relocatable output against an external symbol.  */
289
290 static bfd_reloc_status_type
291 elf32_dlx_relocate16  (abfd, reloc_entry, symbol, data,
292                        input_section, output_bfd, error_message)
293      bfd *abfd;
294      arelent *reloc_entry;
295      asymbol *symbol;
296      PTR data;
297      asection *input_section;
298      bfd *output_bfd;
299      char **error_message ATTRIBUTE_UNUSED;
300 {
301   unsigned long insn, vallo, allignment;
302   int           val;
303
304   /* HACK: I think this first condition is necessary when producing
305      relocatable output.  After the end of HACK, the code is identical
306      to bfd_elf_generic_reloc().  I would _guess_ the first change
307      belongs there rather than here.  martindo 1998-10-23.  */
308
309   if (skip_dlx_elf_hi16_reloc)
310     return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
311                                  input_section, output_bfd, error_message);
312
313   /* Check undefined section and undefined symbols  */
314   if (bfd_is_und_section (symbol->section)
315       && output_bfd == (bfd *) NULL)
316     return bfd_reloc_undefined;
317
318   /* Can not support a long jump to sections other then .text   */
319   if (strcmp (input_section->name, symbol->section->output_section->name) != 0)
320     {
321       fprintf (stderr,
322                "BFD Link Error: branch (PC rel16) to section (%s) not supported\n",
323                symbol->section->output_section->name);
324       return bfd_reloc_undefined;
325     }
326
327   insn  = bfd_get_32 (abfd, (bfd_byte *)data + reloc_entry->address);
328   allignment = 1 << (input_section->output_section->alignment_power - 1);
329   vallo = insn & 0x0000FFFF;
330
331   if (vallo & 0x8000)
332     vallo = ~(vallo | 0xFFFF0000) + 1;
333
334   /* vallo points to the vma of next instruction.  */
335   vallo += (((unsigned long)(input_section->output_section->vma +
336                            input_section->output_offset) +
337             allignment) & ~allignment);
338
339   /* val is the displacement (PC relative to next instruction).  */
340   val =  (symbol->section->output_offset +
341           symbol->section->output_section->vma +
342           symbol->value) - vallo;
343
344   if (abs ((int) val) > 0x00007FFF)
345     return bfd_reloc_outofrange;
346
347   insn  = (insn & 0xFFFF0000) | (val & 0x0000FFFF);
348
349   bfd_put_32 (abfd, insn,
350               (bfd_byte *) data + reloc_entry->address);
351
352   return bfd_reloc_ok;
353 }
354
355 static bfd_reloc_status_type
356 elf32_dlx_relocate26  (abfd, reloc_entry, symbol, data,
357                        input_section, output_bfd, error_message)
358      bfd *abfd;
359      arelent *reloc_entry;
360      asymbol *symbol;
361      PTR data;
362      asection *input_section;
363      bfd *output_bfd;
364      char **error_message ATTRIBUTE_UNUSED;
365 {
366   unsigned long insn, vallo, allignment;
367   int           val;
368
369   /* HACK: I think this first condition is necessary when producing
370      relocatable output.  After the end of HACK, the code is identical
371      to bfd_elf_generic_reloc().  I would _guess_ the first change
372      belongs there rather than here.  martindo 1998-10-23.  */
373
374   if (skip_dlx_elf_hi16_reloc)
375     return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
376                                  input_section, output_bfd, error_message);
377
378   /* Check undefined section and undefined symbols.  */
379   if (bfd_is_und_section (symbol->section)
380       && output_bfd == (bfd *) NULL)
381     return bfd_reloc_undefined;
382
383   /* Can not support a long jump to sections other then .text   */
384   if (strcmp (input_section->name, symbol->section->output_section->name) != 0)
385     {
386       fprintf (stderr,
387                "BFD Link Error: jump (PC rel26) to section (%s) not supported\n",
388                symbol->section->output_section->name);
389       return bfd_reloc_undefined;
390     }
391
392   insn  = bfd_get_32 (abfd, (bfd_byte *)data + reloc_entry->address);
393   allignment = 1 << (input_section->output_section->alignment_power - 1);
394   vallo = insn & 0x03FFFFFF;
395
396   if (vallo & 0x03000000)
397     vallo = ~(vallo | 0xFC000000) + 1;
398
399   /* vallo is the vma for the next instruction.  */
400   vallo += (((unsigned long) (input_section->output_section->vma +
401                               input_section->output_offset) +
402              allignment) & ~allignment);
403
404   /* val is the displacement (PC relative to next instruction).  */
405   val = (symbol->section->output_offset +
406          symbol->section->output_section->vma + symbol->value)
407     - vallo;
408
409   if (abs ((int) val) > 0x01FFFFFF)
410     return bfd_reloc_outofrange;
411
412   insn  = (insn & 0xFC000000) | (val & 0x03FFFFFF);
413   bfd_put_32 (abfd, insn,
414               (bfd_byte *) data + reloc_entry->address);
415
416   return bfd_reloc_ok;
417 }
418
419 /* A mapping from BFD reloc types to DLX ELF reloc types.
420    Stolen from elf32-mips.c.
421
422    More about this table - for dlx elf relocation we do not really
423    need this table, if we have a rtype defined in this table will
424    caused tc_gen_relocate confused and die on us, but if we remove
425    this table it will caused more problem, so for now simple solution
426    is to remove those entries which may cause problem.  */
427 struct elf_reloc_map
428 {
429   bfd_reloc_code_real_type bfd_reloc_val;
430   enum elf_dlx_reloc_type elf_reloc_val;
431 };
432
433 static const struct elf_reloc_map dlx_reloc_map[] =
434   {
435     { BFD_RELOC_NONE,           R_DLX_NONE },
436     { BFD_RELOC_16,             R_DLX_RELOC_16 },
437     { BFD_RELOC_32,             R_DLX_RELOC_32 },
438     { BFD_RELOC_DLX_HI16_S,     R_DLX_RELOC_16_HI },
439     { BFD_RELOC_DLX_LO16,       R_DLX_RELOC_16_LO },
440     { BFD_RELOC_VTABLE_INHERIT, R_DLX_GNU_VTINHERIT },
441     { BFD_RELOC_VTABLE_ENTRY,   R_DLX_GNU_VTENTRY }
442   };
443
444
445 /* Look through the relocs for a section during the first phase.
446    Since we don't do .gots or .plts, we just need to consider the
447    virtual table relocs for gc.  */
448
449 static bfd_boolean
450 elf32_dlx_check_relocs (abfd, info, sec, relocs)
451      bfd *abfd;
452      struct bfd_link_info *info;
453      asection *sec;
454      const Elf_Internal_Rela *relocs;
455 {
456   Elf_Internal_Shdr *symtab_hdr;
457   struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
458   const Elf_Internal_Rela *rel;
459   const Elf_Internal_Rela *rel_end;
460
461   if (info->relocatable)
462     return TRUE;
463
464   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
465   sym_hashes = elf_sym_hashes (abfd);
466   sym_hashes_end = sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
467   if (!elf_bad_symtab (abfd))
468     sym_hashes_end -= symtab_hdr->sh_info;
469
470   rel_end = relocs + sec->reloc_count;
471   for (rel = relocs; rel < rel_end; rel++)
472     {
473       struct elf_link_hash_entry *h;
474       unsigned long r_symndx;
475
476       r_symndx = ELF32_R_SYM (rel->r_info);
477       if (r_symndx < symtab_hdr->sh_info)
478         h = NULL;
479       else
480         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
481
482       switch (ELF32_R_TYPE (rel->r_info))
483         {
484         /* This relocation describes the C++ object vtable hierarchy.
485            Reconstruct it for later use during GC.  */
486         case R_DLX_GNU_VTINHERIT:
487           if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
488             return FALSE;
489           break;
490
491         /* This relocation describes which C++ vtable entries are actually
492            used.  Record for later use during GC.  */
493         case R_DLX_GNU_VTENTRY:
494           if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
495             return FALSE;
496           break;
497         }
498     }
499
500   return TRUE;
501 }
502
503 /* Given a BFD reloc type, return a howto structure.  */
504
505 static reloc_howto_type *
506 elf32_dlx_reloc_type_lookup (abfd, code)
507      bfd *abfd ATTRIBUTE_UNUSED;
508      bfd_reloc_code_real_type code;
509 {
510   unsigned int i;
511
512   for (i = 0; i < sizeof (dlx_reloc_map) / sizeof (struct elf_reloc_map); i++)
513     if (dlx_reloc_map[i].bfd_reloc_val == code)
514       return &dlx_elf_howto_table[(int) dlx_reloc_map[i].elf_reloc_val];
515
516   switch (code)
517     {
518     default:
519       bfd_set_error (bfd_error_bad_value);
520       return NULL;
521     case BFD_RELOC_16_PCREL_S2:
522       return &elf_dlx_gnu_rel16_s2;
523     case BFD_RELOC_DLX_JMP26:
524       return &elf_dlx_gnu_rel26_s2;
525     case BFD_RELOC_HI16_S:
526       return &elf_dlx_reloc_16_hi;
527     case BFD_RELOC_LO16:
528       return &elf_dlx_reloc_16_lo;
529     }
530 }
531
532 static reloc_howto_type *
533 dlx_rtype_to_howto (r_type)
534      unsigned int r_type;
535 {
536   switch (r_type)
537     {
538     case R_DLX_RELOC_16_PCREL:
539       return & elf_dlx_gnu_rel16_s2;
540       break;
541     case R_DLX_RELOC_26_PCREL:
542       return & elf_dlx_gnu_rel26_s2;
543       break;
544     case R_DLX_RELOC_16_HI:
545       return & elf_dlx_reloc_16_hi;
546       break;
547     case R_DLX_RELOC_16_LO:
548       return & elf_dlx_reloc_16_lo;
549       break;
550
551     default:
552       BFD_ASSERT (r_type < (unsigned int) R_DLX_max);
553       return & dlx_elf_howto_table[r_type];
554       break;
555     }
556 }
557
558 static void
559 elf32_dlx_info_to_howto (abfd, cache_ptr, dst)
560      bfd * abfd ATTRIBUTE_UNUSED;
561      arelent * cache_ptr ATTRIBUTE_UNUSED;
562      Elf_Internal_Rela * dst ATTRIBUTE_UNUSED;
563 {
564   abort ();
565 }
566
567 static void
568 elf32_dlx_info_to_howto_rel (abfd, cache_ptr, dst)
569      bfd *abfd ATTRIBUTE_UNUSED;
570      arelent *cache_ptr;
571      Elf_Internal_Rela *dst;
572 {
573   unsigned int r_type;
574
575   r_type = ELF32_R_TYPE (dst->r_info);
576   cache_ptr->howto = dlx_rtype_to_howto (r_type);
577   return;
578 }
579
580 #define TARGET_BIG_SYM          bfd_elf32_dlx_big_vec
581 #define TARGET_BIG_NAME         "elf32-dlx"
582 #define ELF_ARCH                bfd_arch_dlx
583 #define ELF_MACHINE_CODE        EM_DLX
584 #define ELF_MAXPAGESIZE         1 /* FIXME: This number is wrong,  It should be the page size in bytes.  */
585
586 #include "elf32-target.h"