(root)/
binutils-2.41/
bfd/
coff-z80.c
       1  /* BFD back-end for Zilog Z80 COFF binaries.
       2     Copyright (C) 2005-2023 Free Software Foundation, Inc.
       3     Contributed by Arnold Metselaar <arnold_m@operamail.com>
       4  
       5     This file is part of BFD, the Binary File Descriptor library.
       6  
       7     This program is free software; you can redistribute it and/or modify
       8     it under the terms of the GNU General Public License as published by
       9     the Free Software Foundation; either version 3 of the License, or
      10     (at your option) any later version.
      11  
      12     This program is distributed in the hope that it will be useful,
      13     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15     GNU General Public License for more details.
      16  
      17     You should have received a copy of the GNU General Public License
      18     along with this program; if not, write to the Free Software
      19     Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
      20     MA 02110-1301, USA.  */
      21  
      22  #include "sysdep.h"
      23  #include "bfd.h"
      24  #include "libbfd.h"
      25  #include "bfdlink.h"
      26  #include "coff/z80.h"
      27  #include "coff/internal.h"
      28  #include "libcoff.h"
      29  #include "libiberty.h"
      30  
      31  #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER 0
      32  
      33  typedef const struct {
      34    bfd_reloc_code_real_type r_type;
      35    reloc_howto_type howto;
      36  } bfd_howto_type;
      37  
      38  #define BFD_EMPTY_HOWTO(rt,x) {rt, EMPTY_HOWTO(x)}
      39  #define BFD_HOWTO(rt,a,b,c,d,e,f,g,h,i,j,k,l,m) {rt, HOWTO(a,b,c,d,e,f,g,h,i,j,k,l,m)}
      40  
      41  static bfd_howto_type howto_table[] =
      42  {
      43    BFD_EMPTY_HOWTO (BFD_RELOC_NONE, 0),
      44  
      45    BFD_HOWTO (BFD_RELOC_32,
      46       R_IMM32,		/* type */
      47       0,			/* rightshift */
      48       4,			/* size */
      49       32,		/* bitsize */
      50       false,		/* pc_relative */
      51       0,			/* bitpos */
      52       complain_overflow_bitfield, /* complain_on_overflow */
      53       0,			/* special_function */
      54       "r_imm32",		/* name */
      55       false,		/* partial_inplace */
      56       0xffffffff,	/* src_mask */
      57       0xffffffff,	/* dst_mask */
      58       false),		/* pcrel_offset */
      59  
      60    BFD_HOWTO (BFD_RELOC_24,
      61       R_IMM24,		/* type */
      62       0,			/* rightshift */
      63       3,			/* size */
      64       24,		/* bitsize */
      65       false,		/* pc_relative */
      66       0,			/* bitpos */
      67       complain_overflow_bitfield, /* complain_on_overflow */
      68       0,			/* special_function */
      69       "r_imm24",		/* name */
      70       false,		/* partial_inplace */
      71       0x00ffffff,	/* src_mask */
      72       0x00ffffff,	/* dst_mask */
      73       false),		/* pcrel_offset */
      74  
      75    BFD_HOWTO (BFD_RELOC_16,
      76       R_IMM16,		/* type */
      77       0,			/* rightshift */
      78       2,			/* size */
      79       16,		/* bitsize */
      80       false,		/* pc_relative */
      81       0,			/* bitpos */
      82       complain_overflow_bitfield, /* complain_on_overflow */
      83       0,			/* special_function */
      84       "r_imm16",		/* name */
      85       false,		/* partial_inplace */
      86       0x0000ffff,	/* src_mask */
      87       0x0000ffff,	/* dst_mask */
      88       false),		/* pcrel_offset */
      89  
      90    BFD_HOWTO (BFD_RELOC_8,
      91       R_IMM8,		/* type */
      92       0,			/* rightshift */
      93       1,			/* size */
      94       8,			/* bitsize */
      95       false,		/* pc_relative */
      96       0,			/* bitpos */
      97       complain_overflow_bitfield, /* complain_on_overflow */
      98       0,			/* special_function */
      99       "r_imm8",		/* name */
     100       false,		/* partial_inplace */
     101       0x000000ff,	/* src_mask */
     102       0x000000ff,	/* dst_mask */
     103       false),		/* pcrel_offset */
     104  
     105    BFD_HOWTO (BFD_RELOC_8_PCREL,
     106       R_JR,		/* type */
     107       0,			/* rightshift */
     108       1,			/* size */
     109       8,			/* bitsize */
     110       true,		/* pc_relative */
     111       0,			/* bitpos */
     112       complain_overflow_signed, /* complain_on_overflow */
     113       0,			/* special_function */
     114       "r_jr",		/* name */
     115       false,		/* partial_inplace */
     116       0,			/* src_mask */
     117       0xFF,		/* dst_mask */
     118       true),		/* pcrel_offset */
     119  
     120    BFD_HOWTO (BFD_RELOC_Z80_DISP8,
     121       R_OFF8,		/* type */
     122       0,			/* rightshift */
     123       1,			/* size */
     124       8,			/* bitsize */
     125       false,		/* pc_relative */
     126       0,			/* bitpos */
     127       complain_overflow_signed, /* complain_on_overflow */
     128       0,			/* special_function */
     129       "r_off8",		/* name */
     130       false,		/* partial_inplace */
     131       0,			/* src_mask */
     132       0xff,		/* dst_mask */
     133       false),		/* pcrel_offset */
     134  
     135    BFD_HOWTO (BFD_RELOC_Z80_BYTE0,
     136       R_BYTE0,		/* type */
     137       0,			/* rightshift */
     138       1,			/* size */
     139       8,			/* bitsize */
     140       false,		/* pc_relative */
     141       0,			/* bitpos */
     142       complain_overflow_dont, /* complain_on_overflow */
     143       0,			/* special_function */
     144       "r_byte0",		/* name */
     145       false,		/* partial_inplace */
     146       0,			/* src_mask */
     147       0xff,		/* dst_mask */
     148       false),		/* pcrel_offset */
     149  
     150    BFD_HOWTO (BFD_RELOC_Z80_BYTE1,
     151       R_BYTE1,		/* type */
     152       8,			/* rightshift */
     153       1,			/* size */
     154       8,			/* bitsize */
     155       false,		/* pc_relative */
     156       0,			/* bitpos */
     157       complain_overflow_dont, /* complain_on_overflow */
     158       0,			/* special_function */
     159       "r_byte1",		/* name */
     160       false,		/* partial_inplace */
     161       0,			/* src_mask */
     162       0xff,		/* dst_mask */
     163       false),		/* pcrel_offset */
     164  
     165    BFD_HOWTO (BFD_RELOC_Z80_BYTE2,
     166       R_BYTE2,		/* type */
     167       16,		/* rightshift */
     168       1,			/* size */
     169       8,			/* bitsize */
     170       false,		/* pc_relative */
     171       0,			/* bitpos */
     172       complain_overflow_dont, /* complain_on_overflow */
     173       0,			/* special_function */
     174       "r_byte2",		/* name */
     175       false,		/* partial_inplace */
     176       0,			/* src_mask */
     177       0xff,		/* dst_mask */
     178       false),		/* pcrel_offset */
     179  
     180    BFD_HOWTO (BFD_RELOC_Z80_BYTE3,
     181       R_BYTE3,		/* type */
     182       24,		/* rightshift */
     183       1,			/* size */
     184       8,			/* bitsize */
     185       false,		/* pc_relative */
     186       0,			/* bitpos */
     187       complain_overflow_dont, /* complain_on_overflow */
     188       0,			/* special_function */
     189       "r_byte3",		/* name */
     190       false,		/* partial_inplace */
     191       0,			/* src_mask */
     192       0xff,		/* dst_mask */
     193       false),		/* pcrel_offset */
     194  
     195    BFD_HOWTO (BFD_RELOC_Z80_WORD0,
     196       R_WORD0,		/* type */
     197       0,			/* rightshift */
     198       2,			/* size */
     199       16,		/* bitsize */
     200       false,		/* pc_relative */
     201       0,			/* bitpos */
     202       complain_overflow_dont, /* complain_on_overflow */
     203       0,			/* special_function */
     204       "r_word0",		/* name */
     205       false,		/* partial_inplace */
     206       0,			/* src_mask */
     207       0xffff,		/* dst_mask */
     208       false),		/* pcrel_offset */
     209  
     210    BFD_HOWTO (BFD_RELOC_Z80_WORD1,
     211       R_WORD1,		/* type */
     212       16,		/* rightshift */
     213       2,			/* size */
     214       16,		/* bitsize */
     215       false,		/* pc_relative */
     216       0,			/* bitpos */
     217       complain_overflow_dont, /* complain_on_overflow */
     218       0,			/* special_function */
     219       "r_word1",		/* name */
     220       false,		/* partial_inplace */
     221       0,			/* src_mask */
     222       0xffff,		/* dst_mask */
     223       false),		/* pcrel_offset */
     224  
     225    BFD_HOWTO (BFD_RELOC_Z80_16_BE,
     226       R_IMM16BE,		/* type */
     227       0,			/* rightshift */
     228       2,			/* size */
     229       16,		/* bitsize */
     230       false,		/* pc_relative */
     231       0,			/* bitpos */
     232       complain_overflow_bitfield, /* complain_on_overflow */
     233       0,			/* special_function */
     234       "r_imm16be",	/* name */
     235       false,		/* partial_inplace */
     236       0x0000ffff,	/* src_mask */
     237       0x0000ffff,	/* dst_mask */
     238       false),		/* pcrel_offset */
     239  };
     240  
     241  #define NUM_HOWTOS ARRAY_SIZE (howto_table)
     242  
     243  #define BADMAG(x) Z80BADMAG(x)
     244  #define Z80 1			/* Customize coffcode.h.  */
     245  #define __A_MAGIC_SET__
     246  
     247  /* Code to swap in the reloc.  */
     248  
     249  #define SWAP_IN_RELOC_OFFSET	H_GET_32
     250  #define SWAP_OUT_RELOC_OFFSET	H_PUT_32
     251  
     252  #define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \
     253    dst->r_stuff[0] = 'S'; \
     254    dst->r_stuff[1] = 'C';
     255  
     256  /* Code to turn a r_type into a howto ptr, uses the above howto table.  */
     257  static void
     258  rtype2howto (arelent *internal, struct internal_reloc *dst)
     259  {
     260    unsigned i;
     261    for (i = 0; i < NUM_HOWTOS; i++)
     262      {
     263        if (howto_table[i].howto.type == dst->r_type)
     264          {
     265            internal->howto = &howto_table[i].howto;
     266            return;
     267          }
     268      }
     269    internal->howto = NULL;
     270  }
     271  
     272  #define RTYPE2HOWTO(internal, relocentry) rtype2howto (internal, relocentry)
     273  
     274  static reloc_howto_type *
     275  coff_z80_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
     276  			    bfd_reloc_code_real_type code)
     277  {
     278    unsigned i;
     279    for (i = 0; i < NUM_HOWTOS; i++)
     280      if (howto_table[i].r_type == code)
     281        return &howto_table[i].howto;
     282  
     283    BFD_FAIL ();
     284    return NULL;
     285  }
     286  
     287  static reloc_howto_type *
     288  coff_z80_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
     289  			    const char *r_name)
     290  {
     291    unsigned i;
     292    for (i = 0; i < NUM_HOWTOS; i++)
     293      if (strcasecmp(howto_table[i].howto.name, r_name) == 0)
     294        return &howto_table[i].howto;
     295  
     296    return NULL;
     297  }
     298  
     299  /* Perform any necessary magic to the addend in a reloc entry.  */
     300  
     301  #define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \
     302   cache_ptr->addend =  ext_reloc.r_offset;
     303  
     304  #define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \
     305   reloc_processing(relent, reloc, symbols, abfd, section)
     306  
     307  static void
     308  reloc_processing (arelent *relent,
     309  		  struct internal_reloc *reloc,
     310  		  asymbol **symbols,
     311  		  bfd *abfd,
     312  		  asection *section)
     313  {
     314    relent->address = reloc->r_vaddr;
     315    rtype2howto (relent, reloc);
     316  
     317    if (reloc->r_symndx == -1 || symbols == NULL)
     318      relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
     319    else if (reloc->r_symndx >= 0 && reloc->r_symndx < obj_conv_table_size (abfd))
     320      relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx];
     321    else
     322      {
     323        _bfd_error_handler
     324  	/* xgettext:c-format */
     325  	(_("%pB: warning: illegal symbol index %ld in relocs"),
     326  	 abfd, reloc->r_symndx);
     327        relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
     328      }
     329    relent->addend = reloc->r_offset;
     330    relent->address -= section->vma;
     331  }
     332  
     333  static bool
     334  extra_case (bfd *in_abfd,
     335  	    struct bfd_link_info *link_info,
     336  	    struct bfd_link_order *link_order,
     337  	    arelent *reloc,
     338  	    bfd_byte *data,
     339  	    size_t *src_ptr,
     340  	    size_t *dst_ptr)
     341  {
     342    asection * input_section = link_order->u.indirect.section;
     343    bfd_size_type end = bfd_get_section_limit_octets (in_abfd, input_section);
     344    bfd_size_type reloc_size = bfd_get_reloc_size (reloc->howto);
     345  
     346    if (*src_ptr > end
     347        || reloc_size > end - *src_ptr)
     348      {
     349        link_info->callbacks->einfo
     350  	/* xgettext:c-format */
     351  	(_("%X%P: %pB(%pA): relocation \"%pR\" goes out of range\n"),
     352  	 in_abfd, input_section, reloc);
     353        return false;
     354      }
     355  
     356    int val = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
     357    switch (reloc->howto->type)
     358      {
     359      case R_OFF8:
     360        if (reloc->howto->partial_inplace)
     361  	val += (signed char) (bfd_get_8 (in_abfd, data + *src_ptr)
     362  			      & reloc->howto->src_mask);
     363        if (val > 127 || val < -128)
     364  	{
     365  	  link_info->callbacks->reloc_overflow
     366  	    (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
     367  	     reloc->howto->name, reloc->addend, input_section->owner,
     368  	     input_section, reloc->address);
     369  	  return false;
     370  	}
     371  
     372        bfd_put_8 (in_abfd, val, data + *dst_ptr);
     373        *dst_ptr += 1;
     374        *src_ptr += 1;
     375        break;
     376  
     377      case R_BYTE3:
     378        bfd_put_8 (in_abfd, val >> 24, data + *dst_ptr);
     379        *dst_ptr += 1;
     380        *src_ptr += 1;
     381        break;
     382  
     383      case R_BYTE2:
     384        bfd_put_8 (in_abfd, val >> 16, data + *dst_ptr);
     385        *dst_ptr += 1;
     386        *src_ptr += 1;
     387        break;
     388  
     389      case R_BYTE1:
     390        bfd_put_8 (in_abfd, val >> 8, data + *dst_ptr);
     391        *dst_ptr += 1;
     392        *src_ptr += 1;
     393        break;
     394  
     395      case R_IMM8:
     396        if (reloc->howto->partial_inplace)
     397  	val += bfd_get_8 (in_abfd, data + *src_ptr) & reloc->howto->src_mask;
     398        /* Fall through.  */
     399      case R_BYTE0:
     400        bfd_put_8 (in_abfd, val, data + *dst_ptr);
     401        *dst_ptr += 1;
     402        *src_ptr += 1;
     403        break;
     404  
     405      case R_WORD1:
     406        bfd_put_16 (in_abfd, val >> 16, data + *dst_ptr);
     407        *dst_ptr += 2;
     408        *src_ptr += 2;
     409        break;
     410  
     411      case R_IMM16:
     412        if (reloc->howto->partial_inplace)
     413  	val += bfd_get_16 (in_abfd, data + *src_ptr) & reloc->howto->src_mask;
     414        /* Fall through.  */
     415      case R_WORD0:
     416        bfd_put_16 (in_abfd, val, data + *dst_ptr);
     417        *dst_ptr += 2;
     418        *src_ptr += 2;
     419        break;
     420  
     421      case R_IMM24:
     422        if (reloc->howto->partial_inplace)
     423  	val += (bfd_get_24 (in_abfd, data + *src_ptr)
     424  		& reloc->howto->src_mask);
     425        bfd_put_24 (in_abfd, val, data + *dst_ptr);
     426        *dst_ptr += 3;
     427        *src_ptr += 3;
     428        break;
     429  
     430      case R_IMM32:
     431        if (reloc->howto->partial_inplace)
     432  	val += bfd_get_32 (in_abfd, data + *src_ptr) & reloc->howto->src_mask;
     433        bfd_put_32 (in_abfd, val, data + *dst_ptr);
     434        *dst_ptr += 4;
     435        *src_ptr += 4;
     436        break;
     437  
     438      case R_JR:
     439        {
     440  	if (reloc->howto->partial_inplace)
     441  	  val += (signed char) (bfd_get_8 (in_abfd, data + *src_ptr)
     442  				& reloc->howto->src_mask);
     443  	bfd_vma dot = (*dst_ptr
     444  		       + input_section->output_offset
     445  		       + input_section->output_section->vma);
     446  	bfd_signed_vma gap = val - dot;
     447  	if (gap >= 128 || gap < -128)
     448  	  {
     449  	    link_info->callbacks->reloc_overflow
     450  	      (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
     451  	       reloc->howto->name, reloc->addend, input_section->owner,
     452  	       input_section, reloc->address);
     453  	    return false;
     454  	  }
     455  
     456  	bfd_put_8 (in_abfd, gap, data + *dst_ptr);
     457  	*dst_ptr += 1;
     458  	*src_ptr += 1;
     459  	break;
     460        }
     461  
     462      case R_IMM16BE:
     463        if (reloc->howto->partial_inplace)
     464  	val += ((bfd_get_8 (in_abfd, data + *src_ptr + 0) * 0x100
     465  		 + bfd_get_8 (in_abfd, data + *src_ptr + 1))
     466  		& reloc->howto->src_mask);
     467        
     468        bfd_put_8 (in_abfd, val >> 8, data + *dst_ptr + 0);
     469        bfd_put_8 (in_abfd, val, data + *dst_ptr + 1);
     470        *dst_ptr += 2;
     471        *src_ptr += 2;
     472        break;
     473  
     474      default:
     475        link_info->callbacks->einfo
     476  	/* xgettext:c-format */
     477  	(_("%X%P: %pB(%pA): relocation \"%pR\" is not supported\n"),
     478  	 in_abfd, input_section, reloc);
     479        return false;
     480      }
     481    return true;
     482  }
     483  
     484  static bool
     485  z80_is_local_label_name (bfd *        abfd ATTRIBUTE_UNUSED,
     486                           const char * name)
     487  {
     488    return (name[0] == '.' && name[1] == 'L') ||
     489           _bfd_coff_is_local_label_name (abfd, name);
     490  }
     491  
     492  #define coff_bfd_is_local_label_name z80_is_local_label_name
     493  
     494  #define coff_reloc16_extra_cases    extra_case
     495  #define coff_bfd_reloc_type_lookup  coff_z80_reloc_type_lookup
     496  #define coff_bfd_reloc_name_lookup coff_z80_reloc_name_lookup
     497  
     498  #ifndef bfd_pe_print_pdata
     499  #define bfd_pe_print_pdata	NULL
     500  #endif
     501  
     502  #include "coffcode.h"
     503  
     504  #undef  coff_bfd_get_relocated_section_contents
     505  #define coff_bfd_get_relocated_section_contents \
     506    bfd_coff_reloc16_get_relocated_section_contents
     507  
     508  #undef  coff_bfd_relax_section
     509  #define coff_bfd_relax_section bfd_coff_reloc16_relax_section
     510  
     511  CREATE_LITTLE_COFF_TARGET_VEC (z80_coff_vec, "coff-z80", 0,
     512  			       SEC_CODE | SEC_DATA, '\0', NULL,
     513  			       COFF_SWAP_TABLE)
     514