]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - bfd/coff-z80.c
Automatic date update in version.in
[thirdparty/binutils-gdb.git] / bfd / coff-z80.c
CommitLineData
3c9b82ba 1/* BFD back-end for Zilog Z80 COFF binaries.
fd67aa11 2 Copyright (C) 2005-2024 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
bd38246a 33typedef const struct {
6655dba2
SB
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 */
c94cb026 48 4, /* size */
6655dba2 49 32, /* bitsize */
0a1b45a2 50 false, /* pc_relative */
6655dba2
SB
51 0, /* bitpos */
52 complain_overflow_bitfield, /* complain_on_overflow */
53 0, /* special_function */
54 "r_imm32", /* name */
0a1b45a2 55 false, /* partial_inplace */
6655dba2
SB
56 0xffffffff, /* src_mask */
57 0xffffffff, /* dst_mask */
0a1b45a2 58 false), /* pcrel_offset */
6655dba2
SB
59
60 BFD_HOWTO (BFD_RELOC_24,
61 R_IMM24, /* type */
62 0, /* rightshift */
c94cb026 63 3, /* size */
6655dba2 64 24, /* bitsize */
0a1b45a2 65 false, /* pc_relative */
6655dba2
SB
66 0, /* bitpos */
67 complain_overflow_bitfield, /* complain_on_overflow */
68 0, /* special_function */
69 "r_imm24", /* name */
0a1b45a2 70 false, /* partial_inplace */
6655dba2
SB
71 0x00ffffff, /* src_mask */
72 0x00ffffff, /* dst_mask */
0a1b45a2 73 false), /* pcrel_offset */
6655dba2
SB
74
75 BFD_HOWTO (BFD_RELOC_16,
76 R_IMM16, /* type */
77 0, /* rightshift */
c94cb026 78 2, /* size */
6655dba2 79 16, /* bitsize */
0a1b45a2 80 false, /* pc_relative */
6655dba2
SB
81 0, /* bitpos */
82 complain_overflow_bitfield, /* complain_on_overflow */
83 0, /* special_function */
84 "r_imm16", /* name */
0a1b45a2 85 false, /* partial_inplace */
6655dba2
SB
86 0x0000ffff, /* src_mask */
87 0x0000ffff, /* dst_mask */
0a1b45a2 88 false), /* pcrel_offset */
6655dba2
SB
89
90 BFD_HOWTO (BFD_RELOC_8,
91 R_IMM8, /* type */
92 0, /* rightshift */
c94cb026 93 1, /* size */
6655dba2 94 8, /* bitsize */
0a1b45a2 95 false, /* pc_relative */
6655dba2
SB
96 0, /* bitpos */
97 complain_overflow_bitfield, /* complain_on_overflow */
98 0, /* special_function */
99 "r_imm8", /* name */
0a1b45a2 100 false, /* partial_inplace */
6655dba2
SB
101 0x000000ff, /* src_mask */
102 0x000000ff, /* dst_mask */
0a1b45a2 103 false), /* pcrel_offset */
6655dba2
SB
104
105 BFD_HOWTO (BFD_RELOC_8_PCREL,
106 R_JR, /* type */
107 0, /* rightshift */
c94cb026 108 1, /* size */
6655dba2 109 8, /* bitsize */
0a1b45a2 110 true, /* pc_relative */
6655dba2
SB
111 0, /* bitpos */
112 complain_overflow_signed, /* complain_on_overflow */
113 0, /* special_function */
114 "r_jr", /* name */
0a1b45a2 115 false, /* partial_inplace */
6655dba2
SB
116 0, /* src_mask */
117 0xFF, /* dst_mask */
0a1b45a2 118 true), /* pcrel_offset */
6655dba2
SB
119
120 BFD_HOWTO (BFD_RELOC_Z80_DISP8,
121 R_OFF8, /* type */
122 0, /* rightshift */
c94cb026 123 1, /* size */
6655dba2 124 8, /* bitsize */
0a1b45a2 125 false, /* pc_relative */
6655dba2
SB
126 0, /* bitpos */
127 complain_overflow_signed, /* complain_on_overflow */
128 0, /* special_function */
129 "r_off8", /* name */
0a1b45a2 130 false, /* partial_inplace */
6655dba2
SB
131 0, /* src_mask */
132 0xff, /* dst_mask */
0a1b45a2 133 false), /* pcrel_offset */
6655dba2
SB
134
135 BFD_HOWTO (BFD_RELOC_Z80_BYTE0,
136 R_BYTE0, /* type */
137 0, /* rightshift */
c94cb026 138 1, /* size */
6655dba2 139 8, /* bitsize */
0a1b45a2 140 false, /* pc_relative */
6655dba2
SB
141 0, /* bitpos */
142 complain_overflow_dont, /* complain_on_overflow */
143 0, /* special_function */
144 "r_byte0", /* name */
0a1b45a2 145 false, /* partial_inplace */
6655dba2
SB
146 0, /* src_mask */
147 0xff, /* dst_mask */
0a1b45a2 148 false), /* pcrel_offset */
6655dba2
SB
149
150 BFD_HOWTO (BFD_RELOC_Z80_BYTE1,
151 R_BYTE1, /* type */
152 8, /* rightshift */
c94cb026 153 1, /* size */
6655dba2 154 8, /* bitsize */
0a1b45a2 155 false, /* pc_relative */
6655dba2
SB
156 0, /* bitpos */
157 complain_overflow_dont, /* complain_on_overflow */
158 0, /* special_function */
159 "r_byte1", /* name */
0a1b45a2 160 false, /* partial_inplace */
6655dba2
SB
161 0, /* src_mask */
162 0xff, /* dst_mask */
0a1b45a2 163 false), /* pcrel_offset */
6655dba2
SB
164
165 BFD_HOWTO (BFD_RELOC_Z80_BYTE2,
166 R_BYTE2, /* type */
167 16, /* rightshift */
c94cb026 168 1, /* size */
6655dba2 169 8, /* bitsize */
0a1b45a2 170 false, /* pc_relative */
6655dba2
SB
171 0, /* bitpos */
172 complain_overflow_dont, /* complain_on_overflow */
173 0, /* special_function */
174 "r_byte2", /* name */
0a1b45a2 175 false, /* partial_inplace */
6655dba2
SB
176 0, /* src_mask */
177 0xff, /* dst_mask */
0a1b45a2 178 false), /* pcrel_offset */
6655dba2
SB
179
180 BFD_HOWTO (BFD_RELOC_Z80_BYTE3,
181 R_BYTE3, /* type */
182 24, /* rightshift */
c94cb026 183 1, /* size */
6655dba2 184 8, /* bitsize */
0a1b45a2 185 false, /* pc_relative */
6655dba2
SB
186 0, /* bitpos */
187 complain_overflow_dont, /* complain_on_overflow */
188 0, /* special_function */
189 "r_byte3", /* name */
0a1b45a2 190 false, /* partial_inplace */
6655dba2
SB
191 0, /* src_mask */
192 0xff, /* dst_mask */
0a1b45a2 193 false), /* pcrel_offset */
6655dba2
SB
194
195 BFD_HOWTO (BFD_RELOC_Z80_WORD0,
196 R_WORD0, /* type */
197 0, /* rightshift */
c94cb026 198 2, /* size */
6655dba2 199 16, /* bitsize */
0a1b45a2 200 false, /* pc_relative */
6655dba2
SB
201 0, /* bitpos */
202 complain_overflow_dont, /* complain_on_overflow */
203 0, /* special_function */
204 "r_word0", /* name */
0a1b45a2 205 false, /* partial_inplace */
6655dba2
SB
206 0, /* src_mask */
207 0xffff, /* dst_mask */
0a1b45a2 208 false), /* pcrel_offset */
6655dba2
SB
209
210 BFD_HOWTO (BFD_RELOC_Z80_WORD1,
211 R_WORD1, /* type */
212 16, /* rightshift */
c94cb026 213 2, /* size */
6655dba2 214 16, /* bitsize */
0a1b45a2 215 false, /* pc_relative */
6655dba2
SB
216 0, /* bitpos */
217 complain_overflow_dont, /* complain_on_overflow */
218 0, /* special_function */
219 "r_word1", /* name */
0a1b45a2 220 false, /* partial_inplace */
6655dba2
SB
221 0, /* src_mask */
222 0xffff, /* dst_mask */
0a1b45a2 223 false), /* pcrel_offset */
9fc0b501
SB
224
225 BFD_HOWTO (BFD_RELOC_Z80_16_BE,
226 R_IMM16BE, /* type */
227 0, /* rightshift */
c94cb026 228 2, /* size */
9fc0b501 229 16, /* bitsize */
0a1b45a2 230 false, /* pc_relative */
9fc0b501
SB
231 0, /* bitpos */
232 complain_overflow_bitfield, /* complain_on_overflow */
233 0, /* special_function */
234 "r_imm16be", /* name */
0a1b45a2 235 false, /* partial_inplace */
9fc0b501
SB
236 0x0000ffff, /* src_mask */
237 0x0000ffff, /* dst_mask */
0a1b45a2 238 false), /* pcrel_offset */
6655dba2
SB
239};
240
241#define NUM_HOWTOS ARRAY_SIZE (howto_table)
3c9b82ba
NC
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. */
3c9b82ba
NC
257static void
258rtype2howto (arelent *internal, struct internal_reloc *dst)
259{
6655dba2
SB
260 unsigned i;
261 for (i = 0; i < NUM_HOWTOS; i++)
3c9b82ba 262 {
6655dba2
SB
263 if (howto_table[i].howto.type == dst->r_type)
264 {
265 internal->howto = &howto_table[i].howto;
266 return;
267 }
3c9b82ba 268 }
6655dba2 269 internal->howto = NULL;
3c9b82ba
NC
270}
271
272#define RTYPE2HOWTO(internal, relocentry) rtype2howto (internal, relocentry)
273
274static reloc_howto_type *
275coff_z80_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
276 bfd_reloc_code_real_type code)
277{
6655dba2
SB
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;
3c9b82ba
NC
285}
286
157090f7
AM
287static reloc_howto_type *
288coff_z80_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
289 const char *r_name)
290{
6655dba2
SB
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;
157090f7
AM
295
296 return NULL;
297}
298
3c9b82ba
NC
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
307static void
308reloc_processing (arelent *relent,
07d6d2b8
AM
309 struct internal_reloc *reloc,
310 asymbol **symbols,
311 bfd *abfd,
312 asection *section)
3c9b82ba
NC
313{
314 relent->address = reloc->r_vaddr;
315 rtype2howto (relent, reloc);
316
e6b6fad2 317 if (reloc->r_symndx == -1 || symbols == NULL)
e039f7ed
AM
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))
3c9b82ba
NC
320 relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx];
321 else
e039f7ed
AM
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 }
3c9b82ba
NC
329 relent->addend = reloc->r_offset;
330 relent->address -= section->vma;
331}
332
d64c8f71 333static bool
3c9b82ba 334extra_case (bfd *in_abfd,
07d6d2b8
AM
335 struct bfd_link_info *link_info,
336 struct bfd_link_order *link_order,
337 arelent *reloc,
338 bfd_byte *data,
d64c8f71
AM
339 size_t *src_ptr,
340 size_t *dst_ptr)
3c9b82ba
NC
341{
342 asection * input_section = link_order->u.indirect.section;
d64c8f71
AM
343 bfd_size_type end = bfd_get_section_limit_octets (in_abfd, input_section);
344 bfd_size_type reloc_size = bfd_get_reloc_size (reloc->howto);
345
346 if (*src_ptr > end
347 || reloc_size > end - *src_ptr)
348 {
349 link_info->callbacks->einfo
350 /* xgettext:c-format */
351 (_("%X%P: %pB(%pA): relocation \"%pR\" goes out of range\n"),
352 in_abfd, input_section, reloc);
353 return false;
354 }
3c9b82ba 355
d64c8f71 356 int val = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
3c9b82ba
NC
357 switch (reloc->howto->type)
358 {
359 case R_OFF8:
6655dba2 360 if (reloc->howto->partial_inplace)
d64c8f71
AM
361 val += (signed char) (bfd_get_8 (in_abfd, data + *src_ptr)
362 & reloc->howto->src_mask);
363 if (val > 127 || val < -128)
364 {
365 link_info->callbacks->reloc_overflow
1a72702b
AM
366 (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
367 reloc->howto->name, reloc->addend, input_section->owner,
368 input_section, reloc->address);
d64c8f71
AM
369 return false;
370 }
1a72702b 371
d64c8f71
AM
372 bfd_put_8 (in_abfd, val, data + *dst_ptr);
373 *dst_ptr += 1;
374 *src_ptr += 1;
3c9b82ba
NC
375 break;
376
6655dba2
SB
377 case R_BYTE3:
378 bfd_put_8 (in_abfd, val >> 24, data + *dst_ptr);
d64c8f71
AM
379 *dst_ptr += 1;
380 *src_ptr += 1;
6655dba2
SB
381 break;
382
383 case R_BYTE2:
384 bfd_put_8 (in_abfd, val >> 16, data + *dst_ptr);
d64c8f71
AM
385 *dst_ptr += 1;
386 *src_ptr += 1;
6655dba2
SB
387 break;
388
389 case R_BYTE1:
390 bfd_put_8 (in_abfd, val >> 8, data + *dst_ptr);
d64c8f71
AM
391 *dst_ptr += 1;
392 *src_ptr += 1;
6655dba2
SB
393 break;
394
3c9b82ba 395 case R_IMM8:
6655dba2 396 if (reloc->howto->partial_inplace)
d64c8f71 397 val += bfd_get_8 (in_abfd, data + *src_ptr) & reloc->howto->src_mask;
279edac5 398 /* Fall through. */
6655dba2 399 case R_BYTE0:
3c9b82ba 400 bfd_put_8 (in_abfd, val, data + *dst_ptr);
d64c8f71
AM
401 *dst_ptr += 1;
402 *src_ptr += 1;
3c9b82ba
NC
403 break;
404
6655dba2
SB
405 case R_WORD1:
406 bfd_put_16 (in_abfd, val >> 16, data + *dst_ptr);
d64c8f71
AM
407 *dst_ptr += 2;
408 *src_ptr += 2;
6655dba2
SB
409 break;
410
3c9b82ba 411 case R_IMM16:
6655dba2 412 if (reloc->howto->partial_inplace)
d64c8f71 413 val += bfd_get_16 (in_abfd, data + *src_ptr) & reloc->howto->src_mask;
279edac5 414 /* Fall through. */
6655dba2 415 case R_WORD0:
3c9b82ba 416 bfd_put_16 (in_abfd, val, data + *dst_ptr);
d64c8f71
AM
417 *dst_ptr += 2;
418 *src_ptr += 2;
3c9b82ba
NC
419 break;
420
134dcee5 421 case R_IMM24:
6655dba2 422 if (reloc->howto->partial_inplace)
24d34d81
AM
423 val += (bfd_get_24 (in_abfd, data + *src_ptr)
424 & reloc->howto->src_mask);
425 bfd_put_24 (in_abfd, val, data + *dst_ptr);
d64c8f71
AM
426 *dst_ptr += 3;
427 *src_ptr += 3;
134dcee5
AM
428 break;
429
3c9b82ba 430 case R_IMM32:
6655dba2 431 if (reloc->howto->partial_inplace)
d64c8f71 432 val += bfd_get_32 (in_abfd, data + *src_ptr) & reloc->howto->src_mask;
3c9b82ba 433 bfd_put_32 (in_abfd, val, data + *dst_ptr);
d64c8f71
AM
434 *dst_ptr += 4;
435 *src_ptr += 4;
3c9b82ba
NC
436 break;
437
438 case R_JR:
439 {
d64c8f71
AM
440 if (reloc->howto->partial_inplace)
441 val += (signed char) (bfd_get_8 (in_abfd, data + *src_ptr)
442 & reloc->howto->src_mask);
44da2da1
AM
443 bfd_vma dot = (*dst_ptr
444 + input_section->output_offset
3c9b82ba 445 + input_section->output_section->vma);
d64c8f71 446 bfd_signed_vma gap = val - dot;
3c9b82ba 447 if (gap >= 128 || gap < -128)
d64c8f71
AM
448 {
449 link_info->callbacks->reloc_overflow
450 (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
451 reloc->howto->name, reloc->addend, input_section->owner,
452 input_section, reloc->address);
453 return false;
454 }
1a72702b 455
3c9b82ba 456 bfd_put_8 (in_abfd, gap, data + *dst_ptr);
d64c8f71
AM
457 *dst_ptr += 1;
458 *src_ptr += 1;
3c9b82ba
NC
459 break;
460 }
461
9fc0b501
SB
462 case R_IMM16BE:
463 if (reloc->howto->partial_inplace)
d64c8f71
AM
464 val += ((bfd_get_8 (in_abfd, data + *src_ptr + 0) * 0x100
465 + bfd_get_8 (in_abfd, data + *src_ptr + 1))
466 & reloc->howto->src_mask);
9fc0b501 467
d64c8f71
AM
468 bfd_put_8 (in_abfd, val >> 8, data + *dst_ptr + 0);
469 bfd_put_8 (in_abfd, val, data + *dst_ptr + 1);
470 *dst_ptr += 2;
471 *src_ptr += 2;
9fc0b501
SB
472 break;
473
3c9b82ba 474 default:
d64c8f71
AM
475 link_info->callbacks->einfo
476 /* xgettext:c-format */
477 (_("%X%P: %pB(%pA): relocation \"%pR\" is not supported\n"),
478 in_abfd, input_section, reloc);
479 return false;
3c9b82ba 480 }
d64c8f71 481 return true;
3c9b82ba
NC
482}
483
0a1b45a2 484static bool
6655dba2
SB
485z80_is_local_label_name (bfd * abfd ATTRIBUTE_UNUSED,
486 const char * name)
487{
488 return (name[0] == '.' && name[1] == 'L') ||
489 _bfd_coff_is_local_label_name (abfd, name);
490}
491
492#define coff_bfd_is_local_label_name z80_is_local_label_name
493
3c9b82ba
NC
494#define coff_reloc16_extra_cases extra_case
495#define coff_bfd_reloc_type_lookup coff_z80_reloc_type_lookup
157090f7 496#define coff_bfd_reloc_name_lookup coff_z80_reloc_name_lookup
3c9b82ba 497
2b5c217d
NC
498#ifndef bfd_pe_print_pdata
499#define bfd_pe_print_pdata NULL
500#endif
501
3c9b82ba
NC
502#include "coffcode.h"
503
504#undef coff_bfd_get_relocated_section_contents
505#define coff_bfd_get_relocated_section_contents \
506 bfd_coff_reloc16_get_relocated_section_contents
507
508#undef coff_bfd_relax_section
509#define coff_bfd_relax_section bfd_coff_reloc16_relax_section
510
6d00b590 511CREATE_LITTLE_COFF_TARGET_VEC (z80_coff_vec, "coff-z80", 0,
68ffbac6 512 SEC_CODE | SEC_DATA, '\0', NULL,
3c9b82ba
NC
513 COFF_SWAP_TABLE)
514