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