HOWTO size encoding
[binutils-gdb.git] / bfd / coff-z80.c
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
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 *
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 *
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
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
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
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