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