Home | History | Annotate | Line # | Download | only in bfd
coff-z80.c revision 1.1.1.7
      1 /* BFD back-end for Zilog Z80 COFF binaries.
      2    Copyright (C) 2005-2024 Free Software Foundation, Inc.
      3    Contributed by Arnold Metselaar <arnold_m (at) 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 
    515