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