coff-z80.c revision 1.5 1 1.1 christos /* BFD back-end for Zilog Z80 COFF binaries.
2 1.5 christos Copyright (C) 2005-2016 Free Software Foundation, Inc.
3 1.1 christos Contributed by Arnold Metselaar <arnold_m (at) operamail.com>
4 1.1 christos
5 1.1 christos This file is part of BFD, the Binary File Descriptor library.
6 1.1 christos
7 1.3 christos This program is free software; you can redistribute it and/or modify
8 1.1 christos it under the terms of the GNU General Public License as published by
9 1.1 christos the Free Software Foundation; either version 3 of the License, or
10 1.1 christos (at your option) any later version.
11 1.1 christos
12 1.1 christos This program is distributed in the hope that it will be useful,
13 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
14 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 1.1 christos GNU General Public License for more details.
16 1.1 christos
17 1.1 christos You should have received a copy of the GNU General Public License
18 1.1 christos along with this program; if not, write to the Free Software
19 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20 1.1 christos MA 02110-1301, USA. */
21 1.1 christos
22 1.1 christos #include "sysdep.h"
23 1.1 christos #include "bfd.h"
24 1.1 christos #include "libbfd.h"
25 1.1 christos #include "bfdlink.h"
26 1.1 christos #include "coff/z80.h"
27 1.1 christos #include "coff/internal.h"
28 1.1 christos #include "libcoff.h"
29 1.1 christos
30 1.1 christos #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER 0
31 1.1 christos
32 1.1 christos static reloc_howto_type r_imm32 =
33 1.1 christos HOWTO (R_IMM32, 0, 2, 32, FALSE, 0,
34 1.1 christos complain_overflow_dont, 0, "r_imm32", TRUE, 0xffffffff, 0xffffffff,
35 1.1 christos FALSE);
36 1.1 christos
37 1.1 christos static reloc_howto_type r_imm24 =
38 1.1 christos HOWTO (R_IMM24, 0, 1, 24, FALSE, 0,
39 1.1 christos complain_overflow_dont, 0, "r_imm24", TRUE, 0x00ffffff, 0x00ffffff,
40 1.1 christos FALSE);
41 1.1 christos
42 1.1 christos static reloc_howto_type r_imm16 =
43 1.1 christos HOWTO (R_IMM16, 0, 1, 16, FALSE, 0,
44 1.1 christos complain_overflow_dont, 0, "r_imm16", TRUE, 0x0000ffff, 0x0000ffff,
45 1.1 christos FALSE);
46 1.1 christos
47 1.1 christos static reloc_howto_type r_imm8 =
48 1.1 christos HOWTO (R_IMM8, 0, 0, 8, FALSE, 0,
49 1.1 christos complain_overflow_bitfield, 0, "r_imm8", TRUE, 0x000000ff, 0x000000ff,
50 1.1 christos FALSE);
51 1.1 christos
52 1.1 christos static reloc_howto_type r_jr =
53 1.3 christos HOWTO (R_JR, 0, 0, 8, TRUE, 0,
54 1.1 christos complain_overflow_signed, 0, "r_jr", FALSE, 0, 0xFF,
55 1.1 christos FALSE);
56 1.1 christos
57 1.1 christos static reloc_howto_type r_off8 =
58 1.3 christos HOWTO (R_OFF8, 0, 0, 8, FALSE, 0,
59 1.1 christos complain_overflow_signed, 0,"r_off8", FALSE, 0, 0xff,
60 1.1 christos FALSE);
61 1.1 christos
62 1.1 christos
63 1.1 christos #define BADMAG(x) Z80BADMAG(x)
64 1.1 christos #define Z80 1 /* Customize coffcode.h. */
65 1.1 christos #define __A_MAGIC_SET__
66 1.1 christos
67 1.1 christos /* Code to swap in the reloc. */
68 1.1 christos
69 1.1 christos #define SWAP_IN_RELOC_OFFSET H_GET_32
70 1.1 christos #define SWAP_OUT_RELOC_OFFSET H_PUT_32
71 1.1 christos
72 1.1 christos #define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \
73 1.1 christos dst->r_stuff[0] = 'S'; \
74 1.1 christos dst->r_stuff[1] = 'C';
75 1.1 christos
76 1.1 christos /* Code to turn a r_type into a howto ptr, uses the above howto table. */
77 1.1 christos
78 1.1 christos static void
79 1.1 christos rtype2howto (arelent *internal, struct internal_reloc *dst)
80 1.1 christos {
81 1.1 christos switch (dst->r_type)
82 1.1 christos {
83 1.1 christos default:
84 1.3 christos internal->howto = NULL;
85 1.1 christos break;
86 1.1 christos case R_IMM8:
87 1.1 christos internal->howto = &r_imm8;
88 1.1 christos break;
89 1.1 christos case R_IMM16:
90 1.1 christos internal->howto = &r_imm16;
91 1.1 christos break;
92 1.1 christos case R_IMM24:
93 1.1 christos internal->howto = &r_imm24;
94 1.1 christos break;
95 1.1 christos case R_IMM32:
96 1.1 christos internal->howto = &r_imm32;
97 1.1 christos break;
98 1.1 christos case R_JR:
99 1.1 christos internal->howto = &r_jr;
100 1.1 christos break;
101 1.1 christos case R_OFF8:
102 1.1 christos internal->howto = &r_off8;
103 1.1 christos break;
104 1.1 christos }
105 1.1 christos }
106 1.1 christos
107 1.1 christos #define RTYPE2HOWTO(internal, relocentry) rtype2howto (internal, relocentry)
108 1.1 christos
109 1.1 christos static reloc_howto_type *
110 1.1 christos coff_z80_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
111 1.1 christos bfd_reloc_code_real_type code)
112 1.1 christos {
113 1.1 christos switch (code)
114 1.1 christos {
115 1.1 christos case BFD_RELOC_8: return & r_imm8;
116 1.1 christos case BFD_RELOC_16: return & r_imm16;
117 1.1 christos case BFD_RELOC_24: return & r_imm24;
118 1.1 christos case BFD_RELOC_32: return & r_imm32;
119 1.1 christos case BFD_RELOC_8_PCREL: return & r_jr;
120 1.1 christos case BFD_RELOC_Z80_DISP8: return & r_off8;
121 1.1 christos default: BFD_FAIL ();
122 1.1 christos return NULL;
123 1.1 christos }
124 1.1 christos }
125 1.1 christos
126 1.1 christos static reloc_howto_type *
127 1.1 christos coff_z80_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
128 1.1 christos const char *r_name)
129 1.1 christos {
130 1.1 christos if (strcasecmp (r_imm8.name, r_name) == 0)
131 1.1 christos return &r_imm8;
132 1.1 christos if (strcasecmp (r_imm16.name, r_name) == 0)
133 1.1 christos return &r_imm16;
134 1.1 christos if (strcasecmp (r_imm24.name, r_name) == 0)
135 1.1 christos return &r_imm24;
136 1.1 christos if (strcasecmp (r_imm32.name, r_name) == 0)
137 1.1 christos return &r_imm32;
138 1.1 christos if (strcasecmp (r_jr.name, r_name) == 0)
139 1.1 christos return &r_jr;
140 1.1 christos if (strcasecmp (r_off8.name, r_name) == 0)
141 1.1 christos return &r_off8;
142 1.1 christos
143 1.1 christos return NULL;
144 1.1 christos }
145 1.1 christos
146 1.1 christos /* Perform any necessary magic to the addend in a reloc entry. */
147 1.1 christos
148 1.1 christos #define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \
149 1.1 christos cache_ptr->addend = ext_reloc.r_offset;
150 1.1 christos
151 1.1 christos #define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \
152 1.1 christos reloc_processing(relent, reloc, symbols, abfd, section)
153 1.1 christos
154 1.1 christos static void
155 1.1 christos reloc_processing (arelent *relent,
156 1.1 christos struct internal_reloc *reloc,
157 1.1 christos asymbol **symbols,
158 1.1 christos bfd *abfd,
159 1.1 christos asection *section)
160 1.1 christos {
161 1.1 christos relent->address = reloc->r_vaddr;
162 1.1 christos rtype2howto (relent, reloc);
163 1.1 christos
164 1.1 christos if (reloc->r_symndx > 0)
165 1.1 christos relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx];
166 1.1 christos else
167 1.1 christos relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
168 1.1 christos
169 1.1 christos relent->addend = reloc->r_offset;
170 1.1 christos relent->address -= section->vma;
171 1.1 christos }
172 1.1 christos
173 1.1 christos static void
174 1.1 christos extra_case (bfd *in_abfd,
175 1.1 christos struct bfd_link_info *link_info,
176 1.1 christos struct bfd_link_order *link_order,
177 1.1 christos arelent *reloc,
178 1.1 christos bfd_byte *data,
179 1.1 christos unsigned int *src_ptr,
180 1.1 christos unsigned int *dst_ptr)
181 1.1 christos {
182 1.1 christos asection * input_section = link_order->u.indirect.section;
183 1.1 christos int val;
184 1.1 christos
185 1.1 christos switch (reloc->howto->type)
186 1.1 christos {
187 1.1 christos case R_OFF8:
188 1.1 christos val = bfd_coff_reloc16_get_value (reloc, link_info,
189 1.1 christos input_section);
190 1.1 christos if (val>127 || val<-128) /* Test for overflow. */
191 1.5 christos (*link_info->callbacks->reloc_overflow)
192 1.5 christos (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
193 1.5 christos reloc->howto->name, reloc->addend, input_section->owner,
194 1.5 christos input_section, reloc->address);
195 1.5 christos
196 1.1 christos bfd_put_8 (in_abfd, val, data + *dst_ptr);
197 1.1 christos (*dst_ptr) += 1;
198 1.1 christos (*src_ptr) += 1;
199 1.1 christos break;
200 1.1 christos
201 1.1 christos case R_IMM8:
202 1.1 christos val = bfd_get_8 ( in_abfd, data+*src_ptr)
203 1.1 christos + bfd_coff_reloc16_get_value (reloc, link_info, input_section);
204 1.1 christos bfd_put_8 (in_abfd, val, data + *dst_ptr);
205 1.1 christos (*dst_ptr) += 1;
206 1.1 christos (*src_ptr) += 1;
207 1.1 christos break;
208 1.1 christos
209 1.1 christos case R_IMM16:
210 1.1 christos val = bfd_get_16 ( in_abfd, data+*src_ptr)
211 1.1 christos + bfd_coff_reloc16_get_value (reloc, link_info, input_section);
212 1.1 christos bfd_put_16 (in_abfd, val, data + *dst_ptr);
213 1.1 christos (*dst_ptr) += 2;
214 1.1 christos (*src_ptr) += 2;
215 1.1 christos break;
216 1.1 christos
217 1.1 christos case R_IMM24:
218 1.1 christos val = bfd_get_16 ( in_abfd, data+*src_ptr)
219 1.1 christos + (bfd_get_8 ( in_abfd, data+*src_ptr+2) << 16)
220 1.1 christos + bfd_coff_reloc16_get_value (reloc, link_info, input_section);
221 1.1 christos bfd_put_16 (in_abfd, val, data + *dst_ptr);
222 1.1 christos bfd_put_8 (in_abfd, val >> 16, data + *dst_ptr+2);
223 1.1 christos (*dst_ptr) += 3;
224 1.1 christos (*src_ptr) += 3;
225 1.1 christos break;
226 1.1 christos
227 1.1 christos case R_IMM32:
228 1.1 christos val = bfd_get_32 ( in_abfd, data+*src_ptr)
229 1.1 christos + bfd_coff_reloc16_get_value (reloc, link_info, input_section);
230 1.1 christos bfd_put_32 (in_abfd, val, data + *dst_ptr);
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_JR:
236 1.1 christos {
237 1.1 christos bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
238 1.1 christos input_section);
239 1.1 christos bfd_vma dot = (*dst_ptr
240 1.1 christos + input_section->output_offset
241 1.1 christos + input_section->output_section->vma);
242 1.1 christos int gap = dst - dot - 1; /* -1, Since the offset is relative
243 1.1 christos to the value of PC after reading
244 1.1 christos the offset. */
245 1.1 christos
246 1.1 christos if (gap >= 128 || gap < -128)
247 1.5 christos (*link_info->callbacks->reloc_overflow)
248 1.5 christos (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
249 1.5 christos reloc->howto->name, reloc->addend, input_section->owner,
250 1.5 christos input_section, reloc->address);
251 1.5 christos
252 1.1 christos bfd_put_8 (in_abfd, gap, data + *dst_ptr);
253 1.1 christos (*dst_ptr)++;
254 1.1 christos (*src_ptr)++;
255 1.1 christos break;
256 1.1 christos }
257 1.1 christos
258 1.1 christos default:
259 1.1 christos abort ();
260 1.1 christos }
261 1.1 christos }
262 1.1 christos
263 1.1 christos #define coff_reloc16_extra_cases extra_case
264 1.1 christos #define coff_bfd_reloc_type_lookup coff_z80_reloc_type_lookup
265 1.1 christos #define coff_bfd_reloc_name_lookup coff_z80_reloc_name_lookup
266 1.1 christos
267 1.1 christos #ifndef bfd_pe_print_pdata
268 1.1 christos #define bfd_pe_print_pdata NULL
269 1.1 christos #endif
270 1.1 christos
271 1.1 christos #include "coffcode.h"
272 1.1 christos
273 1.1 christos #undef coff_bfd_get_relocated_section_contents
274 1.1 christos #define coff_bfd_get_relocated_section_contents \
275 1.1 christos bfd_coff_reloc16_get_relocated_section_contents
276 1.1 christos
277 1.1 christos #undef coff_bfd_relax_section
278 1.1 christos #define coff_bfd_relax_section bfd_coff_reloc16_relax_section
279 1.1 christos
280 1.3 christos CREATE_LITTLE_COFF_TARGET_VEC (z80_coff_vec, "coff-z80", 0,
281 1.3 christos SEC_CODE | SEC_DATA, '\0', NULL,
282 1.1 christos COFF_SWAP_TABLE)
283 1.1 christos
284