Home | History | Annotate | Line # | Download | only in bfd
coff-z8k.c revision 1.9
      1  1.1  christos /* BFD back-end for Zilog Z800n COFF binaries.
      2  1.9  christos    Copyright (C) 1992-2024 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.9  christos   if (reloc->r_symndx == -1 || symbols == NULL)
    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.9  christos static bool
    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.9  christos 	    size_t *src_ptr,
    203  1.9  christos 	    size_t *dst_ptr)
    204  1.1  christos {
    205  1.1  christos   asection * input_section = link_order->u.indirect.section;
    206  1.9  christos   bfd_size_type end = bfd_get_section_limit_octets (in_abfd, input_section);
    207  1.9  christos   bfd_size_type reloc_size = bfd_get_reloc_size (reloc->howto);
    208  1.9  christos 
    209  1.9  christos   if (*src_ptr > end
    210  1.9  christos       || reloc_size > end - *src_ptr)
    211  1.9  christos     {
    212  1.9  christos       link_info->callbacks->einfo
    213  1.9  christos 	/* xgettext:c-format */
    214  1.9  christos 	(_("%X%P: %pB(%pA): relocation \"%pR\" goes out of range\n"),
    215  1.9  christos 	 in_abfd, input_section, reloc);
    216  1.9  christos       return false;
    217  1.9  christos     }
    218  1.1  christos 
    219  1.1  christos   switch (reloc->howto->type)
    220  1.1  christos     {
    221  1.1  christos     case R_IMM8:
    222  1.1  christos       bfd_put_8 (in_abfd,
    223  1.1  christos 		 bfd_coff_reloc16_get_value (reloc, link_info, input_section),
    224  1.1  christos 		 data + *dst_ptr);
    225  1.9  christos       *dst_ptr += 1;
    226  1.9  christos       *src_ptr += 1;
    227  1.1  christos       break;
    228  1.1  christos 
    229  1.1  christos     case R_IMM32:
    230  1.1  christos       /* If no flags are set, assume immediate value.  */
    231  1.1  christos       if (! (*reloc->sym_ptr_ptr)->section->flags)
    232  1.1  christos 	{
    233  1.1  christos 	  bfd_put_32 (in_abfd,
    234  1.1  christos 		      bfd_coff_reloc16_get_value (reloc, link_info,
    235  1.1  christos 						  input_section),
    236  1.1  christos 		      data + *dst_ptr);
    237  1.1  christos 	}
    238  1.1  christos       else
    239  1.1  christos 	{
    240  1.1  christos 	  bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
    241  1.1  christos 						    input_section);
    242  1.1  christos 	  /* Addresses are 23 bit, and the layout of those in a 32-bit
    243  1.1  christos 	     value is as follows:
    244  1.1  christos 	       1AAAAAAA xxxxxxxx AAAAAAAA AAAAAAAA
    245  1.1  christos 	     (A - address bits,  x - ignore).  */
    246  1.1  christos 	  dst = (dst & 0xffff) | ((dst & 0xff0000) << 8) | 0x80000000;
    247  1.1  christos 	  bfd_put_32 (in_abfd, dst, data + *dst_ptr);
    248  1.1  christos 	}
    249  1.9  christos       *dst_ptr += 4;
    250  1.9  christos       *src_ptr += 4;
    251  1.1  christos       break;
    252  1.1  christos 
    253  1.1  christos     case R_IMM4L:
    254  1.1  christos       bfd_put_8 (in_abfd,
    255  1.1  christos 		 ((bfd_get_8 (in_abfd, data + *dst_ptr) & 0xf0)
    256  1.9  christos 		  | (0x0f & bfd_coff_reloc16_get_value (reloc, link_info,
    257  1.9  christos 							input_section))),
    258  1.1  christos 		 data + *dst_ptr);
    259  1.9  christos       *dst_ptr += 1;
    260  1.9  christos       *src_ptr += 1;
    261  1.1  christos       break;
    262  1.1  christos 
    263  1.1  christos     case R_IMM16:
    264  1.1  christos       bfd_put_16 (in_abfd,
    265  1.1  christos 		  bfd_coff_reloc16_get_value (reloc, link_info, input_section),
    266  1.1  christos 		  data + *dst_ptr);
    267  1.9  christos       *dst_ptr += 2;
    268  1.9  christos       *src_ptr += 2;
    269  1.1  christos       break;
    270  1.1  christos 
    271  1.1  christos     case R_JR:
    272  1.1  christos       {
    273  1.1  christos 	bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
    274  1.1  christos 						  input_section);
    275  1.1  christos 	bfd_vma dot = (*dst_ptr
    276  1.1  christos 		       + input_section->output_offset
    277  1.1  christos 		       + input_section->output_section->vma);
    278  1.9  christos 	/* -1, since we're in the odd byte of the word and the pc has
    279  1.9  christos 	   been incremented.  */
    280  1.9  christos 	bfd_signed_vma gap = dst - dot - 1;
    281  1.9  christos 
    282  1.9  christos 	if ((gap & 1) != 0 || gap > 254 || gap < -256)
    283  1.9  christos 	  {
    284  1.9  christos 	    link_info->callbacks->reloc_overflow
    285  1.9  christos 	      (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
    286  1.9  christos 	       reloc->howto->name, reloc->addend, input_section->owner,
    287  1.9  christos 	       input_section, reloc->address);
    288  1.9  christos 	    return false;
    289  1.9  christos 	  }
    290  1.9  christos 
    291  1.9  christos 	bfd_put_8 (in_abfd, gap / 2, data + *dst_ptr);
    292  1.9  christos 	*dst_ptr += 1;
    293  1.9  christos 	*src_ptr += 1;
    294  1.1  christos 	break;
    295  1.1  christos       }
    296  1.1  christos 
    297  1.1  christos     case R_DISP7:
    298  1.1  christos       {
    299  1.1  christos 	bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
    300  1.1  christos 						  input_section);
    301  1.1  christos 	bfd_vma dot = (*dst_ptr
    302  1.1  christos 		       + input_section->output_offset
    303  1.1  christos 		       + input_section->output_section->vma);
    304  1.9  christos 	bfd_signed_vma gap = dst - dot - 1;
    305  1.1  christos 
    306  1.9  christos 	if ((gap & 1) != 0 || gap > 0 || gap < -254)
    307  1.9  christos 	  {
    308  1.9  christos 	    link_info->callbacks->reloc_overflow
    309  1.9  christos 	      (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
    310  1.9  christos 	       reloc->howto->name, reloc->addend, input_section->owner,
    311  1.9  christos 	       input_section, reloc->address);
    312  1.9  christos 	    return false;
    313  1.9  christos 	  }
    314  1.5  christos 
    315  1.1  christos 	bfd_put_8 (in_abfd,
    316  1.9  christos 		   ((bfd_get_8 (in_abfd, data + *dst_ptr) & 0x80)
    317  1.9  christos 		    + (-gap / 2 & 0x7f)),
    318  1.6  christos 		   data + *dst_ptr);
    319  1.9  christos 	*dst_ptr += 1;
    320  1.9  christos 	*src_ptr += 1;
    321  1.1  christos 	break;
    322  1.1  christos       }
    323  1.1  christos 
    324  1.1  christos     case R_CALLR:
    325  1.1  christos       {
    326  1.1  christos 	bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
    327  1.1  christos 						  input_section);
    328  1.1  christos 	bfd_vma dot = (*dst_ptr
    329  1.1  christos 		       + input_section->output_offset
    330  1.1  christos 		       + input_section->output_section->vma);
    331  1.9  christos 	bfd_signed_vma gap = dst - dot - 2;
    332  1.1  christos 
    333  1.9  christos 	if ((gap & 1) != 0 || gap > 4096 || gap < -4095)
    334  1.9  christos 	  {
    335  1.9  christos 	    link_info->callbacks->reloc_overflow
    336  1.9  christos 	      (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
    337  1.9  christos 	       reloc->howto->name, reloc->addend, input_section->owner,
    338  1.9  christos 	       input_section, reloc->address);
    339  1.9  christos 	    return false;
    340  1.9  christos 	  }
    341  1.5  christos 
    342  1.1  christos 	bfd_put_16 (in_abfd,
    343  1.9  christos 		    ((bfd_get_16 (in_abfd, data + *dst_ptr) & 0xf000)
    344  1.9  christos 		     | (-gap / 2 & 0x0fff)),
    345  1.6  christos 		    data + *dst_ptr);
    346  1.9  christos 	*dst_ptr += 2;
    347  1.9  christos 	*src_ptr += 2;
    348  1.1  christos 	break;
    349  1.1  christos       }
    350  1.1  christos 
    351  1.1  christos     case R_REL16:
    352  1.1  christos       {
    353  1.1  christos 	bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
    354  1.1  christos 						  input_section);
    355  1.1  christos 	bfd_vma dot = (*dst_ptr
    356  1.1  christos 		       + input_section->output_offset
    357  1.1  christos 		       + input_section->output_section->vma);
    358  1.9  christos 	bfd_signed_vma gap = dst - dot - 2;
    359  1.1  christos 
    360  1.1  christos 	if (gap > 32767 || gap < -32768)
    361  1.9  christos 	  {
    362  1.9  christos 	    link_info->callbacks->reloc_overflow
    363  1.9  christos 	      (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
    364  1.9  christos 	       reloc->howto->name, reloc->addend, input_section->owner,
    365  1.9  christos 	       input_section, reloc->address);
    366  1.9  christos 	    return false;
    367  1.9  christos 	  }
    368  1.9  christos 
    369  1.9  christos 	bfd_put_16 (in_abfd, gap, data + *dst_ptr);
    370  1.9  christos 	*dst_ptr += 2;
    371  1.9  christos 	*src_ptr += 2;
    372  1.1  christos 	break;
    373  1.1  christos       }
    374  1.1  christos 
    375  1.1  christos     default:
    376  1.9  christos       link_info->callbacks->einfo
    377  1.9  christos 	/* xgettext:c-format */
    378  1.9  christos 	(_("%X%P: %pB(%pA): relocation \"%pR\" is not supported\n"),
    379  1.9  christos 	 in_abfd, input_section, reloc);
    380  1.9  christos       return false;
    381  1.1  christos     }
    382  1.9  christos   return true;
    383  1.1  christos }
    384  1.1  christos 
    385  1.1  christos #define coff_reloc16_extra_cases    extra_case
    386  1.1  christos #define coff_bfd_reloc_type_lookup  coff_z8k_reloc_type_lookup
    387  1.1  christos #define coff_bfd_reloc_name_lookup coff_z8k_reloc_name_lookup
    388  1.1  christos 
    389  1.1  christos #ifndef bfd_pe_print_pdata
    390  1.1  christos #define bfd_pe_print_pdata	NULL
    391  1.1  christos #endif
    392  1.1  christos 
    393  1.1  christos #include "coffcode.h"
    394  1.1  christos 
    395  1.1  christos #undef  coff_bfd_get_relocated_section_contents
    396  1.1  christos #define coff_bfd_get_relocated_section_contents \
    397  1.1  christos   bfd_coff_reloc16_get_relocated_section_contents
    398  1.1  christos 
    399  1.1  christos #undef  coff_bfd_relax_section
    400  1.1  christos #define coff_bfd_relax_section bfd_coff_reloc16_relax_section
    401  1.1  christos 
    402  1.3  christos CREATE_BIG_COFF_TARGET_VEC (z8k_coff_vec, "coff-z8k", 0, 0, '_', NULL, COFF_SWAP_TABLE)
    403