Commit | Line | Data |
---|---|---|
6655dba2 SB |
1 | /* Zilog (e)Z80-specific support for 32-bit ELF |
2 | Copyright (C) 1999-2019 Free Software Foundation, Inc. | |
3 | (Heavily copied from the S12Z port by Sergey Belyashov (sergey.belyashov@gmail.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 "bfdlink.h" | |
25 | #include "libbfd.h" | |
26 | #include "elf-bfd.h" | |
27 | ||
28 | #include "elf/z80.h" | |
29 | ||
30 | /* All users of this file have bfd_octets_per_byte (abfd, sec) == 1. */ | |
31 | #define OCTETS_PER_BYTE(ABFD, SEC) 1 | |
32 | ||
33 | /* Relocation functions. */ | |
34 | static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup | |
35 | (bfd *, bfd_reloc_code_real_type); | |
36 | static bfd_boolean z80_info_to_howto_rel | |
37 | (bfd *, arelent *, Elf_Internal_Rela *); | |
38 | ||
39 | typedef struct { | |
40 | bfd_reloc_code_real_type r_type; | |
41 | reloc_howto_type howto; | |
42 | } bfd_howto_type; | |
43 | ||
44 | #define BFD_EMPTY_HOWTO(rt,x) {rt, EMPTY_HOWTO(x)} | |
45 | #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)} | |
46 | ||
47 | static const | |
48 | bfd_howto_type elf_z80_howto_table[] = | |
49 | { | |
50 | /* This reloc does nothing. */ | |
51 | BFD_HOWTO (BFD_RELOC_NONE, | |
52 | R_Z80_NONE, /* type */ | |
53 | 0, /* rightshift */ | |
54 | 3, /* size (0 = byte, 1 = short, 2 = long) */ | |
55 | 0, /* bitsize */ | |
56 | FALSE, /* pc_relative */ | |
57 | 0, /* bitpos */ | |
58 | complain_overflow_dont,/* complain_on_overflow */ | |
59 | bfd_elf_generic_reloc, /* special_function */ | |
60 | "R_NONE", /* name */ | |
61 | FALSE, /* partial_inplace */ | |
62 | 0, /* src_mask */ | |
63 | 0, /* dst_mask */ | |
64 | FALSE), /* pcrel_offset */ | |
65 | ||
66 | /* A 8 bit relocation */ | |
67 | BFD_HOWTO (BFD_RELOC_8, | |
68 | R_Z80_8, /* type */ | |
69 | 0, /* rightshift */ | |
70 | 0, /* size (0 = byte, 1 = short, 2 = long) */ | |
71 | 8, /* bitsize */ | |
72 | FALSE, /* pc_relative */ | |
73 | 0, /* bitpos */ | |
74 | complain_overflow_bitfield, /* complain_on_overflow */ | |
75 | bfd_elf_generic_reloc, /* special_function */ | |
76 | "r_imm8", /* name */ | |
77 | FALSE, /* partial_inplace */ | |
78 | 0x00, /* src_mask */ | |
79 | 0xff, /* dst_mask */ | |
80 | FALSE), /* pcrel_offset */ | |
81 | ||
82 | /* A 8 bit index register displacement relocation */ | |
83 | BFD_HOWTO (BFD_RELOC_Z80_DISP8, | |
84 | R_Z80_8_DIS, /* type */ | |
85 | 0, /* rightshift */ | |
86 | 0, /* size (0 = byte, 1 = short, 2 = long) */ | |
87 | 8, /* bitsize */ | |
88 | FALSE, /* pc_relative */ | |
89 | 0, /* bitpos */ | |
90 | complain_overflow_signed, /* complain_on_overflow */ | |
91 | bfd_elf_generic_reloc, /* special_function */ | |
92 | "r_off", /* name */ | |
93 | FALSE, /* partial_inplace */ | |
94 | 0x00, /* src_mask */ | |
95 | 0xff, /* dst_mask */ | |
96 | FALSE), /* pcrel_offset */ | |
97 | ||
98 | /* A 8 bit PC-rel relocation */ | |
99 | BFD_HOWTO (BFD_RELOC_8_PCREL, | |
100 | R_Z80_8_PCREL, /* type */ | |
101 | 0, /* rightshift */ | |
102 | 0, /* size (0 = byte, 1 = short, 2 = long) */ | |
103 | 8, /* bitsize */ | |
104 | TRUE, /* pc_relative */ | |
105 | 0, /* bitpos */ | |
106 | complain_overflow_signed, /* complain_on_overflow */ | |
107 | bfd_elf_generic_reloc, /* special_function */ | |
108 | "r_jr", /* name */ | |
109 | FALSE, /* partial_inplace */ | |
110 | 0x00, /* src_mask */ | |
111 | 0xff, /* dst_mask */ | |
112 | TRUE), /* pcrel_offset */ | |
113 | ||
114 | /* An 16 bit absolute relocation */ | |
115 | BFD_HOWTO (BFD_RELOC_16, | |
116 | R_Z80_16, /* type */ | |
117 | 0, /* rightshift */ | |
118 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
119 | 16, /* bitsize */ | |
120 | FALSE, /* pc_relative */ | |
121 | 0, /* bitpos */ | |
122 | complain_overflow_bitfield, /* complain_on_overflow */ | |
123 | bfd_elf_generic_reloc, /* special_function */ | |
124 | "r_imm16", /* name */ | |
125 | FALSE, /* partial_inplace */ | |
126 | 0x00000000, /* src_mask */ | |
127 | 0x0000ffff, /* dst_mask */ | |
128 | FALSE), /* pcrel_offset */ | |
129 | ||
130 | /* A 24 bit absolute relocation emitted by ADL mode operands */ | |
131 | BFD_HOWTO (BFD_RELOC_24, | |
132 | R_Z80_24, /* type */ | |
133 | 0, /* rightshift */ | |
134 | 5, /* size (0 = byte, 1 = short, 2 = long) */ | |
135 | 24, /* bitsize */ | |
136 | FALSE, /* pc_relative */ | |
137 | 0, /* bitpos */ | |
138 | complain_overflow_bitfield, /* complain_on_overflow */ | |
139 | bfd_elf_generic_reloc, /* special_function */ | |
140 | "r_imm24", /* name */ | |
141 | FALSE, /* partial_inplace */ | |
142 | 0x00000000, /* src_mask */ | |
143 | 0x00ffffff, /* dst_mask */ | |
144 | FALSE), /* pcrel_offset */ | |
145 | ||
146 | BFD_HOWTO (BFD_RELOC_32, | |
147 | R_Z80_32, /* type */ | |
148 | 0, /* rightshift */ | |
149 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
150 | 32, /* bitsize */ | |
151 | FALSE, /* pc_relative */ | |
152 | 0, /* bitpos */ | |
153 | complain_overflow_dont,/* complain_on_overflow */ | |
154 | bfd_elf_generic_reloc, /* special_function */ | |
155 | "r_imm32", /* name */ | |
156 | FALSE, /* partial_inplace */ | |
157 | 0x00000000, /* src_mask */ | |
158 | 0xffffffff, /* dst_mask */ | |
159 | FALSE), /* pcrel_offset */ | |
160 | ||
161 | /* First (lowest) 8 bits of multibyte relocation */ | |
162 | BFD_HOWTO (BFD_RELOC_Z80_BYTE0, | |
163 | R_Z80_BYTE0, /* type */ | |
164 | 0, /* rightshift */ | |
165 | 0, /* size (0 = byte, 1 = short, 2 = long) */ | |
166 | 32, /* bitsize */ | |
167 | FALSE, /* pc_relative */ | |
168 | 0, /* bitpos */ | |
169 | complain_overflow_dont,/* complain_on_overflow */ | |
170 | bfd_elf_generic_reloc, /* special_function */ | |
171 | "r_byte0", /* name */ | |
172 | FALSE, /* partial_inplace */ | |
173 | 0, /* src_mask */ | |
174 | 0xff, /* dst_mask */ | |
175 | FALSE), /* pcrel_offset */ | |
176 | ||
177 | /* Second 8 bits of multibyte relocation */ | |
178 | BFD_HOWTO (BFD_RELOC_Z80_BYTE1, | |
179 | R_Z80_BYTE1, /* type */ | |
180 | 8, /* rightshift */ | |
181 | 0, /* size (0 = byte, 1 = short, 2 = long) */ | |
182 | 32, /* bitsize */ | |
183 | FALSE, /* pc_relative */ | |
184 | 0, /* bitpos */ | |
185 | complain_overflow_dont,/* complain_on_overflow */ | |
186 | bfd_elf_generic_reloc, /* special_function */ | |
187 | "r_byte1", /* name */ | |
188 | FALSE, /* partial_inplace */ | |
189 | 0, /* src_mask */ | |
190 | 0xff, /* dst_mask */ | |
191 | FALSE), /* pcrel_offset */ | |
192 | ||
193 | /* Third 8 bits of multibyte relocation */ | |
194 | BFD_HOWTO (BFD_RELOC_Z80_BYTE2, | |
195 | R_Z80_BYTE2, /* type */ | |
196 | 16, /* rightshift */ | |
197 | 0, /* size (0 = byte, 1 = short, 2 = long) */ | |
198 | 32, /* bitsize */ | |
199 | FALSE, /* pc_relative */ | |
200 | 0, /* bitpos */ | |
201 | complain_overflow_dont,/* complain_on_overflow */ | |
202 | bfd_elf_generic_reloc, /* special_function */ | |
203 | "r_byte2", /* name */ | |
204 | FALSE, /* partial_inplace */ | |
205 | 0, /* src_mask */ | |
206 | 0xff, /* dst_mask */ | |
207 | FALSE), /* pcrel_offset */ | |
208 | ||
209 | /* Fourth (highest) 8 bits of multibyte relocation */ | |
210 | BFD_HOWTO (BFD_RELOC_Z80_BYTE3, | |
211 | R_Z80_BYTE3, /* type */ | |
212 | 24, /* rightshift */ | |
213 | 0, /* size (0 = byte, 1 = short, 2 = long) */ | |
214 | 32, /* bitsize */ | |
215 | FALSE, /* pc_relative */ | |
216 | 0, /* bitpos */ | |
217 | complain_overflow_dont,/* complain_on_overflow */ | |
218 | bfd_elf_generic_reloc, /* special_function */ | |
219 | "r_byte3", /* name */ | |
220 | FALSE, /* partial_inplace */ | |
221 | 0, /* src_mask */ | |
222 | 0xff, /* dst_mask */ | |
223 | FALSE), /* pcrel_offset */ | |
224 | ||
225 | /* An 16 bit absolute relocation of lower word of multibyte value */ | |
226 | BFD_HOWTO (BFD_RELOC_Z80_WORD0, | |
227 | R_Z80_WORD0, /* type */ | |
228 | 0, /* rightshift */ | |
229 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
230 | 32, /* bitsize */ | |
231 | FALSE, /* pc_relative */ | |
232 | 0, /* bitpos */ | |
233 | complain_overflow_dont,/* complain_on_overflow */ | |
234 | bfd_elf_generic_reloc, /* special_function */ | |
235 | "r_word0", /* name */ | |
236 | FALSE, /* partial_inplace */ | |
237 | 0, /* src_mask */ | |
238 | 0xffff, /* dst_mask */ | |
239 | FALSE), /* pcrel_offset */ | |
240 | ||
241 | /* An 16 bit absolute relocation of higher word of multibyte value */ | |
242 | BFD_HOWTO (BFD_RELOC_Z80_WORD1, | |
243 | R_Z80_WORD1, /* type */ | |
244 | 16, /* rightshift */ | |
245 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
246 | 32, /* bitsize */ | |
247 | FALSE, /* pc_relative */ | |
248 | 0, /* bitpos */ | |
249 | complain_overflow_dont,/* complain_on_overflow */ | |
250 | bfd_elf_generic_reloc, /* special_function */ | |
251 | "r_word1", /* name */ | |
252 | FALSE, /* partial_inplace */ | |
253 | 0, /* src_mask */ | |
254 | 0xffff, /* dst_mask */ | |
255 | FALSE), /* pcrel_offset */ | |
256 | }; | |
257 | ||
258 | static reloc_howto_type * | |
259 | bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, | |
260 | bfd_reloc_code_real_type code) | |
261 | { | |
262 | enum | |
263 | { | |
264 | table_size = sizeof (elf_z80_howto_table) / sizeof (elf_z80_howto_table[0]) | |
265 | }; | |
266 | unsigned int i; | |
267 | ||
268 | for (i = 0; i < table_size; i++) | |
269 | { | |
270 | if (elf_z80_howto_table[i].r_type == code) | |
271 | return &elf_z80_howto_table[i].howto; | |
272 | } | |
273 | ||
274 | printf ("%s:%d Not found type %d\n", __FILE__, __LINE__, code); | |
275 | ||
276 | return NULL; | |
277 | } | |
278 | ||
279 | static reloc_howto_type * | |
280 | bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) | |
281 | { | |
282 | enum | |
283 | { | |
284 | table_size = sizeof (elf_z80_howto_table) / sizeof (elf_z80_howto_table[0]) | |
285 | }; | |
286 | unsigned int i; | |
287 | ||
288 | for (i = 0; i < table_size; i++) | |
289 | { | |
290 | if (elf_z80_howto_table[i].howto.name != NULL | |
291 | && strcasecmp (elf_z80_howto_table[i].howto.name, r_name) == 0) | |
292 | return &elf_z80_howto_table[i].howto; | |
293 | } | |
294 | ||
295 | return NULL; | |
296 | } | |
297 | ||
298 | /* Set the howto pointer for an z80 ELF reloc. */ | |
299 | ||
300 | static bfd_boolean | |
301 | z80_info_to_howto_rel (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst) | |
302 | { | |
303 | enum | |
304 | { | |
305 | table_size = sizeof (elf_z80_howto_table) / sizeof (elf_z80_howto_table[0]) | |
306 | }; | |
307 | unsigned int i; | |
308 | unsigned int r_type = ELF32_R_TYPE (dst->r_info); | |
309 | ||
310 | for (i = 0; i < table_size; i++) | |
311 | { | |
312 | if (elf_z80_howto_table[i].howto.type == r_type) | |
313 | { | |
314 | cache_ptr->howto = &elf_z80_howto_table[i].howto; | |
315 | return TRUE; | |
316 | } | |
317 | } | |
318 | ||
319 | /* xgettext:c-format */ | |
320 | _bfd_error_handler (_("%pB: unsupported relocation type %#x"), | |
321 | abfd, r_type); | |
322 | bfd_set_error (bfd_error_bad_value); | |
323 | return FALSE; | |
324 | } | |
325 | ||
326 | static bfd_boolean | |
327 | z80_elf_set_mach_from_flags (bfd *abfd) | |
328 | { | |
329 | int mach; | |
330 | switch (elf_elfheader (abfd)->e_flags) | |
331 | { | |
332 | case EF_Z80_MACH_GBZ80: | |
333 | mach = bfd_mach_gbz80; | |
334 | break; | |
335 | case EF_Z80_MACH_Z80: | |
336 | mach = bfd_mach_z80; | |
337 | break; | |
338 | case EF_Z80_MACH_Z180: | |
339 | mach = bfd_mach_z180; | |
340 | break; | |
341 | case EF_Z80_MACH_EZ80_Z80: | |
342 | mach = bfd_mach_ez80_z80; | |
343 | break; | |
344 | case EF_Z80_MACH_EZ80_ADL: | |
345 | mach = bfd_mach_ez80_adl; | |
346 | break; | |
347 | case EF_Z80_MACH_R800: | |
348 | mach = bfd_mach_r800; | |
349 | break; | |
350 | default: | |
351 | mach = bfd_mach_z80; | |
352 | break; | |
353 | } | |
354 | ||
355 | bfd_default_set_arch_mach (abfd, bfd_arch_z80, mach); | |
356 | return TRUE; | |
357 | } | |
358 | ||
359 | static int | |
360 | z80_is_local_label_name (bfd * abfd ATTRIBUTE_UNUSED, | |
361 | const char * name) | |
362 | { | |
363 | return (name[0] == '.' && name[1] == 'L') || | |
364 | _bfd_elf_is_local_label_name (abfd, name); | |
365 | } | |
366 | ||
367 | ||
368 | #define ELF_ARCH bfd_arch_z80 | |
369 | #define ELF_MACHINE_CODE EM_Z80 | |
370 | #define ELF_MAXPAGESIZE 0x10000 | |
371 | ||
372 | #define TARGET_LITTLE_SYM z80_elf32_vec | |
373 | #define TARGET_LITTLE_NAME "elf32-z80" | |
374 | ||
375 | #define elf_info_to_howto NULL | |
376 | #define elf_info_to_howto_rel z80_info_to_howto_rel | |
377 | #define elf_backend_object_p z80_elf_set_mach_from_flags | |
378 | #define bfd_elf32_bfd_is_local_label_name z80_is_local_label_name | |
379 | ||
380 | #include "elf32-target.h" |