Back to index

cell-binutils  2.17cvs20070401
elf32-xstormy16.c
Go to the documentation of this file.
00001 /* Xstormy16-specific support for 32-bit ELF.
00002    Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
00003    Free Software Foundation, Inc.
00004 
00005    This file is part of BFD, the Binary File Descriptor library.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the Free Software
00019    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
00020    USA.  */
00021 
00022 #include "bfd.h"
00023 #include "sysdep.h"
00024 #include "libbfd.h"
00025 #include "elf-bfd.h"
00026 #include "elf/xstormy16.h"
00027 #include "libiberty.h"
00028 
00029 /* Handle the R_XSTORMY16_24 reloc, which has an odd bit arrangement.  */
00030 
00031 static bfd_reloc_status_type
00032 xstormy16_elf_24_reloc (bfd *abfd,
00033                      arelent *reloc_entry,
00034                      asymbol *symbol,
00035                      void * data,
00036                      asection *input_section,
00037                      bfd *output_bfd,
00038                      char **error_message ATTRIBUTE_UNUSED)
00039 {
00040   bfd_vma relocation, x;
00041 
00042   if (output_bfd != NULL)
00043     {
00044       reloc_entry->address += input_section->output_offset;
00045       return bfd_reloc_ok;
00046     }
00047 
00048   if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
00049     return bfd_reloc_outofrange;
00050 
00051   if (bfd_is_com_section (symbol->section))
00052     relocation = 0;
00053   else
00054     relocation = symbol->value;
00055 
00056   relocation += symbol->section->output_section->vma;
00057   relocation += symbol->section->output_offset;
00058   relocation += reloc_entry->addend;
00059 
00060   x = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
00061   x &= 0x0000ff00;
00062   x |= relocation & 0xff;
00063   x |= (relocation << 8) & 0xffff0000;
00064   bfd_put_32 (abfd, x, (bfd_byte *) data + reloc_entry->address);
00065 
00066   if (relocation & ~ (bfd_vma) 0xffffff)
00067     return bfd_reloc_overflow;
00068 
00069   return bfd_reloc_ok;
00070 }
00071 
00072 static reloc_howto_type xstormy16_elf_howto_table [] =
00073 {
00074   /* This reloc does nothing.  */
00075   HOWTO (R_XSTORMY16_NONE,  /* type */
00076         0,                  /* rightshift */
00077         2,                  /* size (0 = byte, 1 = short, 2 = long) */
00078         32,                 /* bitsize */
00079         FALSE,                     /* pc_relative */
00080         0,                  /* bitpos */
00081         complain_overflow_bitfield, /* complain_on_overflow */
00082         bfd_elf_generic_reloc,     /* special_function */
00083         "R_XSTORMY16_NONE", /* name */
00084         FALSE,                     /* partial_inplace */
00085         0,                  /* src_mask */
00086         0,                  /* dst_mask */
00087         FALSE),             /* pcrel_offset */
00088 
00089   /* A 32 bit absolute relocation.  */
00090   HOWTO (R_XSTORMY16_32,    /* type */
00091         0,                  /* rightshift */
00092         2,                  /* size (0 = byte, 1 = short, 2 = long) */
00093         32,                 /* bitsize */
00094         FALSE,                     /* pc_relative */
00095         0,                  /* bitpos */
00096         complain_overflow_dont, /* complain_on_overflow */
00097         bfd_elf_generic_reloc,     /* special_function */
00098         "R_XSTORMY16_32",   /* name */
00099         FALSE,                     /* partial_inplace */
00100         0,                  /* src_mask */
00101         0xffffffff,         /* dst_mask */
00102         FALSE),             /* pcrel_offset */
00103 
00104   /* A 16 bit absolute relocation.  */
00105   HOWTO (R_XSTORMY16_16,    /* type */
00106         0,                  /* rightshift */
00107         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00108         16,                 /* bitsize */
00109         FALSE,                     /* pc_relative */
00110         0,                  /* bitpos */
00111         complain_overflow_bitfield, /* complain_on_overflow */
00112         bfd_elf_generic_reloc,     /* special_function */
00113         "R_XSTORMY16_16",   /* name */
00114         FALSE,                     /* partial_inplace */
00115         0,                  /* src_mask */
00116         0xffff,             /* dst_mask */
00117         FALSE),             /* pcrel_offset */
00118 
00119   /* An 8 bit absolute relocation.  */
00120   HOWTO (R_XSTORMY16_8,            /* type */
00121         0,                  /* rightshift */
00122         0,                  /* size (0 = byte, 1 = short, 2 = long) */
00123         8,                  /* bitsize */
00124         FALSE,                     /* pc_relative */
00125         0,                  /* bitpos */
00126         complain_overflow_unsigned, /* complain_on_overflow */
00127         bfd_elf_generic_reloc,     /* special_function */
00128         "R_XSTORMY16_8",    /* name */
00129         FALSE,                     /* partial_inplace */
00130         0,                  /* src_mask */
00131         0xff,               /* dst_mask */
00132         FALSE),             /* pcrel_offset */
00133 
00134   /* A 32 bit pc-relative relocation.  */
00135   HOWTO (R_XSTORMY16_PC32,  /* type */
00136         0,                  /* rightshift */
00137         2,                  /* size (0 = byte, 1 = short, 2 = long) */
00138         32,                 /* bitsize */
00139         TRUE,               /* pc_relative */
00140         0,                  /* bitpos */
00141         complain_overflow_dont, /* complain_on_overflow */
00142         bfd_elf_generic_reloc,     /* special_function */
00143         "R_XSTORMY16_PC32", /* name */
00144         FALSE,                     /* partial_inplace */
00145         0,                  /* src_mask */
00146         0xffffffff,         /* dst_mask */
00147         TRUE),                     /* pcrel_offset */
00148 
00149   /* A 16 bit pc-relative relocation.  */
00150   HOWTO (R_XSTORMY16_PC16,  /* type */
00151         0,                  /* rightshift */
00152         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00153         16,                 /* bitsize */
00154         TRUE,               /* pc_relative */
00155         0,                  /* bitpos */
00156         complain_overflow_signed, /* complain_on_overflow */
00157         bfd_elf_generic_reloc,     /* special_function */
00158         "R_XSTORMY16_PC16", /* name */
00159         FALSE,                     /* partial_inplace */
00160         0,                  /* src_mask */
00161         0xffffffff,         /* dst_mask */
00162         TRUE),                     /* pcrel_offset */
00163 
00164   /* An 8 bit pc-relative relocation.  */
00165   HOWTO (R_XSTORMY16_PC8,   /* type */
00166         0,                  /* rightshift */
00167         0,                  /* size (0 = byte, 1 = short, 2 = long) */
00168         8,                  /* bitsize */
00169         TRUE,               /* pc_relative */
00170         0,                  /* bitpos */
00171         complain_overflow_signed, /* complain_on_overflow */
00172         bfd_elf_generic_reloc,     /* special_function */
00173         "R_XSTORMY16_PC8",  /* name */
00174         FALSE,                     /* partial_inplace */
00175         0,                  /* src_mask */
00176         0xffffffff,         /* dst_mask */
00177         TRUE),                     /* pcrel_offset */
00178 
00179   /* A 12-bit pc-relative relocation suitable for the branch instructions.  */
00180   HOWTO (R_XSTORMY16_REL_12,       /* type */
00181         1,                  /* rightshift */
00182         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00183         11,                 /* bitsize */
00184         TRUE,               /* pc_relative */
00185         1,                  /* bitpos */
00186         complain_overflow_signed, /* complain_on_overflow */
00187         bfd_elf_generic_reloc,     /* special_function */
00188         "R_XSTORMY16_REL_12",      /* name */
00189         FALSE,                     /* partial_inplace */
00190         0,                  /* src_mask */
00191         0x0ffe,             /* dst_mask */
00192         TRUE),                     /* pcrel_offset */
00193 
00194   /* A 24-bit absolute relocation suitable for the jump instructions.  */
00195   HOWTO (R_XSTORMY16_24,    /* type */
00196         0,                  /* rightshift */
00197         2,                  /* size (0 = byte, 1 = short, 2 = long) */
00198         24,                 /* bitsize */
00199         FALSE,                     /* pc_relative */
00200         0,                  /* bitpos */
00201         complain_overflow_unsigned, /* complain_on_overflow */
00202         xstormy16_elf_24_reloc,    /* special_function */
00203         "R_XSTORMY16_24",   /* name */
00204         TRUE,               /* partial_inplace */
00205         0,                  /* src_mask */
00206         0xffff00ff,         /* dst_mask */
00207         TRUE),                     /* pcrel_offset */
00208 
00209   /* A 16 bit absolute relocation to a function pointer.  */
00210   HOWTO (R_XSTORMY16_FPTR16,       /* type */
00211         0,                  /* rightshift */
00212         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00213         16,                 /* bitsize */
00214         FALSE,                     /* pc_relative */
00215         0,                  /* bitpos */
00216         complain_overflow_bitfield, /* complain_on_overflow */
00217         bfd_elf_generic_reloc,     /* special_function */
00218         "R_XSTORMY16_FPTR16",      /* name */
00219         FALSE,                     /* partial_inplace */
00220         0,                  /* src_mask */
00221         0xffffffff,         /* dst_mask */
00222         FALSE),             /* pcrel_offset */
00223 
00224   /* Low order 16 bit value of a high memory address.  */
00225   HOWTO (R_XSTORMY16_LO16,  /* type */
00226         0,                  /* rightshift */
00227         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00228         16,                 /* bitsize */
00229         FALSE,                     /* pc_relative */
00230         0,                  /* bitpos */
00231         complain_overflow_dont, /* complain_on_overflow */
00232         bfd_elf_generic_reloc,     /* special_function */
00233         "R_XSTORMY16_LO16", /* name */
00234         FALSE,                     /* partial_inplace */
00235         0,                  /* src_mask */
00236         0xffff,             /* dst_mask */
00237         FALSE),             /* pcrel_offset */
00238 
00239   /* High order 16 bit value of a high memory address.  */
00240   HOWTO (R_XSTORMY16_HI16,  /* type */
00241         16,                 /* rightshift */
00242         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00243         16,                 /* bitsize */
00244         FALSE,                     /* pc_relative */
00245         0,                  /* bitpos */
00246         complain_overflow_dont, /* complain_on_overflow */
00247         bfd_elf_generic_reloc,     /* special_function */
00248         "R_XSTORMY16_HI16", /* name */
00249         FALSE,                     /* partial_inplace */
00250         0,                  /* src_mask */
00251         0xffff,             /* dst_mask */
00252         FALSE),             /* pcrel_offset */
00253 
00254   /* A 12 bit absolute relocation.  */
00255   HOWTO (R_XSTORMY16_12,    /* type */
00256         0,                  /* rightshift */
00257         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00258         12,                 /* bitsize */
00259         FALSE,                     /* pc_relative */
00260         0,                  /* bitpos */
00261         complain_overflow_signed, /* complain_on_overflow */
00262         bfd_elf_generic_reloc,     /* special_function */
00263         "R_XSTORMY16_12",   /* name */
00264         FALSE,                     /* partial_inplace */
00265         0x0000,             /* src_mask */
00266         0x0fff,             /* dst_mask */
00267         FALSE),             /* pcrel_offset */
00268 };
00269 
00270 static reloc_howto_type xstormy16_elf_howto_table2 [] =
00271 {
00272   /* GNU extension to record C++ vtable hierarchy */
00273   HOWTO (R_XSTORMY16_GNU_VTINHERIT, /* type */
00274          0,                     /* rightshift */
00275          2,                     /* size (0 = byte, 1 = short, 2 = long) */
00276          0,                     /* bitsize */
00277          FALSE,                 /* pc_relative */
00278          0,                     /* bitpos */
00279          complain_overflow_dont, /* complain_on_overflow */
00280          NULL,                  /* special_function */
00281          "R_XSTORMY16_GNU_VTINHERIT", /* name */
00282          FALSE,                 /* partial_inplace */
00283          0,                     /* src_mask */
00284          0,                     /* dst_mask */
00285          FALSE),                /* pcrel_offset */
00286 
00287   /* GNU extension to record C++ vtable member usage */
00288   HOWTO (R_XSTORMY16_GNU_VTENTRY,     /* type */
00289          0,                     /* rightshift */
00290          2,                     /* size (0 = byte, 1 = short, 2 = long) */
00291          0,                     /* bitsize */
00292          FALSE,                 /* pc_relative */
00293          0,                     /* bitpos */
00294          complain_overflow_dont, /* complain_on_overflow */
00295          _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
00296          "R_XSTORMY16_GNU_VTENTRY",   /* name */
00297          FALSE,                 /* partial_inplace */
00298          0,                     /* src_mask */
00299          0,                     /* dst_mask */
00300          FALSE),                /* pcrel_offset */
00301 
00302 };
00303 
00304 /* Map BFD reloc types to XSTORMY16 ELF reloc types.  */
00305 
00306 typedef struct xstormy16_reloc_map
00307 {
00308   bfd_reloc_code_real_type  bfd_reloc_val;
00309   unsigned int              xstormy16_reloc_val;
00310   reloc_howto_type *        table;
00311 } reloc_map;
00312 
00313 static const reloc_map xstormy16_reloc_map [] =
00314 {
00315   { BFD_RELOC_NONE,                 R_XSTORMY16_NONE,          xstormy16_elf_howto_table },
00316   { BFD_RELOC_32,                   R_XSTORMY16_32,            xstormy16_elf_howto_table },
00317   { BFD_RELOC_16,                   R_XSTORMY16_16,            xstormy16_elf_howto_table },
00318   { BFD_RELOC_8,                    R_XSTORMY16_8,             xstormy16_elf_howto_table },
00319   { BFD_RELOC_32_PCREL,             R_XSTORMY16_PC32,          xstormy16_elf_howto_table },
00320   { BFD_RELOC_16_PCREL,             R_XSTORMY16_PC16,          xstormy16_elf_howto_table },
00321   { BFD_RELOC_8_PCREL,              R_XSTORMY16_PC8,           xstormy16_elf_howto_table },
00322   { BFD_RELOC_XSTORMY16_REL_12,     R_XSTORMY16_REL_12,        xstormy16_elf_howto_table },
00323   { BFD_RELOC_XSTORMY16_24,     R_XSTORMY16_24,            xstormy16_elf_howto_table },
00324   { BFD_RELOC_XSTORMY16_FPTR16,        R_XSTORMY16_FPTR16,        xstormy16_elf_howto_table },
00325   { BFD_RELOC_LO16,                 R_XSTORMY16_LO16,          xstormy16_elf_howto_table },
00326   { BFD_RELOC_HI16,                 R_XSTORMY16_HI16,          xstormy16_elf_howto_table },
00327   { BFD_RELOC_XSTORMY16_12,         R_XSTORMY16_12,            xstormy16_elf_howto_table },
00328   { BFD_RELOC_VTABLE_INHERIT,       R_XSTORMY16_GNU_VTINHERIT, xstormy16_elf_howto_table2 },
00329   { BFD_RELOC_VTABLE_ENTRY,         R_XSTORMY16_GNU_VTENTRY,   xstormy16_elf_howto_table2 },
00330 };
00331 
00332 static reloc_howto_type *
00333 xstormy16_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
00334                           bfd_reloc_code_real_type code)
00335 {
00336   unsigned int i;
00337 
00338   for (i = ARRAY_SIZE (xstormy16_reloc_map); --i;)
00339     {
00340       const reloc_map * entry;
00341 
00342       entry = xstormy16_reloc_map + i;
00343 
00344       if (entry->bfd_reloc_val == code)
00345        return entry->table + (entry->xstormy16_reloc_val
00346                             - entry->table[0].type);
00347     }
00348 
00349   return NULL;
00350 }
00351 
00352 static reloc_howto_type *
00353 xstormy16_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
00354                           const char *r_name)
00355 {
00356   unsigned int i;
00357 
00358   for (i = 0;
00359        i < (sizeof (xstormy16_elf_howto_table)
00360            / sizeof (xstormy16_elf_howto_table[0]));
00361        i++)
00362     if (xstormy16_elf_howto_table[i].name != NULL
00363        && strcasecmp (xstormy16_elf_howto_table[i].name, r_name) == 0)
00364       return &xstormy16_elf_howto_table[i];
00365 
00366   for (i = 0;
00367        i < (sizeof (xstormy16_elf_howto_table2)
00368            / sizeof (xstormy16_elf_howto_table2[0]));
00369        i++)
00370     if (xstormy16_elf_howto_table2[i].name != NULL
00371        && strcasecmp (xstormy16_elf_howto_table2[i].name, r_name) == 0)
00372       return &xstormy16_elf_howto_table2[i];
00373 
00374   return NULL;
00375 }
00376 
00377 /* Set the howto pointer for an XSTORMY16 ELF reloc.  */
00378 
00379 static void
00380 xstormy16_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED,
00381                            arelent * cache_ptr,
00382                            Elf_Internal_Rela * dst)
00383 {
00384   unsigned int r_type = ELF32_R_TYPE (dst->r_info);
00385 
00386   if (r_type <= (unsigned int) R_XSTORMY16_12)
00387     cache_ptr->howto = &xstormy16_elf_howto_table [r_type];
00388   else if (r_type - R_XSTORMY16_GNU_VTINHERIT
00389           <= (unsigned int) R_XSTORMY16_GNU_VTENTRY)
00390     cache_ptr->howto
00391       = &xstormy16_elf_howto_table2 [r_type - R_XSTORMY16_GNU_VTINHERIT];
00392   else
00393     abort ();
00394 }
00395 
00396 /* We support 16-bit pointers to code above 64k by generating a thunk
00397    below 64k containing a JMPF instruction to the final address.  We
00398    cannot, unfortunately, minimize the number of thunks unless the
00399    -relax switch is given, as otherwise we have no idea where the
00400    sections will fall in the address space.  */
00401 
00402 static bfd_boolean
00403 xstormy16_elf_check_relocs (bfd *abfd,
00404                          struct bfd_link_info *info,
00405                          asection *sec,
00406                          const Elf_Internal_Rela *relocs)
00407 {
00408   const Elf_Internal_Rela *rel, *relend;
00409   struct elf_link_hash_entry **sym_hashes;
00410   Elf_Internal_Shdr *symtab_hdr;
00411   bfd_vma *local_plt_offsets;
00412   asection *splt;
00413   bfd *dynobj;
00414 
00415   if (info->relocatable)
00416     return TRUE;
00417 
00418   symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
00419   sym_hashes = elf_sym_hashes (abfd);
00420   local_plt_offsets = elf_local_got_offsets (abfd);
00421   splt = NULL;
00422   dynobj = elf_hash_table(info)->dynobj;
00423 
00424   relend = relocs + sec->reloc_count;
00425   for (rel = relocs; rel < relend; ++rel)
00426     {
00427       unsigned long r_symndx;
00428       struct elf_link_hash_entry *h;
00429       bfd_vma *offset;
00430 
00431       r_symndx = ELF32_R_SYM (rel->r_info);
00432       if (r_symndx < symtab_hdr->sh_info)
00433        h = NULL;
00434       else
00435        {
00436          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
00437          while (h->root.type == bfd_link_hash_indirect
00438                || h->root.type == bfd_link_hash_warning)
00439            h = (struct elf_link_hash_entry *) h->root.u.i.link;
00440        }
00441 
00442       switch (ELF32_R_TYPE (rel->r_info))
00443         {
00444          /* This relocation describes a 16-bit pointer to a function.
00445             We may need to allocate a thunk in low memory; reserve memory
00446             for it now.  */
00447        case R_XSTORMY16_FPTR16:
00448          if (rel->r_addend != 0)
00449            {
00450              (*info->callbacks->warning)
00451               (info, _("non-zero addend in @fptr reloc"), 0,
00452                abfd, 0, 0);
00453            }
00454 
00455          if (dynobj == NULL)
00456            elf_hash_table (info)->dynobj = dynobj = abfd;
00457          if (splt == NULL)
00458            {
00459              splt = bfd_get_section_by_name (dynobj, ".plt");
00460              if (splt == NULL)
00461               {
00462                 splt = bfd_make_section_with_flags (dynobj, ".plt",
00463                                                 (SEC_ALLOC
00464                                                  | SEC_LOAD
00465                                                  | SEC_HAS_CONTENTS
00466                                                  | SEC_IN_MEMORY
00467                                                  | SEC_LINKER_CREATED
00468                                                  | SEC_READONLY
00469                                                  | SEC_CODE));
00470 
00471                 if (splt == NULL
00472                     || ! bfd_set_section_alignment (dynobj, splt, 1))
00473                   return FALSE;
00474               }
00475            }
00476 
00477          if (h != NULL)
00478            offset = &h->plt.offset;
00479          else
00480            {
00481              if (local_plt_offsets == NULL)
00482               {
00483                 size_t size;
00484                 unsigned int i;
00485 
00486                 size = symtab_hdr->sh_info * sizeof (bfd_vma);
00487                 local_plt_offsets = bfd_alloc (abfd, size);
00488                 if (local_plt_offsets == NULL)
00489                   return FALSE;
00490                 elf_local_got_offsets (abfd) = local_plt_offsets;
00491 
00492                 for (i = 0; i < symtab_hdr->sh_info; i++)
00493                   local_plt_offsets[i] = (bfd_vma) -1;
00494               }
00495              offset = &local_plt_offsets[r_symndx];
00496            }
00497 
00498          if (*offset == (bfd_vma) -1)
00499            {
00500              *offset = splt->size;
00501              splt->size += 4;
00502            }
00503          break;
00504 
00505          /* This relocation describes the C++ object vtable hierarchy.
00506             Reconstruct it for later use during GC.  */
00507         case R_XSTORMY16_GNU_VTINHERIT:
00508           if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
00509             return FALSE;
00510           break;
00511 
00512          /* This relocation describes which C++ vtable entries are actually
00513             used.  Record for later use during GC.  */
00514         case R_XSTORMY16_GNU_VTENTRY:
00515           if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
00516             return FALSE;
00517           break;
00518        }
00519     }
00520 
00521   return TRUE;
00522 }
00523 
00524 /* A subroutine of xstormy16_elf_relax_section.  If the global symbol H
00525    is within the low 64k, remove any entry for it in the plt.  */
00526 
00527 struct relax_plt_data
00528 {
00529   asection *splt;
00530   bfd_boolean *again;
00531 };
00532 
00533 static bfd_boolean
00534 xstormy16_relax_plt_check (struct elf_link_hash_entry *h, void * xdata)
00535 {
00536   struct relax_plt_data *data = (struct relax_plt_data *) xdata;
00537 
00538   if (h->root.type == bfd_link_hash_warning)
00539     h = (struct elf_link_hash_entry *) h->root.u.i.link;
00540 
00541   if (h->plt.offset != (bfd_vma) -1)
00542     {
00543       bfd_vma address;
00544 
00545       if (h->root.type == bfd_link_hash_undefined
00546          || h->root.type == bfd_link_hash_undefweak)
00547        address = 0;
00548       else
00549        address = (h->root.u.def.section->output_section->vma
00550                  + h->root.u.def.section->output_offset
00551                  + h->root.u.def.value);
00552 
00553       if (address <= 0xffff)
00554        {
00555          h->plt.offset = -1;
00556          data->splt->size -= 4;
00557          *data->again = TRUE;
00558        }
00559     }
00560 
00561   return TRUE;
00562 }
00563 
00564 /* A subroutine of xstormy16_elf_relax_section.  If the global symbol H
00565    previously had a plt entry, give it a new entry offset.  */
00566 
00567 static bfd_boolean
00568 xstormy16_relax_plt_realloc (struct elf_link_hash_entry *h, void * xdata)
00569 {
00570   bfd_vma *entry = (bfd_vma *) xdata;
00571 
00572   if (h->root.type == bfd_link_hash_warning)
00573     h = (struct elf_link_hash_entry *) h->root.u.i.link;
00574 
00575   if (h->plt.offset != (bfd_vma) -1)
00576     {
00577       h->plt.offset = *entry;
00578       *entry += 4;
00579     }
00580 
00581   return TRUE;
00582 }
00583 
00584 static bfd_boolean
00585 xstormy16_elf_relax_section (bfd *dynobj,
00586                           asection *splt,
00587                           struct bfd_link_info *info,
00588                           bfd_boolean *again)
00589 {
00590   struct relax_plt_data relax_plt_data;
00591   bfd *ibfd;
00592 
00593   /* Assume nothing changes.  */
00594   *again = FALSE;
00595 
00596   if (info->relocatable)
00597     return TRUE;
00598 
00599   /* We only relax the .plt section at the moment.  */
00600   if (dynobj != elf_hash_table (info)->dynobj
00601       || strcmp (splt->name, ".plt") != 0)
00602     return TRUE;
00603 
00604   /* Quick check for an empty plt.  */
00605   if (splt->size == 0)
00606     return TRUE;
00607 
00608   /* Map across all global symbols; see which ones happen to
00609      fall in the low 64k.  */
00610   relax_plt_data.splt = splt;
00611   relax_plt_data.again = again;
00612   elf_link_hash_traverse (elf_hash_table (info), xstormy16_relax_plt_check,
00613                        &relax_plt_data);
00614 
00615   /* Likewise for local symbols, though that's somewhat less convenient
00616      as we have to walk the list of input bfds and swap in symbol data.  */
00617   for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
00618     {
00619       bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
00620       Elf_Internal_Shdr *symtab_hdr;
00621       Elf_Internal_Sym *isymbuf = NULL;
00622       unsigned int idx;
00623 
00624       if (! local_plt_offsets)
00625        continue;
00626 
00627       symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
00628       if (symtab_hdr->sh_info != 0)
00629        {
00630          isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
00631          if (isymbuf == NULL)
00632            isymbuf = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
00633                                        symtab_hdr->sh_info, 0,
00634                                        NULL, NULL, NULL);
00635          if (isymbuf == NULL)
00636            return FALSE;
00637        }
00638 
00639       for (idx = 0; idx < symtab_hdr->sh_info; ++idx)
00640        {
00641          Elf_Internal_Sym *isym;
00642          asection *tsec;
00643          bfd_vma address;
00644 
00645          if (local_plt_offsets[idx] == (bfd_vma) -1)
00646            continue;
00647 
00648          isym = &isymbuf[idx];
00649          if (isym->st_shndx == SHN_UNDEF)
00650            continue;
00651          else if (isym->st_shndx == SHN_ABS)
00652            tsec = bfd_abs_section_ptr;
00653          else if (isym->st_shndx == SHN_COMMON)
00654            tsec = bfd_com_section_ptr;
00655          else
00656            tsec = bfd_section_from_elf_index (ibfd, isym->st_shndx);
00657 
00658          address = (tsec->output_section->vma
00659                    + tsec->output_offset
00660                    + isym->st_value);
00661          if (address <= 0xffff)
00662            {
00663              local_plt_offsets[idx] = -1;
00664              splt->size -= 4;
00665              *again = TRUE;
00666            }
00667        }
00668 
00669       if (isymbuf != NULL
00670          && symtab_hdr->contents != (unsigned char *) isymbuf)
00671        {
00672          if (! info->keep_memory)
00673            free (isymbuf);
00674          else
00675            {
00676              /* Cache the symbols for elf_link_input_bfd.  */
00677              symtab_hdr->contents = (unsigned char *) isymbuf;
00678            }
00679        }
00680     }
00681 
00682   /* If we changed anything, walk the symbols again to reallocate
00683      .plt entry addresses.  */
00684   if (*again && splt->size > 0)
00685     {
00686       bfd_vma entry = 0;
00687 
00688       elf_link_hash_traverse (elf_hash_table (info),
00689                            xstormy16_relax_plt_realloc, &entry);
00690 
00691       for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
00692        {
00693          bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
00694          unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info;
00695          unsigned int idx;
00696 
00697          if (! local_plt_offsets)
00698            continue;
00699 
00700          for (idx = 0; idx < nlocals; ++idx)
00701            if (local_plt_offsets[idx] != (bfd_vma) -1)
00702              {
00703                local_plt_offsets[idx] = entry;
00704               entry += 4;
00705              }
00706        }
00707     }
00708 
00709   return TRUE;
00710 }
00711 
00712 static bfd_boolean
00713 xstormy16_elf_always_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
00714                                 struct bfd_link_info *info)
00715 {
00716   bfd *dynobj;
00717   asection *splt;
00718 
00719   if (info->relocatable)
00720     return TRUE;
00721 
00722   dynobj = elf_hash_table (info)->dynobj;
00723   if (dynobj == NULL)
00724     return TRUE;
00725 
00726   splt = bfd_get_section_by_name (dynobj, ".plt");
00727   BFD_ASSERT (splt != NULL);
00728 
00729   splt->contents = bfd_zalloc (dynobj, splt->size);
00730   if (splt->contents == NULL)
00731     return FALSE;
00732 
00733   return TRUE;
00734 }
00735 
00736 /* Relocate an XSTORMY16 ELF section.
00737 
00738    The RELOCATE_SECTION function is called by the new ELF backend linker
00739    to handle the relocations for a section.
00740 
00741    The relocs are always passed as Rela structures; if the section
00742    actually uses Rel structures, the r_addend field will always be
00743    zero.
00744 
00745    This function is responsible for adjusting the section contents as
00746    necessary, and (if using Rela relocs and generating a relocatable
00747    output file) adjusting the reloc addend as necessary.
00748 
00749    This function does not have to worry about setting the reloc
00750    address or the reloc symbol index.
00751 
00752    LOCAL_SYMS is a pointer to the swapped in local symbols.
00753 
00754    LOCAL_SECTIONS is an array giving the section in the input file
00755    corresponding to the st_shndx field of each local symbol.
00756 
00757    The global hash table entry for the global symbols can be found
00758    via elf_sym_hashes (input_bfd).
00759 
00760    When generating relocatable output, this function must handle
00761    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
00762    going to be the section symbol corresponding to the output
00763    section, which means that the addend must be adjusted
00764    accordingly.  */
00765 
00766 static bfd_boolean
00767 xstormy16_elf_relocate_section (bfd *                   output_bfd ATTRIBUTE_UNUSED,
00768                             struct bfd_link_info *  info,
00769                             bfd *                   input_bfd,
00770                             asection *              input_section,
00771                             bfd_byte *              contents,
00772                             Elf_Internal_Rela *     relocs,
00773                             Elf_Internal_Sym *      local_syms,
00774                             asection **             local_sections)
00775 {
00776   Elf_Internal_Shdr *           symtab_hdr;
00777   struct elf_link_hash_entry ** sym_hashes;
00778   Elf_Internal_Rela *           rel;
00779   Elf_Internal_Rela *           relend;
00780   bfd *dynobj;
00781   asection *splt;
00782 
00783   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
00784   sym_hashes = elf_sym_hashes (input_bfd);
00785   relend     = relocs + input_section->reloc_count;
00786 
00787   dynobj = elf_hash_table (info)->dynobj;
00788   splt = NULL;
00789   if (dynobj != NULL)
00790     splt = bfd_get_section_by_name (dynobj, ".plt");
00791 
00792   for (rel = relocs; rel < relend; rel ++)
00793     {
00794       reloc_howto_type *           howto;
00795       unsigned long                r_symndx;
00796       Elf_Internal_Sym *           sym;
00797       asection *                   sec;
00798       struct elf_link_hash_entry * h;
00799       bfd_vma                      relocation;
00800       bfd_reloc_status_type        r;
00801       const char *                 name = NULL;
00802       int                          r_type;
00803 
00804       r_type = ELF32_R_TYPE (rel->r_info);
00805 
00806       if (   r_type == R_XSTORMY16_GNU_VTINHERIT
00807          || r_type == R_XSTORMY16_GNU_VTENTRY)
00808        continue;
00809 
00810       r_symndx = ELF32_R_SYM (rel->r_info);
00811       howto  = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info);
00812       h      = NULL;
00813       sym    = NULL;
00814       sec    = NULL;
00815 
00816       if (r_symndx < symtab_hdr->sh_info)
00817        {
00818          sym = local_syms + r_symndx;
00819          sec = local_sections [r_symndx];
00820          relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
00821        }
00822       else
00823        {
00824          bfd_boolean unresolved_reloc, warned;
00825 
00826          RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
00827                                r_symndx, symtab_hdr, sym_hashes,
00828                                h, sec, relocation,
00829                                unresolved_reloc, warned);
00830        }
00831 
00832       if (sec != NULL && elf_discarded_section (sec))
00833        {
00834          /* For relocs against symbols from removed linkonce sections,
00835             or sections discarded by a linker script, we just want the
00836             section contents zeroed.  Avoid any special processing.  */
00837          _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
00838          rel->r_info = 0;
00839          rel->r_addend = 0;
00840          continue;
00841        }
00842 
00843       if (info->relocatable)
00844        continue;
00845 
00846       if (h != NULL)
00847        name = h->root.root.string;
00848       else
00849        {
00850          name = (bfd_elf_string_from_elf_section
00851                 (input_bfd, symtab_hdr->sh_link, sym->st_name));
00852          if (name == NULL || *name == '\0')
00853            name = bfd_section_name (input_bfd, sec);
00854        }
00855 
00856       switch (ELF32_R_TYPE (rel->r_info))
00857        {
00858        case R_XSTORMY16_24:
00859          {
00860            bfd_vma reloc = relocation + rel->r_addend;
00861            unsigned int x;
00862 
00863            x = bfd_get_32 (input_bfd, contents + rel->r_offset);
00864            x &= 0x0000ff00;
00865            x |= reloc & 0xff;
00866            x |= (reloc << 8) & 0xffff0000;
00867            bfd_put_32 (input_bfd, x, contents + rel->r_offset);
00868 
00869            if (reloc & ~0xffffff)
00870              r = bfd_reloc_overflow;
00871            else
00872              r = bfd_reloc_ok;
00873            break;
00874          }
00875 
00876        case R_XSTORMY16_FPTR16:
00877          {
00878            bfd_vma *plt_offset;
00879 
00880            if (h != NULL)
00881              plt_offset = &h->plt.offset;
00882            else
00883              plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
00884 
00885            if (relocation <= 0xffff)
00886              {
00887                /* If the symbol is in range for a 16-bit address, we should
00888                  have deallocated the plt entry in relax_section.  */
00889                BFD_ASSERT (*plt_offset == (bfd_vma) -1);
00890              }
00891            else
00892              {
00893               /* If the symbol is out of range for a 16-bit address,
00894                  we must have allocated a plt entry.  */
00895               BFD_ASSERT (*plt_offset != (bfd_vma) -1);
00896 
00897               /* If this is the first time we've processed this symbol,
00898                  fill in the plt entry with the correct symbol address.  */
00899               if ((*plt_offset & 1) == 0)
00900                 {
00901                   unsigned int x;
00902 
00903                   x = 0x00000200;  /* jmpf */
00904                   x |= relocation & 0xff;
00905                   x |= (relocation << 8) & 0xffff0000;
00906                   bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
00907                   *plt_offset |= 1;
00908                 }
00909 
00910               relocation = (splt->output_section->vma
00911                            + splt->output_offset
00912                            + (*plt_offset & -2));
00913              }
00914            r = _bfd_final_link_relocate (howto, input_bfd, input_section,
00915                                      contents, rel->r_offset,
00916                                      relocation, 0);
00917            break;
00918          }
00919 
00920        default:
00921          r = _bfd_final_link_relocate (howto, input_bfd, input_section,
00922                                    contents, rel->r_offset,
00923                                    relocation, rel->r_addend);
00924          break;
00925        }
00926 
00927       if (r != bfd_reloc_ok)
00928        {
00929          const char * msg = NULL;
00930 
00931          switch (r)
00932            {
00933            case bfd_reloc_overflow:
00934              r = info->callbacks->reloc_overflow
00935               (info, (h ? &h->root : NULL), name, howto->name,
00936                (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
00937              break;
00938 
00939            case bfd_reloc_undefined:
00940              r = info->callbacks->undefined_symbol
00941               (info, name, input_bfd, input_section, rel->r_offset,
00942                TRUE);
00943              break;
00944 
00945            case bfd_reloc_outofrange:
00946              msg = _("internal error: out of range error");
00947              break;
00948 
00949            case bfd_reloc_notsupported:
00950              msg = _("internal error: unsupported relocation error");
00951              break;
00952 
00953            case bfd_reloc_dangerous:
00954              msg = _("internal error: dangerous relocation");
00955              break;
00956 
00957            default:
00958              msg = _("internal error: unknown error");
00959              break;
00960            }
00961 
00962          if (msg)
00963            r = info->callbacks->warning
00964              (info, msg, name, input_bfd, input_section, rel->r_offset);
00965 
00966          if (! r)
00967            return FALSE;
00968        }
00969     }
00970 
00971   return TRUE;
00972 }
00973 
00974 /* This must exist if dynobj is ever set.  */
00975 
00976 static bfd_boolean
00977 xstormy16_elf_finish_dynamic_sections (bfd *abfd ATTRIBUTE_UNUSED,
00978                                    struct bfd_link_info *info)
00979 {
00980   bfd *dynobj;
00981   asection *splt;
00982 
00983   /* As an extra sanity check, verify that all plt entries have
00984      been filled in.  */
00985 
00986   if ((dynobj = elf_hash_table (info)->dynobj) != NULL
00987       && (splt = bfd_get_section_by_name (dynobj, ".plt")) != NULL)
00988     {
00989       bfd_byte *contents = splt->contents;
00990       unsigned int i, size = splt->size;
00991 
00992       for (i = 0; i < size; i += 4)
00993        {
00994          unsigned int x = bfd_get_32 (dynobj, contents + i);
00995 
00996          BFD_ASSERT (x != 0);
00997        }
00998     }
00999 
01000   return TRUE;
01001 }
01002 
01003 /* Return the section that should be marked against GC for a given
01004    relocation.  */
01005 
01006 static asection *
01007 xstormy16_elf_gc_mark_hook (asection *sec,
01008                          struct bfd_link_info *info,
01009                          Elf_Internal_Rela *rel,
01010                          struct elf_link_hash_entry *h,
01011                          Elf_Internal_Sym *sym)
01012 {
01013   if (h != NULL)
01014     switch (ELF32_R_TYPE (rel->r_info))
01015       {
01016       case R_XSTORMY16_GNU_VTINHERIT:
01017       case R_XSTORMY16_GNU_VTENTRY:
01018        return NULL;
01019       }
01020 
01021   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
01022 }
01023 
01024 #define ELF_ARCH            bfd_arch_xstormy16
01025 #define ELF_MACHINE_CODE    EM_XSTORMY16
01026 #define ELF_MAXPAGESIZE            0x100
01027 
01028 #define TARGET_LITTLE_SYM       bfd_elf32_xstormy16_vec
01029 #define TARGET_LITTLE_NAME  "elf32-xstormy16"
01030 
01031 #define elf_info_to_howto_rel                    NULL
01032 #define elf_info_to_howto                 xstormy16_info_to_howto_rela
01033 #define elf_backend_relocate_section             xstormy16_elf_relocate_section
01034 #define elf_backend_gc_mark_hook          xstormy16_elf_gc_mark_hook
01035 #define elf_backend_check_relocs                xstormy16_elf_check_relocs
01036 #define elf_backend_always_size_sections \
01037   xstormy16_elf_always_size_sections
01038 #define elf_backend_omit_section_dynsym \
01039   ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
01040 #define elf_backend_finish_dynamic_sections \
01041   xstormy16_elf_finish_dynamic_sections
01042 
01043 #define elf_backend_can_gc_sections              1
01044 #define elf_backend_rela_normal                  1
01045 
01046 #define bfd_elf32_bfd_reloc_type_lookup          xstormy16_reloc_type_lookup
01047 #define bfd_elf32_bfd_reloc_name_lookup \
01048   xstormy16_reloc_name_lookup
01049 #define bfd_elf32_bfd_relax_section              xstormy16_elf_relax_section
01050 
01051 #include "elf32-target.h"