Back to index

cell-binutils  2.17cvs20070401
coff-w65.c
Go to the documentation of this file.
00001 /* BFD back-end for WDC 65816 COFF binaries.
00002    Copyright 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
00003    2006 Free Software Foundation, Inc.
00004    Written by Steve Chamberlain, <sac@cygnus.com>.
00005 
00006 This file is part of BFD, the Binary File Descriptor library.
00007 
00008 This program is free software; you can redistribute it and/or modify
00009 it under the terms of the GNU General Public License as published by
00010 the Free Software Foundation; either version 2 of the License, or
00011 (at your option) any later version.
00012 
00013 This program is distributed in the hope that it will be useful,
00014 but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 GNU General Public License for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with this program; if not, write to the Free Software
00020 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00021 
00022 #include "bfd.h"
00023 #include "sysdep.h"
00024 #include "libbfd.h"
00025 #include "bfdlink.h"
00026 #include "coff/w65.h"
00027 #include "coff/internal.h"
00028 #include "libcoff.h"
00029 
00030 static int  select_reloc              PARAMS ((reloc_howto_type *));
00031 static void rtype2howto               PARAMS ((arelent *, struct internal_reloc *));
00032 static void reloc_processing          PARAMS ((arelent *, struct internal_reloc *, asymbol **, bfd *, asection *));
00033 static int  w65_reloc16_estimate    PARAMS ((bfd *, asection *, arelent *, unsigned int, struct bfd_link_info *));
00034 static void w65_reloc16_extra_cases PARAMS ((bfd *,struct bfd_link_info *, struct bfd_link_order *, arelent *, bfd_byte *, unsigned int *, unsigned int *));
00035 
00036 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (1)
00037 static reloc_howto_type howto_table[] =
00038   {
00039     HOWTO (R_W65_ABS8,    0,  0, 8,  FALSE, 0, complain_overflow_bitfield, 0, "abs8", TRUE, 0x000000ff, 0x000000ff, FALSE),
00040     HOWTO (R_W65_ABS16,   1,  0, 16, FALSE, 0, complain_overflow_bitfield, 0, "abs16", TRUE, 0x0000ffff, 0x0000ffff, FALSE),
00041     HOWTO (R_W65_ABS24,   0,  2, 32, FALSE, 0, complain_overflow_bitfield, 0, "abs24", TRUE, 0x00ffffff, 0x00ffffff, FALSE),
00042     HOWTO (R_W65_ABS8S8,  0,  0, 8,  FALSE, 0, complain_overflow_bitfield, 0, ">abs8", TRUE, 0x000000ff, 0x000000ff, FALSE),
00043     HOWTO (R_W65_ABS8S16, 0,  0, 8,  FALSE, 0, complain_overflow_bitfield, 0, "^abs8", TRUE, 0x000000ff, 0x000000ff, FALSE),
00044     HOWTO (R_W65_ABS16S8, 1,  0, 16, FALSE, 0, complain_overflow_bitfield, 0, ">abs16", TRUE, 0x0000ffff, 0x0000ffff, FALSE),
00045     HOWTO (R_W65_ABS16S16,1,  0, 16, FALSE, 0, complain_overflow_bitfield, 0, "^abs16", TRUE, 0x0000ffff, 0x0000ffff, FALSE),
00046     HOWTO (R_W65_PCR8,    0,  0, 8,  FALSE, 0, complain_overflow_bitfield, 0, "pcrel8", TRUE, 0x000000ff, 0x000000ff, TRUE),
00047     HOWTO (R_W65_PCR16,   1,  0, 16, FALSE, 0, complain_overflow_bitfield, 0, "pcrel16", TRUE, 0x0000ffff, 0x0000ffff, TRUE),
00048     HOWTO (R_W65_DP,      0,  0, 8,  FALSE, 0, complain_overflow_bitfield, 0, "dp", TRUE, 0x000000ff, 0x000000ff, FALSE),
00049   };
00050 
00051 /* Turn a howto into a reloc number.  */
00052 
00053 #define SELECT_RELOC(x,howto) \
00054   { x.r_type = select_reloc(howto); }
00055 
00056 #define BADMAG(x) (W65BADMAG(x))
00057 #define W65 1               /* Customize coffcode.h */
00058 #define __A_MAGIC_SET__
00059 
00060 /* Code to swap in the reloc */
00061 #define SWAP_IN_RELOC_OFFSET       H_GET_32
00062 #define SWAP_OUT_RELOC_OFFSET      H_PUT_32
00063 #define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \
00064   dst->r_stuff[0] = 'S'; \
00065   dst->r_stuff[1] = 'C';
00066 
00067 static int
00068 select_reloc (howto)
00069      reloc_howto_type *howto;
00070 {
00071   return howto->type ;
00072 }
00073 
00074 /* Code to turn a r_type into a howto ptr, uses the above howto table.  */
00075 
00076 static void
00077 rtype2howto (internal, dst)
00078      arelent *internal;
00079      struct internal_reloc *dst;
00080 {
00081   internal->howto = howto_table + dst->r_type - 1;
00082 }
00083 
00084 #define RTYPE2HOWTO(internal, relocentry) rtype2howto(internal,relocentry)
00085 
00086 /* Perform any necessary magic to the addend in a reloc entry.  */
00087 
00088 #define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \
00089  cache_ptr->addend =  ext_reloc.r_offset;
00090 
00091 #define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \
00092  reloc_processing(relent, reloc, symbols, abfd, section)
00093 
00094 static void
00095 reloc_processing (relent, reloc, symbols, abfd, section)
00096      arelent * relent;
00097      struct internal_reloc *reloc;
00098      asymbol ** symbols;
00099      bfd * abfd;
00100      asection * section;
00101 {
00102   relent->address = reloc->r_vaddr;
00103   rtype2howto (relent, reloc);
00104 
00105   if (((int) reloc->r_symndx) > 0)
00106     relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx];
00107   else
00108     relent->sym_ptr_ptr = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr;
00109 
00110   relent->addend = reloc->r_offset;
00111 
00112   relent->address -= section->vma;
00113   /*  relent->section = 0;*/
00114 }
00115 
00116 static int
00117 w65_reloc16_estimate (abfd, input_section, reloc, shrink, link_info)
00118      bfd *abfd;
00119      asection *input_section;
00120      arelent *reloc;
00121      unsigned int shrink;
00122      struct bfd_link_info *link_info;
00123 {
00124   bfd_vma value;
00125   bfd_vma dot;
00126   bfd_vma gap;
00127 
00128   /* The address of the thing to be relocated will have moved back by
00129    the size of the shrink  - but we don't change reloc->address here,
00130    since we need it to know where the relocation lives in the source
00131    uncooked section.  */
00132 
00133   /*  reloc->address -= shrink;   conceptual */
00134 
00135   bfd_vma address = reloc->address - shrink;
00136 
00137   switch (reloc->howto->type)
00138     {
00139     case R_MOV16B2:
00140     case R_JMP2:
00141       shrink+=2;
00142       break;
00143 
00144       /* Thing is a move one byte.  */
00145     case R_MOV16B1:
00146       value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
00147 
00148       if (value >= 0xff00)
00149        {
00150          /* Change the reloc type from 16bit, possible 8 to 8bit
00151             possible 16.  */
00152          reloc->howto = reloc->howto + 1;
00153          /* The place to relc moves back by one.  */
00154          /* This will be two bytes smaller in the long run.  */
00155          shrink += 2;
00156          bfd_perform_slip (abfd, 2, input_section, address);
00157        }
00158 
00159       break;
00160       /* This is the 24 bit branch which could become an 8 bitter,
00161         the relocation points to the first byte of the insn, not the
00162         actual data.  */
00163 
00164     case R_JMPL1:
00165       value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
00166 
00167       dot = input_section->output_section->vma +
00168        input_section->output_offset + address;
00169 
00170       /* See if the address we're looking at within 127 bytes of where
00171         we are, if so then we can use a small branch rather than the
00172         jump we were going to.  */
00173       gap = value - dot;
00174 
00175       if (-120 < (long) gap && (long) gap < 120)
00176        {
00177          /* Change the reloc type from 24bit, possible 8 to 8bit
00178             possible 32.  */
00179          reloc->howto = reloc->howto + 1;
00180          /* This will be two bytes smaller in the long run.  */
00181          shrink += 2;
00182          bfd_perform_slip (abfd, 2, input_section, address);
00183        }
00184       break;
00185 
00186     case R_JMP1:
00187       value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
00188 
00189       dot = input_section->output_section->vma +
00190        input_section->output_offset + address;
00191 
00192       /* See if the address we're looking at within 127 bytes of where
00193         we are, if so then we can use a small branch rather than the
00194         jump we were going to.  */
00195       gap = value - (dot - shrink);
00196 
00197       if (-120 < (long) gap && (long) gap < 120)
00198        {
00199          /* Change the reloc type from 16bit, possible 8 to 8bit
00200             possible 16.  */
00201          reloc->howto = reloc->howto + 1;
00202          /* The place to relc moves back by one.  */
00203 
00204          /* This will be two bytes smaller in the long run.  */
00205          shrink += 2;
00206          bfd_perform_slip (abfd, 2, input_section, address);
00207        }
00208       break;
00209     }
00210 
00211   return shrink;
00212 }
00213 
00214 /* First phase of a relaxing link.  */
00215 
00216 /* Reloc types
00217    large             small
00218    R_MOV16B1         R_MOV16B2     mov.b with 16bit or 8 bit address
00219    R_JMP1            R_JMP2        jmp or pcrel branch
00220    R_JMPL1           R_JMPL_B8     24jmp or pcrel branch
00221    R_MOV24B1         R_MOV24B2     24 or 8 bit reloc for mov.b  */
00222 
00223 static void
00224 w65_reloc16_extra_cases (abfd, link_info, link_order, reloc, data, src_ptr,
00225                         dst_ptr)
00226      bfd *abfd;
00227      struct bfd_link_info *link_info;
00228      struct bfd_link_order *link_order;
00229      arelent *reloc;
00230      bfd_byte *data;
00231      unsigned int *src_ptr;
00232      unsigned int *dst_ptr;
00233 {
00234   unsigned int src_address = *src_ptr;
00235   unsigned int dst_address = *dst_ptr;
00236   asection *input_section = link_order->u.indirect.section;
00237 
00238   switch (reloc->howto->type)
00239     {
00240     case R_W65_ABS8:
00241     case R_W65_DP:
00242       {
00243        unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info,
00244                                                  input_section);
00245        bfd_put_8 (abfd, gap, data + dst_address);
00246        dst_address += 1;
00247        src_address += 1;
00248       }
00249       break;
00250 
00251     case R_W65_ABS8S8:
00252       {
00253        unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info,
00254                                                  input_section);
00255        gap >>= 8;
00256        bfd_put_8 (abfd, gap, data + dst_address);
00257        dst_address += 1;
00258        src_address += 1;
00259       }
00260       break;
00261 
00262     case R_W65_ABS8S16:
00263       {
00264        unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info,
00265                                                  input_section);
00266        gap >>= 16;
00267        bfd_put_8 (abfd, gap, data + dst_address);
00268        dst_address += 1;
00269        src_address += 1;
00270       }
00271       break;
00272 
00273     case R_W65_ABS16:
00274       {
00275        unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info,
00276                                                  input_section);
00277 
00278        bfd_put_16 (abfd, (bfd_vma) gap, data + dst_address);
00279        dst_address += 2;
00280        src_address += 2;
00281       }
00282       break;
00283     case R_W65_ABS16S8:
00284       {
00285        unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info,
00286                                                  input_section);
00287        gap >>= 8;
00288        bfd_put_16 (abfd, (bfd_vma) gap, data + dst_address);
00289        dst_address += 2;
00290        src_address += 2;
00291       }
00292       break;
00293     case R_W65_ABS16S16:
00294       {
00295        unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info,
00296                                                  input_section);
00297        gap >>= 16;
00298        bfd_put_16 (abfd, (bfd_vma) gap, data + dst_address);
00299        dst_address += 2;
00300        src_address += 2;
00301       }
00302       break;
00303 
00304     case R_W65_ABS24:
00305       {
00306        unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info,
00307                                                  input_section);
00308        bfd_put_16 (abfd, (bfd_vma) gap, data + dst_address);
00309        bfd_put_8 (abfd, gap >> 16, data+dst_address + 2);
00310        dst_address += 3;
00311        src_address += 3;
00312       }
00313       break;
00314 
00315     case R_W65_PCR8:
00316       {
00317        int gap = bfd_coff_reloc16_get_value (reloc, link_info,
00318                                          input_section);
00319        bfd_vma dot = (dst_address
00320                      + input_section->output_offset
00321                      + input_section->output_section->vma);
00322 
00323        gap -= dot + 1;
00324        if (gap < -128 || gap > 127)
00325          {
00326            if (! ((*link_info->callbacks->reloc_overflow)
00327                  (link_info, NULL,
00328                   bfd_asymbol_name (*reloc->sym_ptr_ptr),
00329                   reloc->howto->name, reloc->addend, input_section->owner,
00330                   input_section, reloc->address)))
00331              abort ();
00332          }
00333        bfd_put_8 (abfd, gap, data + dst_address);
00334        dst_address += 1;
00335        src_address += 1;
00336       }
00337       break;
00338 
00339     case R_W65_PCR16:
00340       {
00341        bfd_vma gap = bfd_coff_reloc16_get_value (reloc, link_info,
00342                                             input_section);
00343        bfd_vma dot = (dst_address
00344                      + input_section->output_offset
00345                      + input_section->output_section->vma);
00346 
00347        /* This wraps within the page, so ignore the relativeness, look at the
00348           high part.  */
00349        if ((gap & 0xf0000) != (dot & 0xf0000))
00350          {
00351            if (! ((*link_info->callbacks->reloc_overflow)
00352                  (link_info, NULL,
00353                   bfd_asymbol_name (*reloc->sym_ptr_ptr),
00354                   reloc->howto->name, reloc->addend, input_section->owner,
00355                   input_section, reloc->address)))
00356              abort ();
00357          }
00358 
00359        gap -= dot + 2;
00360        bfd_put_16 (abfd, gap, data + dst_address);
00361        dst_address += 2;
00362        src_address += 2;
00363       }
00364       break;
00365     default:
00366       printf (_("ignoring reloc %s\n"), reloc->howto->name);
00367       break;
00368 
00369     }
00370   *src_ptr = src_address;
00371   *dst_ptr = dst_address;
00372 }
00373 
00374 #define coff_reloc16_extra_cases w65_reloc16_extra_cases
00375 #define coff_reloc16_estimate w65_reloc16_estimate
00376 
00377 #include "coffcode.h"
00378 
00379 #undef coff_bfd_get_relocated_section_contents
00380 #undef coff_bfd_relax_section
00381 #define coff_bfd_get_relocated_section_contents \
00382   bfd_coff_reloc16_get_relocated_section_contents
00383 #define coff_bfd_relax_section bfd_coff_reloc16_relax_section
00384 
00385 CREATE_LITTLE_COFF_TARGET_VEC (w65_vec, "coff-w65", BFD_IS_RELAXABLE, 0, '_', NULL, COFF_SWAP_TABLE)