Home | History | Annotate | Download | only in bfd
      1 /* BFD back-end for WDC 65816 COFF binaries.
      2    Copyright (C) 1995-2014 Free Software Foundation, Inc.
      3    Written by Steve Chamberlain, <sac (at) cygnus.com>.
      4 
      5    This file is part of BFD, the Binary File Descriptor library.
      6 
      7    This program is free software; you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3 of the License, or
     10    (at your option) any later version.
     11 
     12    This program is distributed in the hope that it will be useful,
     13    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15    GNU General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with this program; if not, write to the Free Software
     19    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     20    MA 02110-1301, USA.  */
     21 
     22 #include "sysdep.h"
     23 #include "bfd.h"
     24 #include "libbfd.h"
     25 #include "bfdlink.h"
     26 #include "coff/w65.h"
     27 #include "coff/internal.h"
     28 #include "libcoff.h"
     29 
     30 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (1)
     31 static reloc_howto_type howto_table[] =
     32 {
     33   HOWTO (R_W65_ABS8,    0,  0, 8,  FALSE, 0, complain_overflow_bitfield, 0, "abs8", TRUE, 0x000000ff, 0x000000ff, FALSE),
     34     HOWTO (R_W65_ABS16,   1,  0, 16, FALSE, 0, complain_overflow_bitfield, 0, "abs16", TRUE, 0x0000ffff, 0x0000ffff, FALSE),
     35     HOWTO (R_W65_ABS24,   0,  2, 32, FALSE, 0, complain_overflow_bitfield, 0, "abs24", TRUE, 0x00ffffff, 0x00ffffff, FALSE),
     36     HOWTO (R_W65_ABS8S8,  0,  0, 8,  FALSE, 0, complain_overflow_bitfield, 0, ">abs8", TRUE, 0x000000ff, 0x000000ff, FALSE),
     37     HOWTO (R_W65_ABS8S16, 0,  0, 8,  FALSE, 0, complain_overflow_bitfield, 0, "^abs8", TRUE, 0x000000ff, 0x000000ff, FALSE),
     38     HOWTO (R_W65_ABS16S8, 1,  0, 16, FALSE, 0, complain_overflow_bitfield, 0, ">abs16", TRUE, 0x0000ffff, 0x0000ffff, FALSE),
     39     HOWTO (R_W65_ABS16S16,1,  0, 16, FALSE, 0, complain_overflow_bitfield, 0, "^abs16", TRUE, 0x0000ffff, 0x0000ffff, FALSE),
     40     HOWTO (R_W65_PCR8,    0,  0, 8,  FALSE, 0, complain_overflow_bitfield, 0, "pcrel8", TRUE, 0x000000ff, 0x000000ff, TRUE),
     41     HOWTO (R_W65_PCR16,   1,  0, 16, FALSE, 0, complain_overflow_bitfield, 0, "pcrel16", TRUE, 0x0000ffff, 0x0000ffff, TRUE),
     42     HOWTO (R_W65_DP,      0,  0, 8,  FALSE, 0, complain_overflow_bitfield, 0, "dp", TRUE, 0x000000ff, 0x000000ff, FALSE),
     43   };
     44 
     45 /* Turn a howto into a reloc number.  */
     46 
     47 #define SELECT_RELOC(x,howto) \
     48   { x.r_type = select_reloc(howto); }
     49 
     50 #define BADMAG(x) (W65BADMAG(x))
     51 #define W65 1			/* Customize coffcode.h */
     52 #define __A_MAGIC_SET__
     53 
     54 /* Code to swap in the reloc */
     55 #define SWAP_IN_RELOC_OFFSET	H_GET_32
     56 #define SWAP_OUT_RELOC_OFFSET	H_PUT_32
     57 #define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \
     58   dst->r_stuff[0] = 'S'; \
     59   dst->r_stuff[1] = 'C';
     60 
     61 static int
     62 select_reloc (reloc_howto_type *howto)
     63 {
     64   return howto->type ;
     65 }
     66 
     67 /* Code to turn a r_type into a howto ptr, uses the above howto table.  */
     68 
     69 static void
     70 rtype2howto (arelent *internal,
     71 	     struct internal_reloc *dst)
     72 {
     73   internal->howto = howto_table + dst->r_type - 1;
     74 }
     75 
     76 #define RTYPE2HOWTO(internal, relocentry) rtype2howto(internal,relocentry)
     77 
     78 /* Perform any necessary magic to the addend in a reloc entry.  */
     79 
     80 #define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \
     81  cache_ptr->addend =  ext_reloc.r_offset;
     82 
     83 #define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \
     84  reloc_processing(relent, reloc, symbols, abfd, section)
     85 
     86 static void
     87 reloc_processing (arelent * relent,
     88 		  struct internal_reloc *reloc,
     89 		  asymbol ** symbols,
     90 		  bfd * abfd,
     91 		  asection * section)
     92 {
     93   relent->address = reloc->r_vaddr;
     94   rtype2howto (relent, reloc);
     95 
     96   if (((int) reloc->r_symndx) > 0)
     97     relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx];
     98   else
     99     relent->sym_ptr_ptr = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr;
    100 
    101   relent->addend = reloc->r_offset;
    102 
    103   relent->address -= section->vma;
    104   /*  relent->section = 0;*/
    105 }
    106 
    107 static int
    108 w65_reloc16_estimate (bfd *abfd,
    109 		      asection *input_section,
    110 		      arelent *reloc,
    111 		      unsigned int shrink,
    112 		      struct bfd_link_info *link_info)
    113 {
    114   bfd_vma value;
    115   bfd_vma dot;
    116   bfd_vma gap;
    117 
    118   /* The address of the thing to be relocated will have moved back by
    119      the size of the shrink  - but we don't change reloc->address here,
    120      since we need it to know where the relocation lives in the source
    121      uncooked section.  */
    122 
    123   /*  reloc->address -= shrink;   conceptual */
    124 
    125   bfd_vma address = reloc->address - shrink;
    126 
    127   switch (reloc->howto->type)
    128     {
    129     case R_MOV16B2:
    130     case R_JMP2:
    131       shrink+=2;
    132       break;
    133 
    134       /* Thing is a move one byte.  */
    135     case R_MOV16B1:
    136       value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
    137 
    138       if (value >= 0xff00)
    139 	{
    140 	  /* Change the reloc type from 16bit, possible 8 to 8bit
    141 	     possible 16.  */
    142 	  reloc->howto = reloc->howto + 1;
    143 	  /* The place to relc moves back by one.  */
    144 	  /* This will be two bytes smaller in the long run.  */
    145 	  shrink += 2;
    146 	  bfd_perform_slip (abfd, 2, input_section, address);
    147 	}
    148 
    149       break;
    150       /* This is the 24 bit branch which could become an 8 bitter,
    151 	 the relocation points to the first byte of the insn, not the
    152 	 actual data.  */
    153 
    154     case R_JMPL1:
    155       value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
    156 
    157       dot = input_section->output_section->vma +
    158 	input_section->output_offset + address;
    159 
    160       /* See if the address we're looking at within 127 bytes of where
    161 	 we are, if so then we can use a small branch rather than the
    162 	 jump we were going to.  */
    163       gap = value - dot;
    164 
    165       if (-120 < (long) gap && (long) gap < 120)
    166 	{
    167 	  /* Change the reloc type from 24bit, possible 8 to 8bit
    168 	     possible 32.  */
    169 	  reloc->howto = reloc->howto + 1;
    170 	  /* This will be two bytes smaller in the long run.  */
    171 	  shrink += 2;
    172 	  bfd_perform_slip (abfd, 2, input_section, address);
    173 	}
    174       break;
    175 
    176     case R_JMP1:
    177       value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
    178 
    179       dot = input_section->output_section->vma +
    180 	input_section->output_offset + address;
    181 
    182       /* See if the address we're looking at within 127 bytes of where
    183 	 we are, if so then we can use a small branch rather than the
    184 	 jump we were going to.  */
    185       gap = value - (dot - shrink);
    186 
    187       if (-120 < (long) gap && (long) gap < 120)
    188 	{
    189 	  /* Change the reloc type from 16bit, possible 8 to 8bit
    190 	     possible 16.  */
    191 	  reloc->howto = reloc->howto + 1;
    192 	  /* The place to relc moves back by one.  */
    193 
    194 	  /* This will be two bytes smaller in the long run.  */
    195 	  shrink += 2;
    196 	  bfd_perform_slip (abfd, 2, input_section, address);
    197 	}
    198       break;
    199     }
    200 
    201   return shrink;
    202 }
    203 
    204 /* First phase of a relaxing link.  */
    205 
    206 /* Reloc types
    207    large		small
    208    R_MOV16B1		R_MOV16B2	mov.b with 16bit or 8 bit address
    209    R_JMP1		R_JMP2		jmp or pcrel branch
    210    R_JMPL1		R_JMPL_B8	24jmp or pcrel branch
    211    R_MOV24B1		R_MOV24B2	24 or 8 bit reloc for mov.b  */
    212 
    213 static void
    214 w65_reloc16_extra_cases (bfd *abfd,
    215 			 struct bfd_link_info *link_info,
    216 			 struct bfd_link_order *link_order,
    217 			 arelent *reloc,
    218 			 bfd_byte *data,
    219 			 unsigned int *src_ptr,
    220 			 unsigned int *dst_ptr)
    221 {
    222   unsigned int src_address = *src_ptr;
    223   unsigned int dst_address = *dst_ptr;
    224   asection *input_section = link_order->u.indirect.section;
    225 
    226   switch (reloc->howto->type)
    227     {
    228     case R_W65_ABS8:
    229     case R_W65_DP:
    230       {
    231 	unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info,
    232 						       input_section);
    233 	bfd_put_8 (abfd, gap, data + dst_address);
    234 	dst_address += 1;
    235 	src_address += 1;
    236       }
    237       break;
    238 
    239     case R_W65_ABS8S8:
    240       {
    241 	unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info,
    242 						       input_section);
    243 	gap >>= 8;
    244 	bfd_put_8 (abfd, gap, data + dst_address);
    245 	dst_address += 1;
    246 	src_address += 1;
    247       }
    248       break;
    249 
    250     case R_W65_ABS8S16:
    251       {
    252 	unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info,
    253 						       input_section);
    254 	gap >>= 16;
    255 	bfd_put_8 (abfd, gap, data + dst_address);
    256 	dst_address += 1;
    257 	src_address += 1;
    258       }
    259       break;
    260 
    261     case R_W65_ABS16:
    262       {
    263 	unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info,
    264 						       input_section);
    265 
    266 	bfd_put_16 (abfd, (bfd_vma) gap, data + dst_address);
    267 	dst_address += 2;
    268 	src_address += 2;
    269       }
    270       break;
    271     case R_W65_ABS16S8:
    272       {
    273 	unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info,
    274 						       input_section);
    275 	gap >>= 8;
    276 	bfd_put_16 (abfd, (bfd_vma) gap, data + dst_address);
    277 	dst_address += 2;
    278 	src_address += 2;
    279       }
    280       break;
    281     case R_W65_ABS16S16:
    282       {
    283 	unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info,
    284 						       input_section);
    285 	gap >>= 16;
    286 	bfd_put_16 (abfd, (bfd_vma) gap, data + dst_address);
    287 	dst_address += 2;
    288 	src_address += 2;
    289       }
    290       break;
    291 
    292     case R_W65_ABS24:
    293       {
    294 	unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info,
    295 						       input_section);
    296 	bfd_put_16 (abfd, (bfd_vma) gap, data + dst_address);
    297 	bfd_put_8 (abfd, gap >> 16, data+dst_address + 2);
    298 	dst_address += 3;
    299 	src_address += 3;
    300       }
    301       break;
    302 
    303     case R_W65_PCR8:
    304       {
    305 	int gap = bfd_coff_reloc16_get_value (reloc, link_info,
    306 					      input_section);
    307 	bfd_vma dot = (dst_address
    308 		       + input_section->output_offset
    309 		       + input_section->output_section->vma);
    310 
    311 	gap -= dot + 1;
    312 	if (gap < -128 || gap > 127)
    313 	  {
    314 	    if (! ((*link_info->callbacks->reloc_overflow)
    315 		   (link_info, NULL,
    316 		    bfd_asymbol_name (*reloc->sym_ptr_ptr),
    317 		    reloc->howto->name, reloc->addend, input_section->owner,
    318 		    input_section, reloc->address)))
    319 	      abort ();
    320 	  }
    321 	bfd_put_8 (abfd, gap, data + dst_address);
    322 	dst_address += 1;
    323 	src_address += 1;
    324       }
    325       break;
    326 
    327     case R_W65_PCR16:
    328       {
    329 	bfd_vma gap = bfd_coff_reloc16_get_value (reloc, link_info,
    330 						  input_section);
    331 	bfd_vma dot = (dst_address
    332 		       + input_section->output_offset
    333 		       + input_section->output_section->vma);
    334 
    335 	/* This wraps within the page, so ignore the relativeness, look at the
    336 	   high part.  */
    337 	if ((gap & 0xf0000) != (dot & 0xf0000))
    338 	  {
    339 	    if (! ((*link_info->callbacks->reloc_overflow)
    340 		   (link_info, NULL,
    341 		    bfd_asymbol_name (*reloc->sym_ptr_ptr),
    342 		    reloc->howto->name, reloc->addend, input_section->owner,
    343 		    input_section, reloc->address)))
    344 	      abort ();
    345 	  }
    346 
    347 	gap -= dot + 2;
    348 	bfd_put_16 (abfd, gap, data + dst_address);
    349 	dst_address += 2;
    350 	src_address += 2;
    351       }
    352       break;
    353     default:
    354       printf (_("ignoring reloc %s\n"), reloc->howto->name);
    355       break;
    356 
    357     }
    358   *src_ptr = src_address;
    359   *dst_ptr = dst_address;
    360 }
    361 
    362 #define coff_reloc16_extra_cases w65_reloc16_extra_cases
    363 #define coff_reloc16_estimate w65_reloc16_estimate
    364 
    365 #ifndef bfd_pe_print_pdata
    366 #define bfd_pe_print_pdata	NULL
    367 #endif
    368 
    369 #include "coffcode.h"
    370 
    371 #undef coff_bfd_get_relocated_section_contents
    372 #undef coff_bfd_relax_section
    373 #define coff_bfd_get_relocated_section_contents \
    374   bfd_coff_reloc16_get_relocated_section_contents
    375 #define coff_bfd_relax_section bfd_coff_reloc16_relax_section
    376 
    377 CREATE_LITTLE_COFF_TARGET_VEC (w65_coff_vec, "coff-w65", BFD_IS_RELAXABLE, 0, '_', NULL, COFF_SWAP_TABLE)
    378