Home | History | Annotate | Line # | Download | only in bfd
coff-z80.c revision 1.1
      1  1.1  skrll /* BFD back-end for Zilog Z80 COFF binaries.
      2  1.1  skrll    Copyright 2005, 2007, 2008  Free Software Foundation, Inc.
      3  1.1  skrll    Contributed by Arnold Metselaar <arnold_m (at) operamail.com>
      4  1.1  skrll 
      5  1.1  skrll    This file is part of BFD, the Binary File Descriptor library.
      6  1.1  skrll 
      7  1.1  skrll    This program is free software; you can redistribute it and/or modify
      8  1.1  skrll    it under the terms of the GNU General Public License as published by
      9  1.1  skrll    the Free Software Foundation; either version 3 of the License, or
     10  1.1  skrll    (at your option) any later version.
     11  1.1  skrll 
     12  1.1  skrll    This program is distributed in the hope that it will be useful,
     13  1.1  skrll    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  1.1  skrll    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15  1.1  skrll    GNU General Public License for more details.
     16  1.1  skrll 
     17  1.1  skrll    You should have received a copy of the GNU General Public License
     18  1.1  skrll    along with this program; if not, write to the Free Software
     19  1.1  skrll    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     20  1.1  skrll    MA 02110-1301, USA.  */
     21  1.1  skrll 
     22  1.1  skrll #include "sysdep.h"
     23  1.1  skrll #include "bfd.h"
     24  1.1  skrll #include "libbfd.h"
     25  1.1  skrll #include "bfdlink.h"
     26  1.1  skrll #include "coff/z80.h"
     27  1.1  skrll #include "coff/internal.h"
     28  1.1  skrll #include "libcoff.h"
     29  1.1  skrll 
     30  1.1  skrll #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER 0
     31  1.1  skrll 
     32  1.1  skrll static reloc_howto_type r_imm32 =
     33  1.1  skrll HOWTO (R_IMM32, 0, 1, 32, FALSE, 0,
     34  1.1  skrll        complain_overflow_dont, 0, "r_imm32", TRUE, 0xffffffff, 0xffffffff,
     35  1.1  skrll        FALSE);
     36  1.1  skrll 
     37  1.1  skrll static reloc_howto_type r_imm24 =
     38  1.1  skrll HOWTO (R_IMM24, 0, 1, 24, FALSE, 0,
     39  1.1  skrll        complain_overflow_dont, 0, "r_imm24", TRUE, 0x00ffffff, 0x00ffffff,
     40  1.1  skrll        FALSE);
     41  1.1  skrll 
     42  1.1  skrll static reloc_howto_type r_imm16 =
     43  1.1  skrll HOWTO (R_IMM16, 0, 1, 16, FALSE, 0,
     44  1.1  skrll        complain_overflow_dont, 0, "r_imm16", TRUE, 0x0000ffff, 0x0000ffff,
     45  1.1  skrll        FALSE);
     46  1.1  skrll 
     47  1.1  skrll static reloc_howto_type r_imm8 =
     48  1.1  skrll HOWTO (R_IMM8, 0, 0, 8, FALSE, 0,
     49  1.1  skrll        complain_overflow_bitfield, 0, "r_imm8", TRUE, 0x000000ff, 0x000000ff,
     50  1.1  skrll        FALSE);
     51  1.1  skrll 
     52  1.1  skrll static reloc_howto_type r_jr =
     53  1.1  skrll HOWTO (R_JR, 0, 0, 8, TRUE, 0,
     54  1.1  skrll        complain_overflow_signed, 0, "r_jr", FALSE, 0, 0xFF,
     55  1.1  skrll        FALSE);
     56  1.1  skrll 
     57  1.1  skrll static reloc_howto_type r_off8 =
     58  1.1  skrll HOWTO (R_OFF8, 0, 0, 8, FALSE, 0,
     59  1.1  skrll        complain_overflow_signed, 0,"r_off8", FALSE, 0, 0xff,
     60  1.1  skrll        FALSE);
     61  1.1  skrll 
     62  1.1  skrll 
     63  1.1  skrll #define BADMAG(x) Z80BADMAG(x)
     64  1.1  skrll #define Z80 1			/* Customize coffcode.h.  */
     65  1.1  skrll #define __A_MAGIC_SET__
     66  1.1  skrll 
     67  1.1  skrll /* Code to swap in the reloc.  */
     68  1.1  skrll 
     69  1.1  skrll #define SWAP_IN_RELOC_OFFSET	H_GET_32
     70  1.1  skrll #define SWAP_OUT_RELOC_OFFSET	H_PUT_32
     71  1.1  skrll 
     72  1.1  skrll #define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \
     73  1.1  skrll   dst->r_stuff[0] = 'S'; \
     74  1.1  skrll   dst->r_stuff[1] = 'C';
     75  1.1  skrll 
     76  1.1  skrll /* Code to turn a r_type into a howto ptr, uses the above howto table.  */
     77  1.1  skrll 
     78  1.1  skrll static void
     79  1.1  skrll rtype2howto (arelent *internal, struct internal_reloc *dst)
     80  1.1  skrll {
     81  1.1  skrll   switch (dst->r_type)
     82  1.1  skrll     {
     83  1.1  skrll     default:
     84  1.1  skrll       abort ();
     85  1.1  skrll       break;
     86  1.1  skrll     case R_IMM8:
     87  1.1  skrll       internal->howto = &r_imm8;
     88  1.1  skrll       break;
     89  1.1  skrll     case R_IMM16:
     90  1.1  skrll       internal->howto = &r_imm16;
     91  1.1  skrll       break;
     92  1.1  skrll     case R_IMM24:
     93  1.1  skrll       internal->howto = &r_imm24;
     94  1.1  skrll       break;
     95  1.1  skrll     case R_IMM32:
     96  1.1  skrll       internal->howto = &r_imm32;
     97  1.1  skrll       break;
     98  1.1  skrll     case R_JR:
     99  1.1  skrll       internal->howto = &r_jr;
    100  1.1  skrll       break;
    101  1.1  skrll     case R_OFF8:
    102  1.1  skrll       internal->howto = &r_off8;
    103  1.1  skrll       break;
    104  1.1  skrll     }
    105  1.1  skrll }
    106  1.1  skrll 
    107  1.1  skrll #define RTYPE2HOWTO(internal, relocentry) rtype2howto (internal, relocentry)
    108  1.1  skrll 
    109  1.1  skrll static reloc_howto_type *
    110  1.1  skrll coff_z80_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
    111  1.1  skrll 			    bfd_reloc_code_real_type code)
    112  1.1  skrll {
    113  1.1  skrll   switch (code)
    114  1.1  skrll     {
    115  1.1  skrll     case BFD_RELOC_8:		return & r_imm8;
    116  1.1  skrll     case BFD_RELOC_16:		return & r_imm16;
    117  1.1  skrll     case BFD_RELOC_24:		return & r_imm24;
    118  1.1  skrll     case BFD_RELOC_32:		return & r_imm32;
    119  1.1  skrll     case BFD_RELOC_8_PCREL:	return & r_jr;
    120  1.1  skrll     case BFD_RELOC_Z80_DISP8:	return & r_off8;
    121  1.1  skrll     default:			BFD_FAIL ();
    122  1.1  skrll       return NULL;
    123  1.1  skrll     }
    124  1.1  skrll }
    125  1.1  skrll 
    126  1.1  skrll static reloc_howto_type *
    127  1.1  skrll coff_z80_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
    128  1.1  skrll 			    const char *r_name)
    129  1.1  skrll {
    130  1.1  skrll   if (strcasecmp (r_imm8.name, r_name) == 0)
    131  1.1  skrll     return &r_imm8;
    132  1.1  skrll   if (strcasecmp (r_imm16.name, r_name) == 0)
    133  1.1  skrll     return &r_imm16;
    134  1.1  skrll   if (strcasecmp (r_imm24.name, r_name) == 0)
    135  1.1  skrll     return &r_imm24;
    136  1.1  skrll   if (strcasecmp (r_imm32.name, r_name) == 0)
    137  1.1  skrll     return &r_imm32;
    138  1.1  skrll   if (strcasecmp (r_jr.name, r_name) == 0)
    139  1.1  skrll     return &r_jr;
    140  1.1  skrll   if (strcasecmp (r_off8.name, r_name) == 0)
    141  1.1  skrll     return &r_off8;
    142  1.1  skrll 
    143  1.1  skrll   return NULL;
    144  1.1  skrll }
    145  1.1  skrll 
    146  1.1  skrll /* Perform any necessary magic to the addend in a reloc entry.  */
    147  1.1  skrll 
    148  1.1  skrll #define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \
    149  1.1  skrll  cache_ptr->addend =  ext_reloc.r_offset;
    150  1.1  skrll 
    151  1.1  skrll #define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \
    152  1.1  skrll  reloc_processing(relent, reloc, symbols, abfd, section)
    153  1.1  skrll 
    154  1.1  skrll static void
    155  1.1  skrll reloc_processing (arelent *relent,
    156  1.1  skrll                   struct internal_reloc *reloc,
    157  1.1  skrll                   asymbol **symbols,
    158  1.1  skrll                   bfd *abfd,
    159  1.1  skrll                   asection *section)
    160  1.1  skrll {
    161  1.1  skrll   relent->address = reloc->r_vaddr;
    162  1.1  skrll   rtype2howto (relent, reloc);
    163  1.1  skrll 
    164  1.1  skrll   if (reloc->r_symndx > 0)
    165  1.1  skrll     relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx];
    166  1.1  skrll   else
    167  1.1  skrll     relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
    168  1.1  skrll 
    169  1.1  skrll   relent->addend = reloc->r_offset;
    170  1.1  skrll   relent->address -= section->vma;
    171  1.1  skrll }
    172  1.1  skrll 
    173  1.1  skrll static void
    174  1.1  skrll extra_case (bfd *in_abfd,
    175  1.1  skrll             struct bfd_link_info *link_info,
    176  1.1  skrll             struct bfd_link_order *link_order,
    177  1.1  skrll             arelent *reloc,
    178  1.1  skrll             bfd_byte *data,
    179  1.1  skrll             unsigned int *src_ptr,
    180  1.1  skrll             unsigned int *dst_ptr)
    181  1.1  skrll {
    182  1.1  skrll   asection * input_section = link_order->u.indirect.section;
    183  1.1  skrll   int val;
    184  1.1  skrll 
    185  1.1  skrll   switch (reloc->howto->type)
    186  1.1  skrll     {
    187  1.1  skrll     case R_OFF8:
    188  1.1  skrll 	val = bfd_coff_reloc16_get_value (reloc, link_info,
    189  1.1  skrll 					   input_section);
    190  1.1  skrll 	if (val>127 || val<-128) /* Test for overflow.  */
    191  1.1  skrll 	  {
    192  1.1  skrll 	    if (! ((*link_info->callbacks->reloc_overflow)
    193  1.1  skrll 		   (link_info, NULL,
    194  1.1  skrll 		    bfd_asymbol_name (*reloc->sym_ptr_ptr),
    195  1.1  skrll 		    reloc->howto->name, reloc->addend, input_section->owner,
    196  1.1  skrll 		    input_section, reloc->address)))
    197  1.1  skrll 	      abort ();
    198  1.1  skrll 	  }
    199  1.1  skrll 	bfd_put_8 (in_abfd, val, data + *dst_ptr);
    200  1.1  skrll 	(*dst_ptr) += 1;
    201  1.1  skrll 	(*src_ptr) += 1;
    202  1.1  skrll       break;
    203  1.1  skrll 
    204  1.1  skrll     case R_IMM8:
    205  1.1  skrll       val = bfd_get_8 ( in_abfd, data+*src_ptr)
    206  1.1  skrll 	+ bfd_coff_reloc16_get_value (reloc, link_info, input_section);
    207  1.1  skrll       bfd_put_8 (in_abfd, val, data + *dst_ptr);
    208  1.1  skrll       (*dst_ptr) += 1;
    209  1.1  skrll       (*src_ptr) += 1;
    210  1.1  skrll       break;
    211  1.1  skrll 
    212  1.1  skrll     case R_IMM16:
    213  1.1  skrll       val = bfd_get_16 ( in_abfd, data+*src_ptr)
    214  1.1  skrll 	+ bfd_coff_reloc16_get_value (reloc, link_info, input_section);
    215  1.1  skrll       bfd_put_16 (in_abfd, val, data + *dst_ptr);
    216  1.1  skrll       (*dst_ptr) += 2;
    217  1.1  skrll       (*src_ptr) += 2;
    218  1.1  skrll       break;
    219  1.1  skrll 
    220  1.1  skrll     case R_IMM24:
    221  1.1  skrll       val = bfd_get_16 ( in_abfd, data+*src_ptr)
    222  1.1  skrll 	+ (bfd_get_8 ( in_abfd, data+*src_ptr+2) << 16)
    223  1.1  skrll 	+ bfd_coff_reloc16_get_value (reloc, link_info, input_section);
    224  1.1  skrll       bfd_put_16 (in_abfd, val, data + *dst_ptr);
    225  1.1  skrll       bfd_put_8 (in_abfd, val >> 16, data + *dst_ptr+2);
    226  1.1  skrll       (*dst_ptr) += 3;
    227  1.1  skrll       (*src_ptr) += 3;
    228  1.1  skrll       break;
    229  1.1  skrll 
    230  1.1  skrll     case R_IMM32:
    231  1.1  skrll       val = bfd_get_32 ( in_abfd, data+*src_ptr)
    232  1.1  skrll 	+ bfd_coff_reloc16_get_value (reloc, link_info, input_section);
    233  1.1  skrll       bfd_put_32 (in_abfd, val, data + *dst_ptr);
    234  1.1  skrll       (*dst_ptr) += 4;
    235  1.1  skrll       (*src_ptr) += 4;
    236  1.1  skrll       break;
    237  1.1  skrll 
    238  1.1  skrll     case R_JR:
    239  1.1  skrll       {
    240  1.1  skrll 	bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
    241  1.1  skrll 						  input_section);
    242  1.1  skrll 	bfd_vma dot = (*dst_ptr
    243  1.1  skrll 		       + input_section->output_offset
    244  1.1  skrll 		       + input_section->output_section->vma);
    245  1.1  skrll 	int gap = dst - dot - 1;  /* -1, Since the offset is relative
    246  1.1  skrll 				     to the value of PC after reading
    247  1.1  skrll 				     the offset.  */
    248  1.1  skrll 
    249  1.1  skrll 	if (gap >= 128 || gap < -128)
    250  1.1  skrll 	  {
    251  1.1  skrll 	    if (! ((*link_info->callbacks->reloc_overflow)
    252  1.1  skrll 		   (link_info, NULL,
    253  1.1  skrll 		    bfd_asymbol_name (*reloc->sym_ptr_ptr),
    254  1.1  skrll 		    reloc->howto->name, reloc->addend, input_section->owner,
    255  1.1  skrll 		    input_section, reloc->address)))
    256  1.1  skrll 	      abort ();
    257  1.1  skrll 	  }
    258  1.1  skrll 	bfd_put_8 (in_abfd, gap, data + *dst_ptr);
    259  1.1  skrll 	(*dst_ptr)++;
    260  1.1  skrll 	(*src_ptr)++;
    261  1.1  skrll 	break;
    262  1.1  skrll       }
    263  1.1  skrll 
    264  1.1  skrll     default:
    265  1.1  skrll       abort ();
    266  1.1  skrll     }
    267  1.1  skrll }
    268  1.1  skrll 
    269  1.1  skrll #define coff_reloc16_extra_cases    extra_case
    270  1.1  skrll #define coff_bfd_reloc_type_lookup  coff_z80_reloc_type_lookup
    271  1.1  skrll #define coff_bfd_reloc_name_lookup coff_z80_reloc_name_lookup
    272  1.1  skrll 
    273  1.1  skrll #ifndef bfd_pe_print_pdata
    274  1.1  skrll #define bfd_pe_print_pdata	NULL
    275  1.1  skrll #endif
    276  1.1  skrll 
    277  1.1  skrll #include "coffcode.h"
    278  1.1  skrll 
    279  1.1  skrll #undef  coff_bfd_get_relocated_section_contents
    280  1.1  skrll #define coff_bfd_get_relocated_section_contents \
    281  1.1  skrll   bfd_coff_reloc16_get_relocated_section_contents
    282  1.1  skrll 
    283  1.1  skrll #undef  coff_bfd_relax_section
    284  1.1  skrll #define coff_bfd_relax_section bfd_coff_reloc16_relax_section
    285  1.1  skrll 
    286  1.1  skrll CREATE_LITTLE_COFF_TARGET_VEC (z80coff_vec, "coff-z80", 0, 0, '\0', NULL,
    287  1.1  skrll 			       COFF_SWAP_TABLE)
    288  1.1  skrll 
    289