xref: /netbsd-src/external/gpl3/binutils.old/dist/bfd/coff-z80.c (revision e992f068c547fd6e84b3f104dc2340adcc955732)
1 /* BFD back-end for Zilog Z80 COFF binaries.
2    Copyright (C) 2005-2022 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
rtype2howto(arelent * internal,struct internal_reloc * dst)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 *
coff_z80_reloc_type_lookup(bfd * abfd ATTRIBUTE_UNUSED,bfd_reloc_code_real_type code)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 *
coff_z80_reloc_name_lookup(bfd * abfd ATTRIBUTE_UNUSED,const char * r_name)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
reloc_processing(arelent * relent,struct internal_reloc * reloc,asymbol ** symbols,bfd * abfd,asection * section)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)
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 void
extra_case(bfd * in_abfd,struct bfd_link_info * link_info,struct bfd_link_order * link_order,arelent * reloc,bfd_byte * data,unsigned int * src_ptr,unsigned int * dst_ptr)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 	    unsigned int *src_ptr,
340 	    unsigned int *dst_ptr)
341 {
342   asection * input_section = link_order->u.indirect.section;
343   int val = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
344 
345   switch (reloc->howto->type)
346     {
347     case R_OFF8:
348       if (reloc->howto->partial_inplace)
349         val += (signed char)(bfd_get_8 ( in_abfd, data+*src_ptr)
350                              & reloc->howto->src_mask);
351       if (val>127 || val<-128) /* Test for overflow.  */
352 	  (*link_info->callbacks->reloc_overflow)
353 	    (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
354 	     reloc->howto->name, reloc->addend, input_section->owner,
355 	     input_section, reloc->address);
356 
357 	bfd_put_8 (in_abfd, val, data + *dst_ptr);
358 	(*dst_ptr) += 1;
359 	(*src_ptr) += 1;
360       break;
361 
362     case R_BYTE3:
363       bfd_put_8 (in_abfd, val >> 24, data + *dst_ptr);
364       (*dst_ptr) += 1;
365       (*src_ptr) += 1;
366       break;
367 
368     case R_BYTE2:
369       bfd_put_8 (in_abfd, val >> 16, data + *dst_ptr);
370       (*dst_ptr) += 1;
371       (*src_ptr) += 1;
372       break;
373 
374     case R_BYTE1:
375       bfd_put_8 (in_abfd, val >> 8, data + *dst_ptr);
376       (*dst_ptr) += 1;
377       (*src_ptr) += 1;
378       break;
379 
380     case R_IMM8:
381       if (reloc->howto->partial_inplace)
382         val += bfd_get_8 ( in_abfd, data+*src_ptr) & reloc->howto->src_mask;
383       /* Fall through.  */
384     case R_BYTE0:
385       bfd_put_8 (in_abfd, val, data + *dst_ptr);
386       (*dst_ptr) += 1;
387       (*src_ptr) += 1;
388       break;
389 
390     case R_WORD1:
391       bfd_put_16 (in_abfd, val >> 16, data + *dst_ptr);
392       (*dst_ptr) += 2;
393       (*src_ptr) += 2;
394       break;
395 
396     case R_IMM16:
397       if (reloc->howto->partial_inplace)
398         val += bfd_get_16 ( in_abfd, data+*src_ptr) & reloc->howto->src_mask;
399       /* Fall through.  */
400     case R_WORD0:
401       bfd_put_16 (in_abfd, val, data + *dst_ptr);
402       (*dst_ptr) += 2;
403       (*src_ptr) += 2;
404       break;
405 
406     case R_IMM24:
407       if (reloc->howto->partial_inplace)
408 	val += (bfd_get_24 (in_abfd, data + *src_ptr)
409 		& reloc->howto->src_mask);
410       bfd_put_24 (in_abfd, val, data + *dst_ptr);
411       (*dst_ptr) += 3;
412       (*src_ptr) += 3;
413       break;
414 
415     case R_IMM32:
416       if (reloc->howto->partial_inplace)
417         val += bfd_get_32 ( in_abfd, data+*src_ptr) & reloc->howto->src_mask;
418       bfd_put_32 (in_abfd, val, data + *dst_ptr);
419       (*dst_ptr) += 4;
420       (*src_ptr) += 4;
421       break;
422 
423     case R_JR:
424       {
425         if (reloc->howto->partial_inplace)
426           val += (signed char)(bfd_get_8 ( in_abfd, data+*src_ptr)
427                                & reloc->howto->src_mask);
428 	bfd_vma dot = (*dst_ptr
429 		       + input_section->output_offset
430 		       + input_section->output_section->vma);
431 	int gap = val - dot;
432 	if (gap >= 128 || gap < -128)
433 	  (*link_info->callbacks->reloc_overflow)
434 	    (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
435 	     reloc->howto->name, reloc->addend, input_section->owner,
436 	     input_section, reloc->address);
437 
438 	bfd_put_8 (in_abfd, gap, data + *dst_ptr);
439 	(*dst_ptr)++;
440 	(*src_ptr)++;
441 	break;
442       }
443 
444     case R_IMM16BE:
445       if (reloc->howto->partial_inplace)
446 	val += (bfd_get_8 ( in_abfd, data+*src_ptr+0) * 0x100 +
447 		bfd_get_8 ( in_abfd, data+*src_ptr+1)) & reloc->howto->src_mask;
448 
449       bfd_put_8 (in_abfd, val >> 8, data + *dst_ptr+0);
450       bfd_put_8 (in_abfd, val, data + *dst_ptr+1);
451       (*dst_ptr) += 2;
452       (*src_ptr) += 2;
453       break;
454 
455     default:
456       abort ();
457     }
458 }
459 
460 static bool
z80_is_local_label_name(bfd * abfd ATTRIBUTE_UNUSED,const char * name)461 z80_is_local_label_name (bfd *        abfd ATTRIBUTE_UNUSED,
462                          const char * name)
463 {
464   return (name[0] == '.' && name[1] == 'L') ||
465          _bfd_coff_is_local_label_name (abfd, name);
466 }
467 
468 #define coff_bfd_is_local_label_name z80_is_local_label_name
469 
470 #define coff_reloc16_extra_cases    extra_case
471 #define coff_bfd_reloc_type_lookup  coff_z80_reloc_type_lookup
472 #define coff_bfd_reloc_name_lookup coff_z80_reloc_name_lookup
473 
474 #ifndef bfd_pe_print_pdata
475 #define bfd_pe_print_pdata	NULL
476 #endif
477 
478 #include "coffcode.h"
479 
480 #undef  coff_bfd_get_relocated_section_contents
481 #define coff_bfd_get_relocated_section_contents \
482   bfd_coff_reloc16_get_relocated_section_contents
483 
484 #undef  coff_bfd_relax_section
485 #define coff_bfd_relax_section bfd_coff_reloc16_relax_section
486 
487 CREATE_LITTLE_COFF_TARGET_VEC (z80_coff_vec, "coff-z80", 0,
488 			       SEC_CODE | SEC_DATA, '\0', NULL,
489 			       COFF_SWAP_TABLE)
490 
491