Home | History | Annotate | Line # | Download | only in bfd
coff-z8k.c revision 1.1
      1 /* BFD back-end for Zilog Z800n COFF binaries.
      2    Copyright 1992, 1993, 1994, 1995, 1997, 1999, 2000, 2001, 2002, 2003,
      3    2004, 2005, 2007, 2008  Free Software Foundation, Inc.
      4    Contributed by Cygnus Support.
      5    Written by Steve Chamberlain, <sac (at) cygnus.com>.
      6 
      7    This file is part of BFD, the Binary File Descriptor library.
      8 
      9    This program is free software; you can redistribute it and/or modify
     10    it under the terms of the GNU General Public License as published by
     11    the Free Software Foundation; either version 3 of the License, or
     12    (at your option) any later version.
     13 
     14    This program is distributed in the hope that it will be useful,
     15    but WITHOUT ANY WARRANTY; without even the implied warranty of
     16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17    GNU General Public License for more details.
     18 
     19    You should have received a copy of the GNU General Public License
     20    along with this program; if not, write to the Free Software
     21    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     22    MA 02110-1301, USA.  */
     23 
     24 #include "sysdep.h"
     25 #include "bfd.h"
     26 #include "libbfd.h"
     27 #include "bfdlink.h"
     28 #include "coff/z8k.h"
     29 #include "coff/internal.h"
     30 #include "libcoff.h"
     31 
     32 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (1)
     33 
     34 static reloc_howto_type r_imm32 =
     35 HOWTO (R_IMM32, 0, 2, 32, FALSE, 0,
     36        complain_overflow_bitfield, 0, "r_imm32", TRUE, 0xffffffff,
     37        0xffffffff, FALSE);
     38 
     39 static reloc_howto_type r_imm4l =
     40 HOWTO (R_IMM4L, 0, 0, 4, FALSE, 0,
     41        complain_overflow_bitfield, 0, "r_imm4l", TRUE, 0xf, 0xf, FALSE);
     42 
     43 static reloc_howto_type r_da =
     44 HOWTO (R_IMM16, 0, 1, 16, FALSE, 0,
     45        complain_overflow_bitfield, 0, "r_da", TRUE, 0x0000ffff, 0x0000ffff,
     46        FALSE);
     47 
     48 static reloc_howto_type r_imm8 =
     49 HOWTO (R_IMM8, 0, 0, 8, FALSE, 0,
     50        complain_overflow_bitfield, 0, "r_imm8", TRUE, 0x000000ff, 0x000000ff,
     51        FALSE);
     52 
     53 static reloc_howto_type r_rel16 =
     54 HOWTO (R_REL16, 0, 1, 16, FALSE, 0,
     55        complain_overflow_bitfield, 0, "r_rel16", TRUE, 0x0000ffff, 0x0000ffff,
     56        TRUE);
     57 
     58 static reloc_howto_type r_jr =
     59 HOWTO (R_JR, 1, 0, 8, TRUE, 0, complain_overflow_signed, 0,
     60        "r_jr", TRUE, 0xff, 0xff, TRUE);
     61 
     62 static reloc_howto_type r_disp7 =
     63 HOWTO (R_DISP7, 0, 0, 7, TRUE, 0, complain_overflow_bitfield, 0,
     64        "r_disp7", TRUE, 0x7f, 0x7f, TRUE);
     65 
     66 static reloc_howto_type r_callr =
     67 HOWTO (R_CALLR, 1, 1, 12, TRUE, 0, complain_overflow_signed, 0,
     68        "r_callr", TRUE, 0xfff, 0xfff, TRUE);
     69 
     70 #define BADMAG(x) Z8KBADMAG(x)
     71 #define Z8K 1			/* Customize coffcode.h.  */
     72 #define __A_MAGIC_SET__
     73 
     74 /* Code to swap in the reloc.  */
     75 #define SWAP_IN_RELOC_OFFSET	H_GET_32
     76 #define SWAP_OUT_RELOC_OFFSET	H_PUT_32
     77 #define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \
     78   dst->r_stuff[0] = 'S'; \
     79   dst->r_stuff[1] = 'C';
     80 
     81 /* Code to turn a r_type into a howto ptr, uses the above howto table.  */
     82 
     83 static void
     84 rtype2howto (arelent *internal, struct internal_reloc *dst)
     85 {
     86   switch (dst->r_type)
     87     {
     88     default:
     89       abort ();
     90       break;
     91     case R_IMM8:
     92       internal->howto = &r_imm8;
     93       break;
     94      case R_IMM16:
     95       internal->howto = &r_da;
     96       break;
     97     case R_JR:
     98       internal->howto = &r_jr;
     99       break;
    100     case R_DISP7:
    101       internal->howto = &r_disp7;
    102       break;
    103     case R_CALLR:
    104       internal->howto = &r_callr;
    105       break;
    106     case R_REL16:
    107       internal->howto = &r_rel16;
    108       break;
    109     case R_IMM32:
    110       internal->howto = &r_imm32;
    111       break;
    112     case R_IMM4L:
    113       internal->howto = &r_imm4l;
    114       break;
    115     }
    116 }
    117 
    118 #define RTYPE2HOWTO(internal, relocentry) rtype2howto (internal, relocentry)
    119 
    120 static reloc_howto_type *
    121 coff_z8k_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
    122                             bfd_reloc_code_real_type code)
    123 {
    124   switch (code)
    125     {
    126     case BFD_RELOC_8:      	return & r_imm8;
    127     case BFD_RELOC_16:      	return & r_da;
    128     case BFD_RELOC_32:      	return & r_imm32;
    129     case BFD_RELOC_8_PCREL:     return & r_jr;
    130     case BFD_RELOC_16_PCREL:    return & r_rel16;
    131     case BFD_RELOC_Z8K_DISP7:   return & r_disp7;
    132     case BFD_RELOC_Z8K_CALLR:   return & r_callr;
    133     case BFD_RELOC_Z8K_IMM4L:   return & r_imm4l;
    134     default:			BFD_FAIL ();
    135       return 0;
    136     }
    137 }
    138 
    139 static reloc_howto_type *
    140 coff_z8k_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
    141 			    const char *r_name)
    142 {
    143   if (strcasecmp (r_imm8.name, r_name) == 0)
    144     return &r_imm8;
    145   if (strcasecmp (r_da.name, r_name) == 0)
    146     return &r_da;
    147   if (strcasecmp (r_imm32.name, r_name) == 0)
    148     return &r_imm32;
    149   if (strcasecmp (r_jr.name, r_name) == 0)
    150     return &r_jr;
    151   if (strcasecmp (r_rel16.name, r_name) == 0)
    152     return &r_rel16;
    153   if (strcasecmp (r_disp7.name, r_name) == 0)
    154     return &r_disp7;
    155   if (strcasecmp (r_callr.name, r_name) == 0)
    156     return &r_callr;
    157   if (strcasecmp (r_imm4l.name, r_name) == 0)
    158     return &r_imm4l;
    159 
    160   return NULL;
    161 }
    162 
    163 /* Perform any necessary magic to the addend in a reloc entry.  */
    164 
    165 #define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \
    166  cache_ptr->addend =  ext_reloc.r_offset;
    167 
    168 #define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \
    169  reloc_processing(relent, reloc, symbols, abfd, section)
    170 
    171 static void
    172 reloc_processing (arelent *relent,
    173                   struct internal_reloc *reloc,
    174                   asymbol **symbols,
    175                   bfd *abfd,
    176                   asection *section)
    177 {
    178   relent->address = reloc->r_vaddr;
    179   rtype2howto (relent, reloc);
    180 
    181   if (reloc->r_symndx > 0)
    182     relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx];
    183   else
    184     relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
    185 
    186   relent->addend = reloc->r_offset;
    187   relent->address -= section->vma;
    188 }
    189 
    190 static void
    191 extra_case (bfd *in_abfd,
    192             struct bfd_link_info *link_info,
    193             struct bfd_link_order *link_order,
    194             arelent *reloc,
    195             bfd_byte *data,
    196             unsigned int *src_ptr,
    197             unsigned int *dst_ptr)
    198 {
    199   asection * input_section = link_order->u.indirect.section;
    200 
    201   switch (reloc->howto->type)
    202     {
    203     case R_IMM8:
    204       bfd_put_8 (in_abfd,
    205 		 bfd_coff_reloc16_get_value (reloc, link_info, input_section),
    206 		 data + *dst_ptr);
    207       (*dst_ptr) += 1;
    208       (*src_ptr) += 1;
    209       break;
    210 
    211     case R_IMM32:
    212       /* If no flags are set, assume immediate value.  */
    213       if (! (*reloc->sym_ptr_ptr)->section->flags)
    214 	{
    215 	  bfd_put_32 (in_abfd,
    216 		      bfd_coff_reloc16_get_value (reloc, link_info,
    217 						  input_section),
    218 		      data + *dst_ptr);
    219 	}
    220       else
    221 	{
    222 	  bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
    223 						    input_section);
    224 	  /* Addresses are 23 bit, and the layout of those in a 32-bit
    225 	     value is as follows:
    226 	       1AAAAAAA xxxxxxxx AAAAAAAA AAAAAAAA
    227 	     (A - address bits,  x - ignore).  */
    228 	  dst = (dst & 0xffff) | ((dst & 0xff0000) << 8) | 0x80000000;
    229 	  bfd_put_32 (in_abfd, dst, data + *dst_ptr);
    230 	}
    231       (*dst_ptr) += 4;
    232       (*src_ptr) += 4;
    233       break;
    234 
    235     case R_IMM4L:
    236       bfd_put_8 (in_abfd,
    237 		 ((bfd_get_8 (in_abfd, data + *dst_ptr) & 0xf0)
    238 		  | (0x0f
    239 		     & bfd_coff_reloc16_get_value (reloc, link_info,
    240 						   input_section))),
    241 		 data + *dst_ptr);
    242       (*dst_ptr) += 1;
    243       (*src_ptr) += 1;
    244       break;
    245 
    246     case R_IMM16:
    247       bfd_put_16 (in_abfd,
    248 		  bfd_coff_reloc16_get_value (reloc, link_info, input_section),
    249 		  data + *dst_ptr);
    250       (*dst_ptr) += 2;
    251       (*src_ptr) += 2;
    252       break;
    253 
    254     case R_JR:
    255       {
    256 	bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
    257 						  input_section);
    258 	bfd_vma dot = (*dst_ptr
    259 		       + input_section->output_offset
    260 		       + input_section->output_section->vma);
    261 	int gap = dst - dot - 1;  /* -1, since we're in the odd byte of the
    262                                      word and the pc's been incremented.  */
    263 
    264 	if (gap & 1)
    265 	  abort ();
    266 	gap /= 2;
    267 	if (gap > 128 || gap < -128)
    268 	  {
    269 	    if (! ((*link_info->callbacks->reloc_overflow)
    270 		   (link_info, NULL,
    271 		    bfd_asymbol_name (*reloc->sym_ptr_ptr),
    272 		    reloc->howto->name, reloc->addend, input_section->owner,
    273 		    input_section, reloc->address)))
    274 	      abort ();
    275 	  }
    276 	bfd_put_8 (in_abfd, gap, data + *dst_ptr);
    277 	(*dst_ptr)++;
    278 	(*src_ptr)++;
    279 	break;
    280       }
    281 
    282     case R_DISP7:
    283       {
    284 	bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
    285 						  input_section);
    286 	bfd_vma dot = (*dst_ptr
    287 		       + input_section->output_offset
    288 		       + input_section->output_section->vma);
    289 	int gap = dst - dot - 1;  /* -1, since we're in the odd byte of the
    290                                      word and the pc's been incremented.  */
    291 
    292 	if (gap & 1)
    293 	  abort ();
    294 	gap /= 2;
    295 
    296 	if (gap > 0 || gap < -127)
    297 	  {
    298 	    if (! ((*link_info->callbacks->reloc_overflow)
    299 		   (link_info, NULL,
    300 		    bfd_asymbol_name (*reloc->sym_ptr_ptr),
    301 		    reloc->howto->name, reloc->addend, input_section->owner,
    302 		    input_section, reloc->address)))
    303 	      abort ();
    304 	  }
    305 	bfd_put_8 (in_abfd,
    306                    (bfd_get_8 ( in_abfd, data + *dst_ptr) & 0x80) + (-gap & 0x7f),
    307                    data + *dst_ptr);
    308 	(*dst_ptr)++;
    309 	(*src_ptr)++;
    310 	break;
    311       }
    312 
    313     case R_CALLR:
    314       {
    315 	bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
    316 						  input_section);
    317 	bfd_vma dot = (*dst_ptr
    318 		       + input_section->output_offset
    319 		       + input_section->output_section->vma);
    320 	int gap = dst - dot - 2;
    321 
    322 	if (gap & 1)
    323 	  abort ();
    324 	if (gap > 4096 || gap < -4095)
    325 	  {
    326 	    if (! ((*link_info->callbacks->reloc_overflow)
    327 		   (link_info, NULL,
    328 		    bfd_asymbol_name (*reloc->sym_ptr_ptr),
    329 		    reloc->howto->name, reloc->addend, input_section->owner,
    330 		    input_section, reloc->address)))
    331 	      abort ();
    332 	  }
    333 	gap /= 2;
    334 	bfd_put_16 (in_abfd,
    335                     (bfd_get_16 ( in_abfd, data + *dst_ptr) & 0xf000) | (-gap & 0x0fff),
    336                     data + *dst_ptr);
    337 	(*dst_ptr) += 2;
    338 	(*src_ptr) += 2;
    339 	break;
    340       }
    341 
    342     case R_REL16:
    343       {
    344 	bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
    345 						  input_section);
    346 	bfd_vma dot = (*dst_ptr
    347 		       + input_section->output_offset
    348 		       + input_section->output_section->vma);
    349 	int gap = dst - dot - 2;
    350 
    351 	if (gap > 32767 || gap < -32768)
    352 	  {
    353 	    if (! ((*link_info->callbacks->reloc_overflow)
    354 		   (link_info, NULL,
    355 		    bfd_asymbol_name (*reloc->sym_ptr_ptr),
    356 		    reloc->howto->name, reloc->addend, input_section->owner,
    357 		    input_section, reloc->address)))
    358 	      abort ();
    359 	  }
    360 	bfd_put_16 (in_abfd, (bfd_vma) gap, data + *dst_ptr);
    361 	(*dst_ptr) += 2;
    362 	(*src_ptr) += 2;
    363 	break;
    364       }
    365 
    366     default:
    367       abort ();
    368     }
    369 }
    370 
    371 #define coff_reloc16_extra_cases    extra_case
    372 #define coff_bfd_reloc_type_lookup  coff_z8k_reloc_type_lookup
    373 #define coff_bfd_reloc_name_lookup coff_z8k_reloc_name_lookup
    374 
    375 #ifndef bfd_pe_print_pdata
    376 #define bfd_pe_print_pdata	NULL
    377 #endif
    378 
    379 #include "coffcode.h"
    380 
    381 #undef  coff_bfd_get_relocated_section_contents
    382 #define coff_bfd_get_relocated_section_contents \
    383   bfd_coff_reloc16_get_relocated_section_contents
    384 
    385 #undef  coff_bfd_relax_section
    386 #define coff_bfd_relax_section bfd_coff_reloc16_relax_section
    387 
    388 CREATE_BIG_COFF_TARGET_VEC (z8kcoff_vec, "coff-z8k", 0, 0, '_', NULL, COFF_SWAP_TABLE)
    389