Home | History | Annotate | Line # | Download | only in bfd
coff-z8k.c revision 1.8
      1  1.1  christos /* BFD back-end for Zilog Z800n COFF binaries.
      2  1.8  christos    Copyright (C) 1992-2022 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.8  christos HOWTO (R_IMM32, 0, 4, 32, false, 0,
     35  1.8  christos        complain_overflow_bitfield, 0, "r_imm32", true, 0xffffffff,
     36  1.8  christos        0xffffffff, false);
     37  1.1  christos 
     38  1.1  christos static reloc_howto_type r_imm4l =
     39  1.8  christos HOWTO (R_IMM4L, 0, 1, 4, false, 0,
     40  1.8  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.8  christos HOWTO (R_IMM16, 0, 2, 16, false, 0,
     44  1.8  christos        complain_overflow_bitfield, 0, "r_da", true, 0x0000ffff, 0x0000ffff,
     45  1.8  christos        false);
     46  1.1  christos 
     47  1.1  christos static reloc_howto_type r_imm8 =
     48  1.8  christos HOWTO (R_IMM8, 0, 1, 8, false, 0,
     49  1.8  christos        complain_overflow_bitfield, 0, "r_imm8", true, 0x000000ff, 0x000000ff,
     50  1.8  christos        false);
     51  1.1  christos 
     52  1.1  christos static reloc_howto_type r_rel16 =
     53  1.8  christos HOWTO (R_REL16, 0, 2, 16, false, 0,
     54  1.8  christos        complain_overflow_bitfield, 0, "r_rel16", true, 0x0000ffff, 0x0000ffff,
     55  1.8  christos        true);
     56  1.1  christos 
     57  1.1  christos static reloc_howto_type r_jr =
     58  1.8  christos HOWTO (R_JR, 1, 1, 8, true, 0, complain_overflow_signed, 0,
     59  1.8  christos        "r_jr", true, 0xff, 0xff, true);
     60  1.1  christos 
     61  1.1  christos static reloc_howto_type r_disp7 =
     62  1.8  christos HOWTO (R_DISP7, 0, 1, 7, true, 0, complain_overflow_bitfield, 0,
     63  1.8  christos        "r_disp7", true, 0x7f, 0x7f, true);
     64  1.1  christos 
     65  1.1  christos static reloc_howto_type r_callr =
     66  1.8  christos HOWTO (R_CALLR, 1, 2, 12, true, 0, complain_overflow_signed, 0,
     67  1.8  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.6  christos 			    bfd_reloc_code_real_type code)
    122  1.1  christos {
    123  1.1  christos   switch (code)
    124  1.1  christos     {
    125  1.6  christos     case BFD_RELOC_8:		return & r_imm8;
    126  1.6  christos     case BFD_RELOC_16:		return & r_da;
    127  1.6  christos     case BFD_RELOC_32:		return & r_imm32;
    128  1.6  christos     case BFD_RELOC_8_PCREL:	return & r_jr;
    129  1.6  christos     case BFD_RELOC_16_PCREL:	return & r_rel16;
    130  1.6  christos     case BFD_RELOC_Z8K_DISP7:	return & r_disp7;
    131  1.6  christos     case BFD_RELOC_Z8K_CALLR:	return & r_callr;
    132  1.6  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.6  christos 		  struct internal_reloc *reloc,
    173  1.6  christos 		  asymbol **symbols,
    174  1.6  christos 		  bfd *abfd,
    175  1.6  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.8  christos   if (reloc->r_symndx == -1)
    181  1.8  christos     relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
    182  1.8  christos   else if (reloc->r_symndx >= 0 && reloc->r_symndx < obj_conv_table_size (abfd))
    183  1.1  christos     relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx];
    184  1.1  christos   else
    185  1.8  christos     {
    186  1.8  christos       _bfd_error_handler
    187  1.8  christos 	/* xgettext:c-format */
    188  1.8  christos 	(_("%pB: warning: illegal symbol index %ld in relocs"),
    189  1.8  christos 	 abfd, reloc->r_symndx);
    190  1.8  christos       relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
    191  1.8  christos     }
    192  1.1  christos   relent->addend = reloc->r_offset;
    193  1.1  christos   relent->address -= section->vma;
    194  1.1  christos }
    195  1.1  christos 
    196  1.1  christos static void
    197  1.1  christos extra_case (bfd *in_abfd,
    198  1.6  christos 	    struct bfd_link_info *link_info,
    199  1.6  christos 	    struct bfd_link_order *link_order,
    200  1.6  christos 	    arelent *reloc,
    201  1.6  christos 	    bfd_byte *data,
    202  1.6  christos 	    unsigned int *src_ptr,
    203  1.6  christos 	    unsigned int *dst_ptr)
    204  1.1  christos {
    205  1.1  christos   asection * input_section = link_order->u.indirect.section;
    206  1.1  christos 
    207  1.1  christos   switch (reloc->howto->type)
    208  1.1  christos     {
    209  1.1  christos     case R_IMM8:
    210  1.1  christos       bfd_put_8 (in_abfd,
    211  1.1  christos 		 bfd_coff_reloc16_get_value (reloc, link_info, input_section),
    212  1.1  christos 		 data + *dst_ptr);
    213  1.1  christos       (*dst_ptr) += 1;
    214  1.1  christos       (*src_ptr) += 1;
    215  1.1  christos       break;
    216  1.1  christos 
    217  1.1  christos     case R_IMM32:
    218  1.1  christos       /* If no flags are set, assume immediate value.  */
    219  1.1  christos       if (! (*reloc->sym_ptr_ptr)->section->flags)
    220  1.1  christos 	{
    221  1.1  christos 	  bfd_put_32 (in_abfd,
    222  1.1  christos 		      bfd_coff_reloc16_get_value (reloc, link_info,
    223  1.1  christos 						  input_section),
    224  1.1  christos 		      data + *dst_ptr);
    225  1.1  christos 	}
    226  1.1  christos       else
    227  1.1  christos 	{
    228  1.1  christos 	  bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
    229  1.1  christos 						    input_section);
    230  1.1  christos 	  /* Addresses are 23 bit, and the layout of those in a 32-bit
    231  1.1  christos 	     value is as follows:
    232  1.1  christos 	       1AAAAAAA xxxxxxxx AAAAAAAA AAAAAAAA
    233  1.1  christos 	     (A - address bits,  x - ignore).  */
    234  1.1  christos 	  dst = (dst & 0xffff) | ((dst & 0xff0000) << 8) | 0x80000000;
    235  1.1  christos 	  bfd_put_32 (in_abfd, dst, data + *dst_ptr);
    236  1.1  christos 	}
    237  1.1  christos       (*dst_ptr) += 4;
    238  1.1  christos       (*src_ptr) += 4;
    239  1.1  christos       break;
    240  1.1  christos 
    241  1.1  christos     case R_IMM4L:
    242  1.1  christos       bfd_put_8 (in_abfd,
    243  1.1  christos 		 ((bfd_get_8 (in_abfd, data + *dst_ptr) & 0xf0)
    244  1.1  christos 		  | (0x0f
    245  1.1  christos 		     & bfd_coff_reloc16_get_value (reloc, link_info,
    246  1.1  christos 						   input_section))),
    247  1.1  christos 		 data + *dst_ptr);
    248  1.1  christos       (*dst_ptr) += 1;
    249  1.1  christos       (*src_ptr) += 1;
    250  1.1  christos       break;
    251  1.1  christos 
    252  1.1  christos     case R_IMM16:
    253  1.1  christos       bfd_put_16 (in_abfd,
    254  1.1  christos 		  bfd_coff_reloc16_get_value (reloc, link_info, input_section),
    255  1.1  christos 		  data + *dst_ptr);
    256  1.1  christos       (*dst_ptr) += 2;
    257  1.1  christos       (*src_ptr) += 2;
    258  1.1  christos       break;
    259  1.1  christos 
    260  1.1  christos     case R_JR:
    261  1.1  christos       {
    262  1.1  christos 	bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
    263  1.1  christos 						  input_section);
    264  1.1  christos 	bfd_vma dot = (*dst_ptr
    265  1.1  christos 		       + input_section->output_offset
    266  1.1  christos 		       + input_section->output_section->vma);
    267  1.1  christos 	int gap = dst - dot - 1;  /* -1, since we're in the odd byte of the
    268  1.6  christos 				     word and the pc's been incremented.  */
    269  1.1  christos 
    270  1.1  christos 	if (gap & 1)
    271  1.1  christos 	  abort ();
    272  1.1  christos 	gap /= 2;
    273  1.5  christos 	if (gap > 127 || gap < -128)
    274  1.5  christos 	  (*link_info->callbacks->reloc_overflow)
    275  1.5  christos 	    (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
    276  1.5  christos 	     reloc->howto->name, reloc->addend, input_section->owner,
    277  1.5  christos 	     input_section, reloc->address);
    278  1.5  christos 
    279  1.1  christos 	bfd_put_8 (in_abfd, gap, data + *dst_ptr);
    280  1.1  christos 	(*dst_ptr)++;
    281  1.1  christos 	(*src_ptr)++;
    282  1.1  christos 	break;
    283  1.1  christos       }
    284  1.1  christos 
    285  1.1  christos     case R_DISP7:
    286  1.1  christos       {
    287  1.1  christos 	bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
    288  1.1  christos 						  input_section);
    289  1.1  christos 	bfd_vma dot = (*dst_ptr
    290  1.1  christos 		       + input_section->output_offset
    291  1.1  christos 		       + input_section->output_section->vma);
    292  1.1  christos 	int gap = dst - dot - 1;  /* -1, since we're in the odd byte of the
    293  1.6  christos 				     word and the pc's been incremented.  */
    294  1.1  christos 
    295  1.1  christos 	if (gap & 1)
    296  1.1  christos 	  abort ();
    297  1.1  christos 	gap /= 2;
    298  1.1  christos 
    299  1.1  christos 	if (gap > 0 || gap < -127)
    300  1.5  christos 	  (*link_info->callbacks->reloc_overflow)
    301  1.5  christos 	    (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
    302  1.5  christos 	     reloc->howto->name, reloc->addend, input_section->owner,
    303  1.5  christos 	     input_section, reloc->address);
    304  1.5  christos 
    305  1.1  christos 	bfd_put_8 (in_abfd,
    306  1.6  christos 		   (bfd_get_8 ( in_abfd, data + *dst_ptr) & 0x80) + (-gap & 0x7f),
    307  1.6  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.5  christos 	  (*link_info->callbacks->reloc_overflow)
    326  1.5  christos 	    (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
    327  1.5  christos 	     reloc->howto->name, reloc->addend, input_section->owner,
    328  1.5  christos 	     input_section, reloc->address);
    329  1.5  christos 
    330  1.1  christos 	gap /= 2;
    331  1.1  christos 	bfd_put_16 (in_abfd,
    332  1.6  christos 		    (bfd_get_16 ( in_abfd, data + *dst_ptr) & 0xf000) | (-gap & 0x0fff),
    333  1.6  christos 		    data + *dst_ptr);
    334  1.1  christos 	(*dst_ptr) += 2;
    335  1.1  christos 	(*src_ptr) += 2;
    336  1.1  christos 	break;
    337  1.1  christos       }
    338  1.1  christos 
    339  1.1  christos     case R_REL16:
    340  1.1  christos       {
    341  1.1  christos 	bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
    342  1.1  christos 						  input_section);
    343  1.1  christos 	bfd_vma dot = (*dst_ptr
    344  1.1  christos 		       + input_section->output_offset
    345  1.1  christos 		       + input_section->output_section->vma);
    346  1.1  christos 	int gap = dst - dot - 2;
    347  1.1  christos 
    348  1.1  christos 	if (gap > 32767 || gap < -32768)
    349  1.5  christos 	  (*link_info->callbacks->reloc_overflow)
    350  1.5  christos 	    (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
    351  1.5  christos 	     reloc->howto->name, reloc->addend, input_section->owner,
    352  1.5  christos 	     input_section, reloc->address);
    353  1.5  christos 
    354  1.1  christos 	bfd_put_16 (in_abfd, (bfd_vma) gap, data + *dst_ptr);
    355  1.1  christos 	(*dst_ptr) += 2;
    356  1.1  christos 	(*src_ptr) += 2;
    357  1.1  christos 	break;
    358  1.1  christos       }
    359  1.1  christos 
    360  1.1  christos     default:
    361  1.1  christos       abort ();
    362  1.1  christos     }
    363  1.1  christos }
    364  1.1  christos 
    365  1.1  christos #define coff_reloc16_extra_cases    extra_case
    366  1.1  christos #define coff_bfd_reloc_type_lookup  coff_z8k_reloc_type_lookup
    367  1.1  christos #define coff_bfd_reloc_name_lookup coff_z8k_reloc_name_lookup
    368  1.1  christos 
    369  1.1  christos #ifndef bfd_pe_print_pdata
    370  1.1  christos #define bfd_pe_print_pdata	NULL
    371  1.1  christos #endif
    372  1.1  christos 
    373  1.1  christos #include "coffcode.h"
    374  1.1  christos 
    375  1.1  christos #undef  coff_bfd_get_relocated_section_contents
    376  1.1  christos #define coff_bfd_get_relocated_section_contents \
    377  1.1  christos   bfd_coff_reloc16_get_relocated_section_contents
    378  1.1  christos 
    379  1.1  christos #undef  coff_bfd_relax_section
    380  1.1  christos #define coff_bfd_relax_section bfd_coff_reloc16_relax_section
    381  1.1  christos 
    382  1.3  christos CREATE_BIG_COFF_TARGET_VEC (z8k_coff_vec, "coff-z8k", 0, 0, '_', NULL, COFF_SWAP_TABLE)
    383