xref: /netbsd-src/external/gpl3/binutils/dist/bfd/coff-z80.c (revision d536862b7d93d77932ef5de7eebdc48d76921b77)
1 /* BFD back-end for Zilog Z80 COFF binaries.
2    Copyright (C) 2005-2020 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 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 
460