]> Git Repo - binutils.git/blob - bfd/coff-z80.c
Add support for the GBZ80, Z180, and eZ80 variants of the Z80 architecure. Add an...
[binutils.git] / bfd / coff-z80.c
1 /* BFD back-end for Zilog Z80 COFF binaries.
2    Copyright (C) 2005-2020 Free Software Foundation, Inc.
3    Contributed by Arnold Metselaar <[email protected]>
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 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      2,                 /* size (0 = byte, 1 = short, 2 = long) */
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      1,                 /* size (0 = byte, 1 = short, 2 = long) */
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      1,                 /* size (0 = byte, 1 = short, 2 = long) */
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      0,                 /* size (0 = byte, 1 = short, 2 = long) */
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      0,                 /* size (0 = byte, 1 = short, 2 = long) */
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      0,                 /* size (0 = byte, 1 = short, 2 = long) */
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      0,                 /* size (0 = byte, 1 = short, 2 = long) */
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      0,                 /* size (0 = byte, 1 = short, 2 = long) */
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      0,                 /* size (0 = byte, 1 = short, 2 = long) */
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      0,                 /* size (0 = byte, 1 = short, 2 = long) */
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      0,                 /* size (0 = byte, 1 = short, 2 = long) */
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      0,                 /* size (0 = byte, 1 = short, 2 = long) */
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
226 #define NUM_HOWTOS ARRAY_SIZE (howto_table)
227
228 #define BADMAG(x) Z80BADMAG(x)
229 #define Z80 1                   /* Customize coffcode.h.  */
230 #define __A_MAGIC_SET__
231
232 /* Code to swap in the reloc.  */
233
234 #define SWAP_IN_RELOC_OFFSET    H_GET_32
235 #define SWAP_OUT_RELOC_OFFSET   H_PUT_32
236
237 #define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \
238   dst->r_stuff[0] = 'S'; \
239   dst->r_stuff[1] = 'C';
240
241 /* Code to turn a r_type into a howto ptr, uses the above howto table.  */
242 static void
243 rtype2howto (arelent *internal, struct internal_reloc *dst)
244 {
245   unsigned i;
246   for (i = 0; i < NUM_HOWTOS; i++)
247     {
248       if (howto_table[i].howto.type == dst->r_type)
249         {
250           internal->howto = &howto_table[i].howto;
251           return;
252         }
253     }
254   internal->howto = NULL;
255 }
256
257 #define RTYPE2HOWTO(internal, relocentry) rtype2howto (internal, relocentry)
258
259 static reloc_howto_type *
260 coff_z80_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
261                             bfd_reloc_code_real_type code)
262 {
263   unsigned i;
264   for (i = 0; i < NUM_HOWTOS; i++)
265     if (howto_table[i].r_type == code)
266       return &howto_table[i].howto;
267
268   BFD_FAIL ();
269   return NULL;
270 }
271
272 static reloc_howto_type *
273 coff_z80_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
274                             const char *r_name)
275 {
276   unsigned i;
277   for (i = 0; i < NUM_HOWTOS; i++)
278     if (strcasecmp(howto_table[i].howto.name, r_name) == 0)
279       return &howto_table[i].howto;
280
281   return NULL;
282 }
283
284 /* Perform any necessary magic to the addend in a reloc entry.  */
285
286 #define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \
287  cache_ptr->addend =  ext_reloc.r_offset;
288
289 #define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \
290  reloc_processing(relent, reloc, symbols, abfd, section)
291
292 static void
293 reloc_processing (arelent *relent,
294                   struct internal_reloc *reloc,
295                   asymbol **symbols,
296                   bfd *abfd,
297                   asection *section)
298 {
299   relent->address = reloc->r_vaddr;
300   rtype2howto (relent, reloc);
301
302   if (reloc->r_symndx > 0)
303     relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx];
304   else
305     relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
306
307   relent->addend = reloc->r_offset;
308   relent->address -= section->vma;
309 }
310
311 static void
312 extra_case (bfd *in_abfd,
313             struct bfd_link_info *link_info,
314             struct bfd_link_order *link_order,
315             arelent *reloc,
316             bfd_byte *data,
317             unsigned int *src_ptr,
318             unsigned int *dst_ptr)
319 {
320   asection * input_section = link_order->u.indirect.section;
321   int val = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
322
323   switch (reloc->howto->type)
324     {
325     case R_OFF8:
326       if (reloc->howto->partial_inplace)
327         val += (signed char)(bfd_get_8 ( in_abfd, data+*src_ptr)
328                              & reloc->howto->src_mask);
329       if (val>127 || val<-128) /* Test for overflow.  */
330           (*link_info->callbacks->reloc_overflow)
331             (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
332              reloc->howto->name, reloc->addend, input_section->owner,
333              input_section, reloc->address);
334
335         bfd_put_8 (in_abfd, val, data + *dst_ptr);
336         (*dst_ptr) += 1;
337         (*src_ptr) += 1;
338       break;
339
340     case R_BYTE3:
341       bfd_put_8 (in_abfd, val >> 24, data + *dst_ptr);
342       (*dst_ptr) += 1;
343       (*src_ptr) += 1;
344       break;
345
346     case R_BYTE2:
347       bfd_put_8 (in_abfd, val >> 16, data + *dst_ptr);
348       (*dst_ptr) += 1;
349       (*src_ptr) += 1;
350       break;
351
352     case R_BYTE1:
353       bfd_put_8 (in_abfd, val >> 8, data + *dst_ptr);
354       (*dst_ptr) += 1;
355       (*src_ptr) += 1;
356       break;
357
358     case R_IMM8:
359       if (reloc->howto->partial_inplace)
360         val += bfd_get_8 ( in_abfd, data+*src_ptr) & reloc->howto->src_mask;
361       //fallthrough
362     case R_BYTE0:
363       bfd_put_8 (in_abfd, val, data + *dst_ptr);
364       (*dst_ptr) += 1;
365       (*src_ptr) += 1;
366       break;
367
368     case R_WORD1:
369       bfd_put_16 (in_abfd, val >> 16, data + *dst_ptr);
370       (*dst_ptr) += 2;
371       (*src_ptr) += 2;
372       break;
373
374     case R_IMM16:
375       if (reloc->howto->partial_inplace)
376         val += bfd_get_16 ( in_abfd, data+*src_ptr) & reloc->howto->src_mask;
377       //fallthrough
378     case R_WORD0:
379       bfd_put_16 (in_abfd, val, data + *dst_ptr);
380       (*dst_ptr) += 2;
381       (*src_ptr) += 2;
382       break;
383
384     case R_IMM24:
385       if (reloc->howto->partial_inplace)
386         val += (bfd_get_16 ( in_abfd, data+*src_ptr)
387             + (bfd_get_8 ( in_abfd, data+*src_ptr+2) << 16))
388             & reloc->howto->src_mask;
389       bfd_put_16 (in_abfd, val, data + *dst_ptr);
390       bfd_put_8 (in_abfd, val >> 16, data + *dst_ptr+2);
391       (*dst_ptr) += 3;
392       (*src_ptr) += 3;
393       break;
394
395     case R_IMM32:
396       if (reloc->howto->partial_inplace)
397         val += bfd_get_32 ( in_abfd, data+*src_ptr) & reloc->howto->src_mask;
398       bfd_put_32 (in_abfd, val, data + *dst_ptr);
399       (*dst_ptr) += 4;
400       (*src_ptr) += 4;
401       break;
402
403     case R_JR:
404       {
405         if (reloc->howto->partial_inplace)
406           val += (signed char)(bfd_get_8 ( in_abfd, data+*src_ptr) 
407                                & reloc->howto->src_mask);
408         bfd_vma dot = (*dst_ptr
409                        + input_section->output_offset
410                        + input_section->output_section->vma);
411         int gap = val - dot;
412         if (gap >= 128 || gap < -128)
413           (*link_info->callbacks->reloc_overflow)
414             (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
415              reloc->howto->name, reloc->addend, input_section->owner,
416              input_section, reloc->address);
417
418         bfd_put_8 (in_abfd, gap, data + *dst_ptr);
419         (*dst_ptr)++;
420         (*src_ptr)++;
421         break;
422       }
423
424     default:
425       abort ();
426     }
427 }
428
429 static int
430 z80_is_local_label_name (bfd *        abfd ATTRIBUTE_UNUSED,
431                          const char * name)
432 {
433   return (name[0] == '.' && name[1] == 'L') ||
434          _bfd_coff_is_local_label_name (abfd, name);
435 }
436
437 #define coff_bfd_is_local_label_name z80_is_local_label_name
438
439 #define coff_reloc16_extra_cases    extra_case
440 #define coff_bfd_reloc_type_lookup  coff_z80_reloc_type_lookup
441 #define coff_bfd_reloc_name_lookup coff_z80_reloc_name_lookup
442
443 #ifndef bfd_pe_print_pdata
444 #define bfd_pe_print_pdata      NULL
445 #endif
446
447 #include "coffcode.h"
448
449 #undef  coff_bfd_get_relocated_section_contents
450 #define coff_bfd_get_relocated_section_contents \
451   bfd_coff_reloc16_get_relocated_section_contents
452
453 #undef  coff_bfd_relax_section
454 #define coff_bfd_relax_section bfd_coff_reloc16_relax_section
455
456 CREATE_LITTLE_COFF_TARGET_VEC (z80_coff_vec, "coff-z80", 0,
457                                SEC_CODE | SEC_DATA, '\0', NULL,
458                                COFF_SWAP_TABLE)
459
This page took 0.052267 seconds and 4 git commands to generate.