]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - bfd/coff-z80.c
Add support for the GBZ80, Z180, and eZ80 variants of the Z80 architecure. Add an...
[thirdparty/binutils-gdb.git] / bfd / coff-z80.c
CommitLineData
3c9b82ba 1/* BFD back-end for Zilog Z80 COFF binaries.
b3adc24a 2 Copyright (C) 2005-2020 Free Software Foundation, Inc.
3c9b82ba
NC
3 Contributed by Arnold Metselaar <arnold_m@operamail.com>
4
5 This file is part of BFD, the Binary File Descriptor library.
6
68ffbac6 7 This program is free software; you can redistribute it and/or modify
3c9b82ba 8 it under the terms of the GNU General Public License as published by
cd123cb7 9 the Free Software Foundation; either version 3 of the License, or
3c9b82ba
NC
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
3c9b82ba 22#include "sysdep.h"
3db64b00 23#include "bfd.h"
3c9b82ba
NC
24#include "libbfd.h"
25#include "bfdlink.h"
26#include "coff/z80.h"
27#include "coff/internal.h"
28#include "libcoff.h"
6655dba2 29#include "libiberty.h"
3c9b82ba
NC
30
31#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER 0
32
6655dba2
SB
33typedef struct {
34 bfd_reloc_code_real_type r_type;
35 reloc_howto_type howto;
36} bfd_howto_type;
3c9b82ba 37
6655dba2
SB
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)}
3c9b82ba 40
6655dba2
SB
41static 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)
3c9b82ba
NC
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. */
3c9b82ba
NC
242static void
243rtype2howto (arelent *internal, struct internal_reloc *dst)
244{
6655dba2
SB
245 unsigned i;
246 for (i = 0; i < NUM_HOWTOS; i++)
3c9b82ba 247 {
6655dba2
SB
248 if (howto_table[i].howto.type == dst->r_type)
249 {
250 internal->howto = &howto_table[i].howto;
251 return;
252 }
3c9b82ba 253 }
6655dba2 254 internal->howto = NULL;
3c9b82ba
NC
255}
256
257#define RTYPE2HOWTO(internal, relocentry) rtype2howto (internal, relocentry)
258
259static reloc_howto_type *
260coff_z80_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
261 bfd_reloc_code_real_type code)
262{
6655dba2
SB
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;
3c9b82ba
NC
270}
271
157090f7
AM
272static reloc_howto_type *
273coff_z80_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
274 const char *r_name)
275{
6655dba2
SB
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;
157090f7
AM
280
281 return NULL;
282}
283
3c9b82ba
NC
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
292static void
293reloc_processing (arelent *relent,
07d6d2b8
AM
294 struct internal_reloc *reloc,
295 asymbol **symbols,
296 bfd *abfd,
297 asection *section)
3c9b82ba
NC
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
311static void
312extra_case (bfd *in_abfd,
07d6d2b8
AM
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)
3c9b82ba
NC
319{
320 asection * input_section = link_order->u.indirect.section;
6655dba2 321 int val = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
3c9b82ba
NC
322
323 switch (reloc->howto->type)
324 {
325 case R_OFF8:
6655dba2
SB
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. */
1a72702b
AM
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
3c9b82ba
NC
335 bfd_put_8 (in_abfd, val, data + *dst_ptr);
336 (*dst_ptr) += 1;
337 (*src_ptr) += 1;
338 break;
339
6655dba2
SB
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
3c9b82ba 358 case R_IMM8:
6655dba2
SB
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:
3c9b82ba
NC
363 bfd_put_8 (in_abfd, val, data + *dst_ptr);
364 (*dst_ptr) += 1;
365 (*src_ptr) += 1;
366 break;
367
6655dba2
SB
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
3c9b82ba 374 case R_IMM16:
6655dba2
SB
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:
3c9b82ba
NC
379 bfd_put_16 (in_abfd, val, data + *dst_ptr);
380 (*dst_ptr) += 2;
381 (*src_ptr) += 2;
382 break;
383
134dcee5 384 case R_IMM24:
6655dba2
SB
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;
134dcee5
AM
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
3c9b82ba 395 case R_IMM32:
6655dba2
SB
396 if (reloc->howto->partial_inplace)
397 val += bfd_get_32 ( in_abfd, data+*src_ptr) & reloc->howto->src_mask;
3c9b82ba
NC
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 {
6655dba2
SB
405 if (reloc->howto->partial_inplace)
406 val += (signed char)(bfd_get_8 ( in_abfd, data+*src_ptr)
407 & reloc->howto->src_mask);
44da2da1
AM
408 bfd_vma dot = (*dst_ptr
409 + input_section->output_offset
3c9b82ba 410 + input_section->output_section->vma);
6655dba2 411 int gap = val - dot;
3c9b82ba 412 if (gap >= 128 || gap < -128)
1a72702b
AM
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
3c9b82ba
NC
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
6655dba2
SB
429static int
430z80_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
3c9b82ba
NC
439#define coff_reloc16_extra_cases extra_case
440#define coff_bfd_reloc_type_lookup coff_z80_reloc_type_lookup
157090f7 441#define coff_bfd_reloc_name_lookup coff_z80_reloc_name_lookup
3c9b82ba 442
2b5c217d
NC
443#ifndef bfd_pe_print_pdata
444#define bfd_pe_print_pdata NULL
445#endif
446
3c9b82ba
NC
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
6d00b590 456CREATE_LITTLE_COFF_TARGET_VEC (z80_coff_vec, "coff-z80", 0,
68ffbac6 457 SEC_CODE | SEC_DATA, '\0', NULL,
3c9b82ba
NC
458 COFF_SWAP_TABLE)
459