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
26int    set_dlx_skip_hi16_flag PARAMS ((int));
27
28static bfd_boolean elf32_dlx_check_relocs
29  PARAMS ((bfd *, struct bfd_link_info *, asection *,
30	   const Elf_Internal_Rela *));
31static void elf32_dlx_info_to_howto
32  PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
33static void elf32_dlx_info_to_howto_rel
34  PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
35static bfd_reloc_status_type elf32_dlx_relocate16
36  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
37static bfd_reloc_status_type elf32_dlx_relocate26
38  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
39static reloc_howto_type *elf32_dlx_reloc_type_lookup
40  PARAMS ((bfd *, bfd_reloc_code_real_type));
41static bfd_reloc_status_type _bfd_dlx_elf_hi16_reloc
42  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
43static 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
54static 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#if 0
102    /* 26 bit jump address.  */
103    HOWTO (R_DLX_RELOC_26,        /* type */
104	   0,                     /* rightshift */
105	   2,                     /* size (0 = byte, 1 = short, 2 = long) */
106	   26,                    /* bitsize */
107	   FALSE,                 /* pc_relative */
108	   0,                     /* bitpos */
109	   complain_overflow_dont,/* complain_on_overflow */
110	   /* This needs complex overflow detection, because the upper four
111	      bits must match the PC + 4.  */
112	   bfd_elf_generic_reloc, /* special_function */
113	   "R_DLX_RELOC_26",      /* name */
114	   TRUE,                  /* partial_inplace */
115	   0x3ffffff,             /* src_mask */
116	   0x3ffffff,             /* dst_mask */
117	   FALSE),                /* pcrel_offset */
118#endif
119
120    /* 32 bit relocation.  */
121    HOWTO (R_DLX_RELOC_32,        /* type */
122	   0,                     /* rightshift */
123	   2,                     /* size (0 = byte, 1 = short, 2 = long) */
124	   32,                    /* bitsize */
125	   FALSE,                 /* pc_relative */
126	   0,                     /* bitpos */
127	   complain_overflow_dont,/* complain_on_overflow */
128	   bfd_elf_generic_reloc, /* special_function */
129	   "R_DLX_RELOC_32",      /* name */
130	   TRUE,                  /* partial_inplace */
131	   0xffffffff,            /* src_mask */
132	   0xffffffff,            /* dst_mask */
133	   FALSE),                /* pcrel_offset */
134
135    /* GNU extension to record C++ vtable hierarchy */
136    HOWTO (R_DLX_GNU_VTINHERIT,   /* type */
137	   0,			  /* rightshift */
138	   2,			  /* size (0 = byte, 1 = short, 2 = long) */
139	   0,			  /* bitsize */
140	   FALSE,		  /* pc_relative */
141	   0,			  /* bitpos */
142	   complain_overflow_dont,/* complain_on_overflow */
143	   NULL,		  /* special_function */
144	   "R_DLX_GNU_VTINHERIT", /* name */
145	   FALSE,		  /* partial_inplace */
146	   0,			  /* src_mask */
147	   0,			  /* dst_mask */
148	   FALSE),		  /* pcrel_offset */
149
150    /* GNU extension to record C++ vtable member usage */
151    HOWTO (R_DLX_GNU_VTENTRY,     /* type */
152	   0,			  /* rightshift */
153	   2,			  /* size (0 = byte, 1 = short, 2 = long) */
154	   0,			  /* bitsize */
155	   FALSE,		  /* pc_relative */
156	   0,			  /* bitpos */
157	   complain_overflow_dont,/* complain_on_overflow */
158	   _bfd_elf_rel_vtable_reloc_fn,/* special_function */
159	   "R_DLX_GNU_VTENTRY",	  /* name */
160	   FALSE,		  /* partial_inplace */
161	   0,			  /* src_mask */
162	   0,			  /* dst_mask */
163	   FALSE)		  /* pcrel_offset */
164  };
165
166/* 16 bit offset for pc-relative branches.  */
167static reloc_howto_type elf_dlx_gnu_rel16_s2 =
168HOWTO (R_DLX_RELOC_16_PCREL,  /* type */
169       0,                     /* rightshift */
170       1,                     /* size (0 = byte, 1 = short, 2 = long) */
171       16,                    /* bitsize */
172       TRUE,                  /* pc_relative */
173       0,                     /* bitpos */
174       complain_overflow_signed, /* complain_on_overflow */
175       elf32_dlx_relocate16,  /* special_function */
176       "R_DLX_RELOC_16_PCREL",/* name */
177       TRUE,                  /* partial_inplace */
178       0xffff,                /* src_mask */
179       0xffff,                /* dst_mask */
180       TRUE);                 /* pcrel_offset */
181
182/* 26 bit offset for pc-relative branches.  */
183static reloc_howto_type elf_dlx_gnu_rel26_s2 =
184HOWTO (R_DLX_RELOC_26_PCREL,  /* type */
185       0,                     /* rightshift */
186       2,                     /* size (0 = byte, 1 = short, 2 = long) */
187       26,                    /* bitsize */
188       TRUE,                  /* pc_relative */
189       0,                     /* bitpos */
190       complain_overflow_dont,/* complain_on_overflow */
191       elf32_dlx_relocate26,  /* special_function */
192       "R_DLX_RELOC_26_PCREL",/* name */
193       TRUE,                  /* partial_inplace */
194       0xffff,                /* src_mask */
195       0xffff,                /* dst_mask */
196       TRUE);                 /* pcrel_offset */
197
198/* High 16 bits of symbol value.  */
199static reloc_howto_type elf_dlx_reloc_16_hi =
200HOWTO (R_DLX_RELOC_16_HI,     /* type */
201       16,                    /* rightshift */
202       2,                     /* size (0 = byte, 1 = short, 2 = long) */
203       32,                    /* bitsize */
204       FALSE,                 /* pc_relative */
205       0,                     /* bitpos */
206       complain_overflow_dont, /* complain_on_overflow */
207       _bfd_dlx_elf_hi16_reloc,/* special_function */
208       "R_DLX_RELOC_16_HI",   /* name */
209       TRUE,                  /* partial_inplace */
210       0xFFFF,                /* src_mask */
211       0xffff,                /* dst_mask */
212       FALSE);                /* pcrel_offset */
213
214  /* Low 16 bits of symbol value.  */
215static reloc_howto_type elf_dlx_reloc_16_lo =
216HOWTO (R_DLX_RELOC_16_LO,     /* type */
217       0,                     /* rightshift */
218       1,                     /* size (0 = byte, 1 = short, 2 = long) */
219       16,                    /* bitsize */
220       FALSE,                 /* pc_relative */
221       0,                     /* bitpos */
222       complain_overflow_dont,/* complain_on_overflow */
223       bfd_elf_generic_reloc, /* special_function */
224       "R_DLX_RELOC_16_LO",   /* name */
225       TRUE,                  /* partial_inplace */
226       0xffff,                /* src_mask */
227       0xffff,                /* dst_mask */
228       FALSE);                /* pcrel_offset */
229
230
231/* The gas default behavior is not to preform the %hi modifier so that the
232   GNU assembler can have the lower 16 bits offset placed in the insn, BUT
233   we do like the gas to indicate it is %hi reloc type so when we in the link
234   loader phase we can have the corrected hi16 vale replace the buggous lo16
235   value that was placed there by gas.  */
236
237static int skip_dlx_elf_hi16_reloc = 0;
238
239int
240set_dlx_skip_hi16_flag (flag)
241     int flag;
242{
243  skip_dlx_elf_hi16_reloc = flag;
244  return flag;
245}
246
247static bfd_reloc_status_type
248_bfd_dlx_elf_hi16_reloc (abfd, reloc_entry, symbol, data,
249			 input_section, output_bfd, error_message)
250     bfd *abfd;
251     arelent *reloc_entry;
252     asymbol *symbol;
253     PTR data;
254     asection *input_section;
255     bfd *output_bfd;
256     char **error_message;
257{
258  bfd_reloc_status_type ret;
259  bfd_vma relocation;
260
261  /* If the skip flag is set then we simply do the generic relocating, this
262     is more of a hack for dlx gas/gld, so we do not need to do the %hi/%lo
263     fixup like mips gld did.   */
264#if 0
265  printf ("DEBUG: skip_dlx_elf_hi16_reloc = 0x%08x\n", skip_dlx_elf_hi16_reloc);
266#endif
267  if (skip_dlx_elf_hi16_reloc)
268    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
269                          input_section, output_bfd, error_message);
270
271  /* If we're relocating, and this an external symbol, we don't want
272     to change anything.  */
273  if (output_bfd != (bfd *) NULL
274      && (symbol->flags & BSF_SECTION_SYM) == 0
275      && reloc_entry->addend == 0)
276    {
277      reloc_entry->address += input_section->output_offset;
278      return bfd_reloc_ok;
279    }
280
281  ret = bfd_reloc_ok;
282
283  if (bfd_is_und_section (symbol->section)
284      && output_bfd == (bfd *) NULL)
285    ret = bfd_reloc_undefined;
286
287#if 0
288  {
289    unsigned long vallo, val;
290
291    vallo = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address);
292    printf ("DEBUG: The relocation address = 0x%08x\n", reloc_entry->address);
293    printf ("DEBUG: The symbol        = 0x%08x\n", vallo);
294    printf ("DEBUG: The symbol name   = %s\n", bfd_asymbol_name (symbol));
295    printf ("DEBUG: The symbol->value = 0x%08x\n", symbol->value);
296    printf ("DEBUG: The vma           = 0x%08x\n", symbol->section->output_section->vma);
297    printf ("DEBUG: The output_offset = 0x%08x\n", symbol->section->output_offset);
298    printf ("DEBUG: The input_offset  = 0x%08x\n", input_section->output_offset);
299    printf ("DEBUG: The input_vma     = 0x%08x\n", input_section->vma);
300    printf ("DEBUG: The addend        = 0x%08x\n", reloc_entry->addend);
301  }
302#endif
303
304  relocation = (bfd_is_com_section (symbol->section)) ? 0 : symbol->value;
305  relocation += symbol->section->output_section->vma;
306  relocation += symbol->section->output_offset;
307  relocation += reloc_entry->addend;
308  relocation += bfd_get_16 (abfd, (bfd_byte *)data + reloc_entry->address);
309
310  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
311    return bfd_reloc_outofrange;
312
313#if 0
314  printf ("DEBUG: The finial relocation value = 0x%08x\n", relocation);
315#endif
316
317  bfd_put_16 (abfd, (short)((relocation >> 16) & 0xFFFF),
318              (bfd_byte *)data + reloc_entry->address);
319
320  return ret;
321}
322
323/* ELF relocs are against symbols.  If we are producing relocatable
324   output, and the reloc is against an external symbol, and nothing
325   has given us any additional addend, the resulting reloc will also
326   be against the same symbol.  In such a case, we don't want to
327   change anything about the way the reloc is handled, since it will
328   all be done at final link time.  Rather than put special case code
329   into bfd_perform_relocation, all the reloc types use this howto
330   function.  It just short circuits the reloc if producing
331   relocatable output against an external symbol.  */
332
333static bfd_reloc_status_type
334elf32_dlx_relocate16  (abfd, reloc_entry, symbol, data,
335                       input_section, output_bfd, error_message)
336     bfd *abfd;
337     arelent *reloc_entry;
338     asymbol *symbol;
339     PTR data;
340     asection *input_section;
341     bfd *output_bfd;
342     char **error_message ATTRIBUTE_UNUSED;
343{
344  unsigned long insn, vallo, allignment;
345  int           val;
346
347  /* HACK: I think this first condition is necessary when producing
348     relocatable output.  After the end of HACK, the code is identical
349     to bfd_elf_generic_reloc().  I would _guess_ the first change
350     belongs there rather than here.  martindo 1998-10-23.  */
351
352  if (skip_dlx_elf_hi16_reloc)
353    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
354                                 input_section, output_bfd, error_message);
355
356  /* Check undefined section and undefined symbols  */
357  if (bfd_is_und_section (symbol->section)
358      && output_bfd == (bfd *) NULL)
359    return bfd_reloc_undefined;
360
361  /* Can not support a long jump to sections other then .text   */
362  if (strcmp (input_section->name, symbol->section->output_section->name) != 0)
363    {
364      fprintf (stderr,
365	       "BFD Link Error: branch (PC rel16) to section (%s) not supported\n",
366	       symbol->section->output_section->name);
367      return bfd_reloc_undefined;
368    }
369
370  insn  = bfd_get_32 (abfd, (bfd_byte *)data + reloc_entry->address);
371  allignment = 1 << (input_section->output_section->alignment_power - 1);
372  vallo = insn & 0x0000FFFF;
373
374  if (vallo & 0x8000)
375    vallo = ~(vallo | 0xFFFF0000) + 1;
376
377  /* vallo points to the vma of next instruction.  */
378  vallo += (((unsigned long)(input_section->output_section->vma +
379                           input_section->output_offset) +
380            allignment) & ~allignment);
381
382  /* val is the displacement (PC relative to next instruction).  */
383  val =  (symbol->section->output_offset +
384	  symbol->section->output_section->vma +
385	  symbol->value) - vallo;
386#if 0
387  printf ("DEBUG elf32_dlx_relocate: We are here\n");
388  printf ("DEBUG: The insn            = 0x%08x\n", insn);
389  printf ("DEBUG: The vallo           = 0x%08x\n", vallo);
390  printf ("DEBUG: The val             = 0x%08x\n", val);
391  printf ("DEBUG: The symbol name     = %s\n", bfd_asymbol_name (symbol));
392  printf ("DEBUG: The symbol->value   = 0x%08x\n", symbol->value);
393  printf ("DEBUG: The vma             = 0x%08x\n", symbol->section->output_section->vma);
394  printf ("DEBUG: The lma             = 0x%08x\n", symbol->section->output_section->lma);
395  printf ("DEBUG: The alignment_power = 0x%08x\n", symbol->section->output_section->alignment_power);
396  printf ("DEBUG: The output_offset   = 0x%08x\n", symbol->section->output_offset);
397  printf ("DEBUG: The addend          = 0x%08x\n", reloc_entry->addend);
398#endif
399
400  if (abs ((int) val) > 0x00007FFF)
401    return bfd_reloc_outofrange;
402
403  insn  = (insn & 0xFFFF0000) | (val & 0x0000FFFF);
404
405  bfd_put_32 (abfd, insn,
406              (bfd_byte *) data + reloc_entry->address);
407
408  return bfd_reloc_ok;
409}
410
411static bfd_reloc_status_type
412elf32_dlx_relocate26  (abfd, reloc_entry, symbol, data,
413                       input_section, output_bfd, error_message)
414     bfd *abfd;
415     arelent *reloc_entry;
416     asymbol *symbol;
417     PTR data;
418     asection *input_section;
419     bfd *output_bfd;
420     char **error_message ATTRIBUTE_UNUSED;
421{
422  unsigned long insn, vallo, allignment;
423  int           val;
424
425  /* HACK: I think this first condition is necessary when producing
426     relocatable output.  After the end of HACK, the code is identical
427     to bfd_elf_generic_reloc().  I would _guess_ the first change
428     belongs there rather than here.  martindo 1998-10-23.  */
429
430  if (skip_dlx_elf_hi16_reloc)
431    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
432                                 input_section, output_bfd, error_message);
433
434  /* Check undefined section and undefined symbols.  */
435  if (bfd_is_und_section (symbol->section)
436      && output_bfd == (bfd *) NULL)
437    return bfd_reloc_undefined;
438
439  /* Can not support a long jump to sections other then .text   */
440  if (strcmp (input_section->name, symbol->section->output_section->name) != 0)
441    {
442      fprintf (stderr,
443	       "BFD Link Error: jump (PC rel26) to section (%s) not supported\n",
444	       symbol->section->output_section->name);
445      return bfd_reloc_undefined;
446    }
447
448  insn  = bfd_get_32 (abfd, (bfd_byte *)data + reloc_entry->address);
449  allignment = 1 << (input_section->output_section->alignment_power - 1);
450  vallo = insn & 0x03FFFFFF;
451
452  if (vallo & 0x03000000)
453    vallo = ~(vallo | 0xFC000000) + 1;
454
455  /* vallo is the vma for the next instruction.  */
456  vallo += (((unsigned long) (input_section->output_section->vma +
457			      input_section->output_offset) +
458	     allignment) & ~allignment);
459
460  /* val is the displacement (PC relative to next instruction).  */
461  val = (symbol->section->output_offset +
462	 symbol->section->output_section->vma + symbol->value)
463    - vallo;
464#if 0
465  printf ("DEBUG elf32_dlx_relocate26: We are here\n");
466  printf ("DEBUG: The insn          = 0x%08x\n", insn);
467  printf ("DEBUG: The vallo         = 0x%08x\n", vallo);
468  printf ("DEBUG: The val           = 0x%08x\n", val);
469  printf ("DEBUG: The abs(val)      = 0x%08x\n", abs (val));
470  printf ("DEBUG: The symbol name   = %s\n", bfd_asymbol_name (symbol));
471  printf ("DEBUG: The symbol->value = 0x%08x\n", symbol->value);
472  printf ("DEBUG: The vma           = 0x%08x\n", symbol->section->output_section->vma);
473  printf ("DEBUG: The output_offset = 0x%08x\n", symbol->section->output_offset);
474  printf ("DEBUG: The input_vma     = 0x%08x\n", input_section->output_section->vma);
475  printf ("DEBUG: The input_offset  = 0x%08x\n", input_section->output_offset);
476  printf ("DEBUG: The input_name    = %s\n", input_section->name);
477  printf ("DEBUG: The addend        = 0x%08x\n", reloc_entry->addend);
478#endif
479
480  if (abs ((int) val) > 0x01FFFFFF)
481    return bfd_reloc_outofrange;
482
483  insn  = (insn & 0xFC000000) | (val & 0x03FFFFFF);
484  bfd_put_32 (abfd, insn,
485              (bfd_byte *) data + reloc_entry->address);
486
487  return bfd_reloc_ok;
488}
489
490/* A mapping from BFD reloc types to DLX ELF reloc types.
491   Stolen from elf32-mips.c.
492
493   More about this table - for dlx elf relocation we do not really
494   need this table, if we have a rtype defined in this table will
495   caused tc_gen_relocate confused and die on us, but if we remove
496   this table it will caused more problem, so for now simple solution
497   is to remove those entries which may cause problem.  */
498struct elf_reloc_map
499{
500  bfd_reloc_code_real_type bfd_reloc_val;
501  enum elf_dlx_reloc_type elf_reloc_val;
502};
503
504static const struct elf_reloc_map dlx_reloc_map[] =
505  {
506    { BFD_RELOC_NONE,           R_DLX_NONE },
507    { BFD_RELOC_16,             R_DLX_RELOC_16 },
508#if 0
509    { BFD_RELOC_DLX_JMP26,      R_DLX_RELOC_26_PCREL },
510#endif
511    { BFD_RELOC_32,             R_DLX_RELOC_32 },
512    { BFD_RELOC_DLX_HI16_S,     R_DLX_RELOC_16_HI },
513    { BFD_RELOC_DLX_LO16,       R_DLX_RELOC_16_LO },
514    { BFD_RELOC_VTABLE_INHERIT,	R_DLX_GNU_VTINHERIT },
515    { BFD_RELOC_VTABLE_ENTRY,	R_DLX_GNU_VTENTRY }
516  };
517
518
519/* Look through the relocs for a section during the first phase.
520   Since we don't do .gots or .plts, we just need to consider the
521   virtual table relocs for gc.  */
522
523static bfd_boolean
524elf32_dlx_check_relocs (abfd, info, sec, relocs)
525     bfd *abfd;
526     struct bfd_link_info *info;
527     asection *sec;
528     const Elf_Internal_Rela *relocs;
529{
530  Elf_Internal_Shdr *symtab_hdr;
531  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
532  const Elf_Internal_Rela *rel;
533  const Elf_Internal_Rela *rel_end;
534
535  if (info->relocatable)
536    return TRUE;
537
538  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
539  sym_hashes = elf_sym_hashes (abfd);
540  sym_hashes_end = sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
541  if (!elf_bad_symtab (abfd))
542    sym_hashes_end -= symtab_hdr->sh_info;
543
544  rel_end = relocs + sec->reloc_count;
545  for (rel = relocs; rel < rel_end; rel++)
546    {
547      struct elf_link_hash_entry *h;
548      unsigned long r_symndx;
549
550      r_symndx = ELF32_R_SYM (rel->r_info);
551      if (r_symndx < symtab_hdr->sh_info)
552        h = NULL;
553      else
554        h = sym_hashes[r_symndx - symtab_hdr->sh_info];
555
556      switch (ELF32_R_TYPE (rel->r_info))
557        {
558        /* This relocation describes the C++ object vtable hierarchy.
559           Reconstruct it for later use during GC.  */
560        case R_DLX_GNU_VTINHERIT:
561          if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
562            return FALSE;
563          break;
564
565        /* This relocation describes which C++ vtable entries are actually
566           used.  Record for later use during GC.  */
567        case R_DLX_GNU_VTENTRY:
568          if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
569            return FALSE;
570          break;
571        }
572    }
573
574  return TRUE;
575}
576
577/* Given a BFD reloc type, return a howto structure.  */
578
579static reloc_howto_type *
580elf32_dlx_reloc_type_lookup (abfd, code)
581     bfd *abfd ATTRIBUTE_UNUSED;
582     bfd_reloc_code_real_type code;
583{
584  unsigned int i;
585
586  for (i = 0; i < sizeof (dlx_reloc_map) / sizeof (struct elf_reloc_map); i++)
587    if (dlx_reloc_map[i].bfd_reloc_val == code)
588      return &dlx_elf_howto_table[(int) dlx_reloc_map[i].elf_reloc_val];
589
590  switch (code)
591    {
592    default:
593      bfd_set_error (bfd_error_bad_value);
594      return NULL;
595    case BFD_RELOC_16_PCREL_S2:
596      return &elf_dlx_gnu_rel16_s2;
597    case BFD_RELOC_DLX_JMP26:
598      return &elf_dlx_gnu_rel26_s2;
599    case BFD_RELOC_HI16_S:
600      return &elf_dlx_reloc_16_hi;
601    case BFD_RELOC_LO16:
602      return &elf_dlx_reloc_16_lo;
603    }
604}
605
606static reloc_howto_type *
607dlx_rtype_to_howto (r_type)
608     unsigned int r_type;
609{
610  switch (r_type)
611    {
612    case R_DLX_RELOC_16_PCREL:
613      return & elf_dlx_gnu_rel16_s2;
614      break;
615    case R_DLX_RELOC_26_PCREL:
616      return & elf_dlx_gnu_rel26_s2;
617      break;
618    case R_DLX_RELOC_16_HI:
619      return & elf_dlx_reloc_16_hi;
620      break;
621    case R_DLX_RELOC_16_LO:
622      return & elf_dlx_reloc_16_lo;
623      break;
624
625    default:
626      BFD_ASSERT (r_type < (unsigned int) R_DLX_max);
627      return & dlx_elf_howto_table[r_type];
628      break;
629    }
630}
631
632static void
633elf32_dlx_info_to_howto (abfd, cache_ptr, dst)
634     bfd * abfd ATTRIBUTE_UNUSED;
635     arelent * cache_ptr ATTRIBUTE_UNUSED;
636     Elf_Internal_Rela * dst ATTRIBUTE_UNUSED;
637{
638  abort ();
639}
640
641static void
642elf32_dlx_info_to_howto_rel (abfd, cache_ptr, dst)
643     bfd *abfd ATTRIBUTE_UNUSED;
644     arelent *cache_ptr;
645     Elf_Internal_Rela *dst;
646{
647  unsigned int r_type;
648
649  r_type = ELF32_R_TYPE (dst->r_info);
650  cache_ptr->howto = dlx_rtype_to_howto (r_type);
651  return;
652}
653
654#define TARGET_BIG_SYM          bfd_elf32_dlx_big_vec
655#define TARGET_BIG_NAME         "elf32-dlx"
656#define ELF_ARCH                bfd_arch_dlx
657#define ELF_MACHINE_CODE        EM_DLX
658#define ELF_MAXPAGESIZE         1 /* FIXME: This number is wrong,  It should be the page size in bytes.  */
659
660#include "elf32-target.h"
661