coff-z8k.c revision 1.8 1 1.1 christos /* BFD back-end for Zilog Z800n COFF binaries.
2 1.8 christos Copyright (C) 1992-2022 Free Software Foundation, Inc.
3 1.1 christos Contributed by Cygnus Support.
4 1.1 christos Written by Steve Chamberlain, <sac (at) cygnus.com>.
5 1.1 christos
6 1.1 christos This file is part of BFD, the Binary File Descriptor library.
7 1.1 christos
8 1.1 christos This program is free software; you can redistribute it and/or modify
9 1.1 christos it under the terms of the GNU General Public License as published by
10 1.1 christos the Free Software Foundation; either version 3 of the License, or
11 1.1 christos (at your option) any later version.
12 1.1 christos
13 1.1 christos This program is distributed in the hope that it will be useful,
14 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
15 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 1.1 christos GNU General Public License for more details.
17 1.1 christos
18 1.1 christos You should have received a copy of the GNU General Public License
19 1.1 christos along with this program; if not, write to the Free Software
20 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 1.1 christos MA 02110-1301, USA. */
22 1.1 christos
23 1.1 christos #include "sysdep.h"
24 1.1 christos #include "bfd.h"
25 1.1 christos #include "libbfd.h"
26 1.1 christos #include "bfdlink.h"
27 1.1 christos #include "coff/z8k.h"
28 1.1 christos #include "coff/internal.h"
29 1.1 christos #include "libcoff.h"
30 1.1 christos
31 1.1 christos #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (1)
32 1.1 christos
33 1.1 christos static reloc_howto_type r_imm32 =
34 1.8 christos HOWTO (R_IMM32, 0, 4, 32, false, 0,
35 1.8 christos complain_overflow_bitfield, 0, "r_imm32", true, 0xffffffff,
36 1.8 christos 0xffffffff, false);
37 1.1 christos
38 1.1 christos static reloc_howto_type r_imm4l =
39 1.8 christos HOWTO (R_IMM4L, 0, 1, 4, false, 0,
40 1.8 christos complain_overflow_bitfield, 0, "r_imm4l", true, 0xf, 0xf, false);
41 1.1 christos
42 1.1 christos static reloc_howto_type r_da =
43 1.8 christos HOWTO (R_IMM16, 0, 2, 16, false, 0,
44 1.8 christos complain_overflow_bitfield, 0, "r_da", true, 0x0000ffff, 0x0000ffff,
45 1.8 christos false);
46 1.1 christos
47 1.1 christos static reloc_howto_type r_imm8 =
48 1.8 christos HOWTO (R_IMM8, 0, 1, 8, false, 0,
49 1.8 christos complain_overflow_bitfield, 0, "r_imm8", true, 0x000000ff, 0x000000ff,
50 1.8 christos false);
51 1.1 christos
52 1.1 christos static reloc_howto_type r_rel16 =
53 1.8 christos HOWTO (R_REL16, 0, 2, 16, false, 0,
54 1.8 christos complain_overflow_bitfield, 0, "r_rel16", true, 0x0000ffff, 0x0000ffff,
55 1.8 christos true);
56 1.1 christos
57 1.1 christos static reloc_howto_type r_jr =
58 1.8 christos HOWTO (R_JR, 1, 1, 8, true, 0, complain_overflow_signed, 0,
59 1.8 christos "r_jr", true, 0xff, 0xff, true);
60 1.1 christos
61 1.1 christos static reloc_howto_type r_disp7 =
62 1.8 christos HOWTO (R_DISP7, 0, 1, 7, true, 0, complain_overflow_bitfield, 0,
63 1.8 christos "r_disp7", true, 0x7f, 0x7f, true);
64 1.1 christos
65 1.1 christos static reloc_howto_type r_callr =
66 1.8 christos HOWTO (R_CALLR, 1, 2, 12, true, 0, complain_overflow_signed, 0,
67 1.8 christos "r_callr", true, 0xfff, 0xfff, true);
68 1.1 christos
69 1.1 christos #define BADMAG(x) Z8KBADMAG(x)
70 1.1 christos #define Z8K 1 /* Customize coffcode.h. */
71 1.1 christos #define __A_MAGIC_SET__
72 1.1 christos
73 1.1 christos /* Code to swap in the reloc. */
74 1.1 christos #define SWAP_IN_RELOC_OFFSET H_GET_32
75 1.1 christos #define SWAP_OUT_RELOC_OFFSET H_PUT_32
76 1.1 christos #define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \
77 1.1 christos dst->r_stuff[0] = 'S'; \
78 1.1 christos dst->r_stuff[1] = 'C';
79 1.1 christos
80 1.1 christos /* Code to turn a r_type into a howto ptr, uses the above howto table. */
81 1.1 christos
82 1.1 christos static void
83 1.1 christos rtype2howto (arelent *internal, struct internal_reloc *dst)
84 1.1 christos {
85 1.1 christos switch (dst->r_type)
86 1.1 christos {
87 1.1 christos default:
88 1.3 christos internal->howto = NULL;
89 1.1 christos break;
90 1.1 christos case R_IMM8:
91 1.1 christos internal->howto = &r_imm8;
92 1.1 christos break;
93 1.1 christos case R_IMM16:
94 1.1 christos internal->howto = &r_da;
95 1.1 christos break;
96 1.1 christos case R_JR:
97 1.1 christos internal->howto = &r_jr;
98 1.1 christos break;
99 1.1 christos case R_DISP7:
100 1.1 christos internal->howto = &r_disp7;
101 1.1 christos break;
102 1.1 christos case R_CALLR:
103 1.1 christos internal->howto = &r_callr;
104 1.1 christos break;
105 1.1 christos case R_REL16:
106 1.1 christos internal->howto = &r_rel16;
107 1.1 christos break;
108 1.1 christos case R_IMM32:
109 1.1 christos internal->howto = &r_imm32;
110 1.1 christos break;
111 1.1 christos case R_IMM4L:
112 1.1 christos internal->howto = &r_imm4l;
113 1.1 christos break;
114 1.1 christos }
115 1.1 christos }
116 1.1 christos
117 1.1 christos #define RTYPE2HOWTO(internal, relocentry) rtype2howto (internal, relocentry)
118 1.1 christos
119 1.1 christos static reloc_howto_type *
120 1.1 christos coff_z8k_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
121 1.6 christos bfd_reloc_code_real_type code)
122 1.1 christos {
123 1.1 christos switch (code)
124 1.1 christos {
125 1.6 christos case BFD_RELOC_8: return & r_imm8;
126 1.6 christos case BFD_RELOC_16: return & r_da;
127 1.6 christos case BFD_RELOC_32: return & r_imm32;
128 1.6 christos case BFD_RELOC_8_PCREL: return & r_jr;
129 1.6 christos case BFD_RELOC_16_PCREL: return & r_rel16;
130 1.6 christos case BFD_RELOC_Z8K_DISP7: return & r_disp7;
131 1.6 christos case BFD_RELOC_Z8K_CALLR: return & r_callr;
132 1.6 christos case BFD_RELOC_Z8K_IMM4L: return & r_imm4l;
133 1.1 christos default: BFD_FAIL ();
134 1.1 christos return 0;
135 1.1 christos }
136 1.1 christos }
137 1.1 christos
138 1.1 christos static reloc_howto_type *
139 1.1 christos coff_z8k_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
140 1.1 christos const char *r_name)
141 1.1 christos {
142 1.1 christos if (strcasecmp (r_imm8.name, r_name) == 0)
143 1.1 christos return &r_imm8;
144 1.1 christos if (strcasecmp (r_da.name, r_name) == 0)
145 1.1 christos return &r_da;
146 1.1 christos if (strcasecmp (r_imm32.name, r_name) == 0)
147 1.1 christos return &r_imm32;
148 1.1 christos if (strcasecmp (r_jr.name, r_name) == 0)
149 1.1 christos return &r_jr;
150 1.1 christos if (strcasecmp (r_rel16.name, r_name) == 0)
151 1.1 christos return &r_rel16;
152 1.1 christos if (strcasecmp (r_disp7.name, r_name) == 0)
153 1.1 christos return &r_disp7;
154 1.1 christos if (strcasecmp (r_callr.name, r_name) == 0)
155 1.1 christos return &r_callr;
156 1.1 christos if (strcasecmp (r_imm4l.name, r_name) == 0)
157 1.1 christos return &r_imm4l;
158 1.1 christos
159 1.1 christos return NULL;
160 1.1 christos }
161 1.1 christos
162 1.1 christos /* Perform any necessary magic to the addend in a reloc entry. */
163 1.1 christos
164 1.1 christos #define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \
165 1.1 christos cache_ptr->addend = ext_reloc.r_offset;
166 1.1 christos
167 1.1 christos #define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \
168 1.1 christos reloc_processing(relent, reloc, symbols, abfd, section)
169 1.1 christos
170 1.1 christos static void
171 1.1 christos reloc_processing (arelent *relent,
172 1.6 christos struct internal_reloc *reloc,
173 1.6 christos asymbol **symbols,
174 1.6 christos bfd *abfd,
175 1.6 christos asection *section)
176 1.1 christos {
177 1.1 christos relent->address = reloc->r_vaddr;
178 1.1 christos rtype2howto (relent, reloc);
179 1.1 christos
180 1.8 christos if (reloc->r_symndx == -1)
181 1.8 christos relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
182 1.8 christos else if (reloc->r_symndx >= 0 && reloc->r_symndx < obj_conv_table_size (abfd))
183 1.1 christos relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx];
184 1.1 christos else
185 1.8 christos {
186 1.8 christos _bfd_error_handler
187 1.8 christos /* xgettext:c-format */
188 1.8 christos (_("%pB: warning: illegal symbol index %ld in relocs"),
189 1.8 christos abfd, reloc->r_symndx);
190 1.8 christos relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
191 1.8 christos }
192 1.1 christos relent->addend = reloc->r_offset;
193 1.1 christos relent->address -= section->vma;
194 1.1 christos }
195 1.1 christos
196 1.1 christos static void
197 1.1 christos extra_case (bfd *in_abfd,
198 1.6 christos struct bfd_link_info *link_info,
199 1.6 christos struct bfd_link_order *link_order,
200 1.6 christos arelent *reloc,
201 1.6 christos bfd_byte *data,
202 1.6 christos unsigned int *src_ptr,
203 1.6 christos unsigned int *dst_ptr)
204 1.1 christos {
205 1.1 christos asection * input_section = link_order->u.indirect.section;
206 1.1 christos
207 1.1 christos switch (reloc->howto->type)
208 1.1 christos {
209 1.1 christos case R_IMM8:
210 1.1 christos bfd_put_8 (in_abfd,
211 1.1 christos bfd_coff_reloc16_get_value (reloc, link_info, input_section),
212 1.1 christos data + *dst_ptr);
213 1.1 christos (*dst_ptr) += 1;
214 1.1 christos (*src_ptr) += 1;
215 1.1 christos break;
216 1.1 christos
217 1.1 christos case R_IMM32:
218 1.1 christos /* If no flags are set, assume immediate value. */
219 1.1 christos if (! (*reloc->sym_ptr_ptr)->section->flags)
220 1.1 christos {
221 1.1 christos bfd_put_32 (in_abfd,
222 1.1 christos bfd_coff_reloc16_get_value (reloc, link_info,
223 1.1 christos input_section),
224 1.1 christos data + *dst_ptr);
225 1.1 christos }
226 1.1 christos else
227 1.1 christos {
228 1.1 christos bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
229 1.1 christos input_section);
230 1.1 christos /* Addresses are 23 bit, and the layout of those in a 32-bit
231 1.1 christos value is as follows:
232 1.1 christos 1AAAAAAA xxxxxxxx AAAAAAAA AAAAAAAA
233 1.1 christos (A - address bits, x - ignore). */
234 1.1 christos dst = (dst & 0xffff) | ((dst & 0xff0000) << 8) | 0x80000000;
235 1.1 christos bfd_put_32 (in_abfd, dst, data + *dst_ptr);
236 1.1 christos }
237 1.1 christos (*dst_ptr) += 4;
238 1.1 christos (*src_ptr) += 4;
239 1.1 christos break;
240 1.1 christos
241 1.1 christos case R_IMM4L:
242 1.1 christos bfd_put_8 (in_abfd,
243 1.1 christos ((bfd_get_8 (in_abfd, data + *dst_ptr) & 0xf0)
244 1.1 christos | (0x0f
245 1.1 christos & bfd_coff_reloc16_get_value (reloc, link_info,
246 1.1 christos input_section))),
247 1.1 christos data + *dst_ptr);
248 1.1 christos (*dst_ptr) += 1;
249 1.1 christos (*src_ptr) += 1;
250 1.1 christos break;
251 1.1 christos
252 1.1 christos case R_IMM16:
253 1.1 christos bfd_put_16 (in_abfd,
254 1.1 christos bfd_coff_reloc16_get_value (reloc, link_info, input_section),
255 1.1 christos data + *dst_ptr);
256 1.1 christos (*dst_ptr) += 2;
257 1.1 christos (*src_ptr) += 2;
258 1.1 christos break;
259 1.1 christos
260 1.1 christos case R_JR:
261 1.1 christos {
262 1.1 christos bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
263 1.1 christos input_section);
264 1.1 christos bfd_vma dot = (*dst_ptr
265 1.1 christos + input_section->output_offset
266 1.1 christos + input_section->output_section->vma);
267 1.1 christos int gap = dst - dot - 1; /* -1, since we're in the odd byte of the
268 1.6 christos word and the pc's been incremented. */
269 1.1 christos
270 1.1 christos if (gap & 1)
271 1.1 christos abort ();
272 1.1 christos gap /= 2;
273 1.5 christos if (gap > 127 || gap < -128)
274 1.5 christos (*link_info->callbacks->reloc_overflow)
275 1.5 christos (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
276 1.5 christos reloc->howto->name, reloc->addend, input_section->owner,
277 1.5 christos input_section, reloc->address);
278 1.5 christos
279 1.1 christos bfd_put_8 (in_abfd, gap, data + *dst_ptr);
280 1.1 christos (*dst_ptr)++;
281 1.1 christos (*src_ptr)++;
282 1.1 christos break;
283 1.1 christos }
284 1.1 christos
285 1.1 christos case R_DISP7:
286 1.1 christos {
287 1.1 christos bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
288 1.1 christos input_section);
289 1.1 christos bfd_vma dot = (*dst_ptr
290 1.1 christos + input_section->output_offset
291 1.1 christos + input_section->output_section->vma);
292 1.1 christos int gap = dst - dot - 1; /* -1, since we're in the odd byte of the
293 1.6 christos word and the pc's been incremented. */
294 1.1 christos
295 1.1 christos if (gap & 1)
296 1.1 christos abort ();
297 1.1 christos gap /= 2;
298 1.1 christos
299 1.1 christos if (gap > 0 || gap < -127)
300 1.5 christos (*link_info->callbacks->reloc_overflow)
301 1.5 christos (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
302 1.5 christos reloc->howto->name, reloc->addend, input_section->owner,
303 1.5 christos input_section, reloc->address);
304 1.5 christos
305 1.1 christos bfd_put_8 (in_abfd,
306 1.6 christos (bfd_get_8 ( in_abfd, data + *dst_ptr) & 0x80) + (-gap & 0x7f),
307 1.6 christos data + *dst_ptr);
308 1.1 christos (*dst_ptr)++;
309 1.1 christos (*src_ptr)++;
310 1.1 christos break;
311 1.1 christos }
312 1.1 christos
313 1.1 christos case R_CALLR:
314 1.1 christos {
315 1.1 christos bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
316 1.1 christos input_section);
317 1.1 christos bfd_vma dot = (*dst_ptr
318 1.1 christos + input_section->output_offset
319 1.1 christos + input_section->output_section->vma);
320 1.1 christos int gap = dst - dot - 2;
321 1.1 christos
322 1.1 christos if (gap & 1)
323 1.1 christos abort ();
324 1.1 christos if (gap > 4096 || gap < -4095)
325 1.5 christos (*link_info->callbacks->reloc_overflow)
326 1.5 christos (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
327 1.5 christos reloc->howto->name, reloc->addend, input_section->owner,
328 1.5 christos input_section, reloc->address);
329 1.5 christos
330 1.1 christos gap /= 2;
331 1.1 christos bfd_put_16 (in_abfd,
332 1.6 christos (bfd_get_16 ( in_abfd, data + *dst_ptr) & 0xf000) | (-gap & 0x0fff),
333 1.6 christos data + *dst_ptr);
334 1.1 christos (*dst_ptr) += 2;
335 1.1 christos (*src_ptr) += 2;
336 1.1 christos break;
337 1.1 christos }
338 1.1 christos
339 1.1 christos case R_REL16:
340 1.1 christos {
341 1.1 christos bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
342 1.1 christos input_section);
343 1.1 christos bfd_vma dot = (*dst_ptr
344 1.1 christos + input_section->output_offset
345 1.1 christos + input_section->output_section->vma);
346 1.1 christos int gap = dst - dot - 2;
347 1.1 christos
348 1.1 christos if (gap > 32767 || gap < -32768)
349 1.5 christos (*link_info->callbacks->reloc_overflow)
350 1.5 christos (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
351 1.5 christos reloc->howto->name, reloc->addend, input_section->owner,
352 1.5 christos input_section, reloc->address);
353 1.5 christos
354 1.1 christos bfd_put_16 (in_abfd, (bfd_vma) gap, data + *dst_ptr);
355 1.1 christos (*dst_ptr) += 2;
356 1.1 christos (*src_ptr) += 2;
357 1.1 christos break;
358 1.1 christos }
359 1.1 christos
360 1.1 christos default:
361 1.1 christos abort ();
362 1.1 christos }
363 1.1 christos }
364 1.1 christos
365 1.1 christos #define coff_reloc16_extra_cases extra_case
366 1.1 christos #define coff_bfd_reloc_type_lookup coff_z8k_reloc_type_lookup
367 1.1 christos #define coff_bfd_reloc_name_lookup coff_z8k_reloc_name_lookup
368 1.1 christos
369 1.1 christos #ifndef bfd_pe_print_pdata
370 1.1 christos #define bfd_pe_print_pdata NULL
371 1.1 christos #endif
372 1.1 christos
373 1.1 christos #include "coffcode.h"
374 1.1 christos
375 1.1 christos #undef coff_bfd_get_relocated_section_contents
376 1.1 christos #define coff_bfd_get_relocated_section_contents \
377 1.1 christos bfd_coff_reloc16_get_relocated_section_contents
378 1.1 christos
379 1.1 christos #undef coff_bfd_relax_section
380 1.1 christos #define coff_bfd_relax_section bfd_coff_reloc16_relax_section
381 1.1 christos
382 1.3 christos CREATE_BIG_COFF_TARGET_VEC (z8k_coff_vec, "coff-z8k", 0, 0, '_', NULL, COFF_SWAP_TABLE)
383