]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - bfd/elf32-xstormy16.c
bfd/
[thirdparty/binutils-gdb.git] / bfd / elf32-xstormy16.c
1 /* XSTORMY16-specific support for 32-bit ELF.
2 Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
3
4 This file is part of BFD, the Binary File Descriptor library.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19
20 #include "bfd.h"
21 #include "sysdep.h"
22 #include "libbfd.h"
23 #include "elf-bfd.h"
24 #include "elf/xstormy16.h"
25 #include "libiberty.h"
26
27 /* Forward declarations. */
28 static reloc_howto_type * xstormy16_reloc_type_lookup
29 PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
30 static void xstormy16_info_to_howto_rela
31 PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
32 static bfd_reloc_status_type xstormy16_elf_24_reloc
33 PARAMS ((bfd *abfd, arelent *reloc_entry, asymbol *symbol,
34 PTR data, asection *input_section, bfd *output_bfd,
35 char **error_message));
36 static bfd_boolean xstormy16_elf_check_relocs
37 PARAMS ((bfd *, struct bfd_link_info *, asection *,
38 const Elf_Internal_Rela *));
39 static bfd_boolean xstormy16_relax_plt_check
40 PARAMS ((struct elf_link_hash_entry *, PTR));
41 static bfd_boolean xstormy16_relax_plt_realloc
42 PARAMS ((struct elf_link_hash_entry *, PTR));
43 static bfd_boolean xstormy16_elf_relax_section
44 PARAMS ((bfd *abfd, asection *sec, struct bfd_link_info *link_info,
45 bfd_boolean *again));
46 static bfd_boolean xstormy16_elf_always_size_sections
47 PARAMS ((bfd *, struct bfd_link_info *));
48 static bfd_boolean xstormy16_elf_relocate_section
49 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
50 Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
51 static bfd_boolean xstormy16_elf_finish_dynamic_sections
52 PARAMS((bfd *, struct bfd_link_info *));
53 static bfd_boolean xstormy16_elf_gc_sweep_hook
54 PARAMS ((bfd *, struct bfd_link_info *, asection *,
55 const Elf_Internal_Rela *));
56 static asection * xstormy16_elf_gc_mark_hook
57 PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
58 struct elf_link_hash_entry *, Elf_Internal_Sym *));
59
60 static reloc_howto_type xstormy16_elf_howto_table [] =
61 {
62 /* This reloc does nothing. */
63 HOWTO (R_XSTORMY16_NONE, /* type */
64 0, /* rightshift */
65 2, /* size (0 = byte, 1 = short, 2 = long) */
66 32, /* bitsize */
67 FALSE, /* pc_relative */
68 0, /* bitpos */
69 complain_overflow_bitfield, /* complain_on_overflow */
70 bfd_elf_generic_reloc, /* special_function */
71 "R_XSTORMY16_NONE", /* name */
72 FALSE, /* partial_inplace */
73 0, /* src_mask */
74 0, /* dst_mask */
75 FALSE), /* pcrel_offset */
76
77 /* A 32 bit absolute relocation. */
78 HOWTO (R_XSTORMY16_32, /* type */
79 0, /* rightshift */
80 2, /* size (0 = byte, 1 = short, 2 = long) */
81 32, /* bitsize */
82 FALSE, /* pc_relative */
83 0, /* bitpos */
84 complain_overflow_dont, /* complain_on_overflow */
85 bfd_elf_generic_reloc, /* special_function */
86 "R_XSTORMY16_32", /* name */
87 FALSE, /* partial_inplace */
88 0, /* src_mask */
89 0xffffffff, /* dst_mask */
90 FALSE), /* pcrel_offset */
91
92 /* A 16 bit absolute relocation. */
93 HOWTO (R_XSTORMY16_16, /* type */
94 0, /* rightshift */
95 1, /* size (0 = byte, 1 = short, 2 = long) */
96 16, /* bitsize */
97 FALSE, /* pc_relative */
98 0, /* bitpos */
99 complain_overflow_bitfield, /* complain_on_overflow */
100 bfd_elf_generic_reloc, /* special_function */
101 "R_XSTORMY16_16", /* name */
102 FALSE, /* partial_inplace */
103 0, /* src_mask */
104 0xffff, /* dst_mask */
105 FALSE), /* pcrel_offset */
106
107 /* An 8 bit absolute relocation. */
108 HOWTO (R_XSTORMY16_8, /* type */
109 0, /* rightshift */
110 0, /* size (0 = byte, 1 = short, 2 = long) */
111 8, /* bitsize */
112 FALSE, /* pc_relative */
113 0, /* bitpos */
114 complain_overflow_unsigned, /* complain_on_overflow */
115 bfd_elf_generic_reloc, /* special_function */
116 "R_XSTORMY16_8", /* name */
117 FALSE, /* partial_inplace */
118 0, /* src_mask */
119 0xff, /* dst_mask */
120 FALSE), /* pcrel_offset */
121
122 /* A 32 bit pc-relative relocation. */
123 HOWTO (R_XSTORMY16_PC32, /* type */
124 0, /* rightshift */
125 2, /* size (0 = byte, 1 = short, 2 = long) */
126 32, /* bitsize */
127 TRUE, /* pc_relative */
128 0, /* bitpos */
129 complain_overflow_dont, /* complain_on_overflow */
130 bfd_elf_generic_reloc, /* special_function */
131 "R_XSTORMY16_PC32", /* name */
132 FALSE, /* partial_inplace */
133 0, /* src_mask */
134 0xffffffff, /* dst_mask */
135 TRUE), /* pcrel_offset */
136
137 /* A 16 bit pc-relative relocation. */
138 HOWTO (R_XSTORMY16_PC16, /* type */
139 0, /* rightshift */
140 1, /* size (0 = byte, 1 = short, 2 = long) */
141 16, /* bitsize */
142 TRUE, /* pc_relative */
143 0, /* bitpos */
144 complain_overflow_signed, /* complain_on_overflow */
145 bfd_elf_generic_reloc, /* special_function */
146 "R_XSTORMY16_PC16", /* name */
147 FALSE, /* partial_inplace */
148 0, /* src_mask */
149 0xffffffff, /* dst_mask */
150 TRUE), /* pcrel_offset */
151
152 /* An 8 bit pc-relative relocation. */
153 HOWTO (R_XSTORMY16_PC8, /* type */
154 0, /* rightshift */
155 0, /* size (0 = byte, 1 = short, 2 = long) */
156 8, /* bitsize */
157 TRUE, /* pc_relative */
158 0, /* bitpos */
159 complain_overflow_signed, /* complain_on_overflow */
160 bfd_elf_generic_reloc, /* special_function */
161 "R_XSTORMY16_PC8", /* name */
162 FALSE, /* partial_inplace */
163 0, /* src_mask */
164 0xffffffff, /* dst_mask */
165 TRUE), /* pcrel_offset */
166
167 /* A 12-bit pc-relative relocation suitable for the branch instructions. */
168 HOWTO (R_XSTORMY16_REL_12, /* type */
169 1, /* rightshift */
170 1, /* size (0 = byte, 1 = short, 2 = long) */
171 11, /* bitsize */
172 TRUE, /* pc_relative */
173 1, /* bitpos */
174 complain_overflow_signed, /* complain_on_overflow */
175 bfd_elf_generic_reloc, /* special_function */
176 "R_XSTORMY16_REL_12", /* name */
177 FALSE, /* partial_inplace */
178 0, /* src_mask */
179 0x0ffe, /* dst_mask */
180 TRUE), /* pcrel_offset */
181
182 /* A 24-bit absolute relocation suitable for the jump instructions. */
183 HOWTO (R_XSTORMY16_24, /* type */
184 0, /* rightshift */
185 2, /* size (0 = byte, 1 = short, 2 = long) */
186 24, /* bitsize */
187 FALSE, /* pc_relative */
188 0, /* bitpos */
189 complain_overflow_unsigned, /* complain_on_overflow */
190 xstormy16_elf_24_reloc, /* special_function */
191 "R_XSTORMY16_24", /* name */
192 TRUE, /* partial_inplace */
193 0, /* src_mask */
194 0xffff00ff, /* dst_mask */
195 TRUE), /* pcrel_offset */
196
197 /* A 16 bit absolute relocation to a function pointer. */
198 HOWTO (R_XSTORMY16_FPTR16, /* type */
199 0, /* rightshift */
200 1, /* size (0 = byte, 1 = short, 2 = long) */
201 16, /* bitsize */
202 FALSE, /* pc_relative */
203 0, /* bitpos */
204 complain_overflow_bitfield, /* complain_on_overflow */
205 bfd_elf_generic_reloc, /* special_function */
206 "R_XSTORMY16_FPTR16", /* name */
207 FALSE, /* partial_inplace */
208 0, /* src_mask */
209 0xffffffff, /* dst_mask */
210 FALSE), /* pcrel_offset */
211
212 /* Low order 16 bit value of a high memory address. */
213 HOWTO (R_XSTORMY16_LO16, /* type */
214 0, /* rightshift */
215 1, /* size (0 = byte, 1 = short, 2 = long) */
216 16, /* bitsize */
217 FALSE, /* pc_relative */
218 0, /* bitpos */
219 complain_overflow_dont, /* complain_on_overflow */
220 bfd_elf_generic_reloc, /* special_function */
221 "R_XSTORMY16_LO16", /* name */
222 FALSE, /* partial_inplace */
223 0, /* src_mask */
224 0xffff, /* dst_mask */
225 FALSE), /* pcrel_offset */
226
227 /* High order 16 bit value of a high memory address. */
228 HOWTO (R_XSTORMY16_HI16, /* type */
229 16, /* rightshift */
230 1, /* size (0 = byte, 1 = short, 2 = long) */
231 16, /* bitsize */
232 FALSE, /* pc_relative */
233 0, /* bitpos */
234 complain_overflow_dont, /* complain_on_overflow */
235 bfd_elf_generic_reloc, /* special_function */
236 "R_XSTORMY16_HI16", /* name */
237 FALSE, /* partial_inplace */
238 0, /* src_mask */
239 0xffff, /* dst_mask */
240 FALSE), /* pcrel_offset */
241
242 /* A 12 bit absolute relocation. */
243 HOWTO (R_XSTORMY16_12, /* type */
244 0, /* rightshift */
245 1, /* size (0 = byte, 1 = short, 2 = long) */
246 12, /* bitsize */
247 FALSE, /* pc_relative */
248 0, /* bitpos */
249 complain_overflow_signed, /* complain_on_overflow */
250 bfd_elf_generic_reloc, /* special_function */
251 "R_XSTORMY16_12", /* name */
252 FALSE, /* partial_inplace */
253 0x0000, /* src_mask */
254 0x0fff, /* dst_mask */
255 FALSE), /* pcrel_offset */
256 };
257
258 static reloc_howto_type xstormy16_elf_howto_table2 [] =
259 {
260 /* GNU extension to record C++ vtable hierarchy */
261 HOWTO (R_XSTORMY16_GNU_VTINHERIT, /* type */
262 0, /* rightshift */
263 2, /* size (0 = byte, 1 = short, 2 = long) */
264 0, /* bitsize */
265 FALSE, /* pc_relative */
266 0, /* bitpos */
267 complain_overflow_dont, /* complain_on_overflow */
268 NULL, /* special_function */
269 "R_XSTORMY16_GNU_VTINHERIT", /* name */
270 FALSE, /* partial_inplace */
271 0, /* src_mask */
272 0, /* dst_mask */
273 FALSE), /* pcrel_offset */
274
275 /* GNU extension to record C++ vtable member usage */
276 HOWTO (R_XSTORMY16_GNU_VTENTRY, /* type */
277 0, /* rightshift */
278 2, /* size (0 = byte, 1 = short, 2 = long) */
279 0, /* bitsize */
280 FALSE, /* pc_relative */
281 0, /* bitpos */
282 complain_overflow_dont, /* complain_on_overflow */
283 _bfd_elf_rel_vtable_reloc_fn, /* special_function */
284 "R_XSTORMY16_GNU_VTENTRY", /* name */
285 FALSE, /* partial_inplace */
286 0, /* src_mask */
287 0, /* dst_mask */
288 FALSE), /* pcrel_offset */
289
290 };
291 \f
292 /* Map BFD reloc types to XSTORMY16 ELF reloc types. */
293
294 typedef struct xstormy16_reloc_map
295 {
296 bfd_reloc_code_real_type bfd_reloc_val;
297 unsigned int xstormy16_reloc_val;
298 reloc_howto_type * table;
299 } reloc_map;
300
301 static const reloc_map xstormy16_reloc_map [] =
302 {
303 { BFD_RELOC_NONE, R_XSTORMY16_NONE, xstormy16_elf_howto_table },
304 { BFD_RELOC_32, R_XSTORMY16_32, xstormy16_elf_howto_table },
305 { BFD_RELOC_16, R_XSTORMY16_16, xstormy16_elf_howto_table },
306 { BFD_RELOC_8, R_XSTORMY16_8, xstormy16_elf_howto_table },
307 { BFD_RELOC_32_PCREL, R_XSTORMY16_PC32, xstormy16_elf_howto_table },
308 { BFD_RELOC_16_PCREL, R_XSTORMY16_PC16, xstormy16_elf_howto_table },
309 { BFD_RELOC_8_PCREL, R_XSTORMY16_PC8, xstormy16_elf_howto_table },
310 { BFD_RELOC_XSTORMY16_REL_12, R_XSTORMY16_REL_12, xstormy16_elf_howto_table },
311 { BFD_RELOC_XSTORMY16_24, R_XSTORMY16_24, xstormy16_elf_howto_table },
312 { BFD_RELOC_XSTORMY16_FPTR16, R_XSTORMY16_FPTR16, xstormy16_elf_howto_table },
313 { BFD_RELOC_LO16, R_XSTORMY16_LO16, xstormy16_elf_howto_table },
314 { BFD_RELOC_HI16, R_XSTORMY16_HI16, xstormy16_elf_howto_table },
315 { BFD_RELOC_XSTORMY16_12, R_XSTORMY16_12, xstormy16_elf_howto_table },
316 { BFD_RELOC_VTABLE_INHERIT, R_XSTORMY16_GNU_VTINHERIT, xstormy16_elf_howto_table2 },
317 { BFD_RELOC_VTABLE_ENTRY, R_XSTORMY16_GNU_VTENTRY, xstormy16_elf_howto_table2 },
318 };
319
320 static reloc_howto_type *
321 xstormy16_reloc_type_lookup (abfd, code)
322 bfd * abfd ATTRIBUTE_UNUSED;
323 bfd_reloc_code_real_type code;
324 {
325 unsigned int i;
326
327 for (i = ARRAY_SIZE (xstormy16_reloc_map); --i;)
328 {
329 const reloc_map * entry;
330
331 entry = xstormy16_reloc_map + i;
332
333 if (entry->bfd_reloc_val == code)
334 return entry->table + (entry->xstormy16_reloc_val
335 - entry->table[0].type);
336 }
337
338 return NULL;
339 }
340
341 /* Set the howto pointer for an XSTORMY16 ELF reloc. */
342
343 static void
344 xstormy16_info_to_howto_rela (abfd, cache_ptr, dst)
345 bfd * abfd ATTRIBUTE_UNUSED;
346 arelent * cache_ptr;
347 Elf_Internal_Rela * dst;
348 {
349 unsigned int r_type = ELF32_R_TYPE (dst->r_info);
350
351 if (r_type <= (unsigned int) R_XSTORMY16_12)
352 cache_ptr->howto = &xstormy16_elf_howto_table [r_type];
353 else if (r_type - R_XSTORMY16_GNU_VTINHERIT
354 <= (unsigned int) R_XSTORMY16_GNU_VTENTRY)
355 cache_ptr->howto
356 = &xstormy16_elf_howto_table2 [r_type - R_XSTORMY16_GNU_VTINHERIT];
357 else
358 abort ();
359 }
360
361 /* Handle the R_XSTORMY16_24 reloc, which has an odd bit arrangement. */
362
363 static bfd_reloc_status_type
364 xstormy16_elf_24_reloc (abfd, reloc_entry, symbol, data, input_section,
365 output_bfd, error_message)
366 bfd *abfd;
367 arelent *reloc_entry;
368 asymbol *symbol;
369 PTR data;
370 asection *input_section;
371 bfd *output_bfd;
372 char **error_message ATTRIBUTE_UNUSED;
373 {
374 bfd_vma relocation, x;
375 bfd_size_type sz;
376
377 if (output_bfd != NULL)
378 {
379 reloc_entry->address += input_section->output_offset;
380 return bfd_reloc_ok;
381 }
382
383 sz = input_section->rawsize ? input_section->rawsize : input_section->size;
384 if (reloc_entry->address > sz)
385 return bfd_reloc_outofrange;
386
387 if (bfd_is_com_section (symbol->section))
388 relocation = 0;
389 else
390 relocation = symbol->value;
391
392 relocation += symbol->section->output_section->vma;
393 relocation += symbol->section->output_offset;
394 relocation += reloc_entry->addend;
395
396 x = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
397 x &= 0x0000ff00;
398 x |= relocation & 0xff;
399 x |= (relocation << 8) & 0xffff0000;
400 bfd_put_32 (abfd, x, (bfd_byte *) data + reloc_entry->address);
401
402 if (relocation & ~ (bfd_vma) 0xffffff)
403 return bfd_reloc_overflow;
404
405 return bfd_reloc_ok;
406 }
407 \f
408 /* We support 16-bit pointers to code above 64k by generating a thunk
409 below 64k containing a JMPF instruction to the final address. We
410 cannot, unfortunately, minimize the number of thunks unless the
411 -relax switch is given, as otherwise we have no idea where the
412 sections will fall in the address space. */
413
414 static bfd_boolean
415 xstormy16_elf_check_relocs (abfd, info, sec, relocs)
416 bfd *abfd;
417 struct bfd_link_info *info;
418 asection *sec;
419 const Elf_Internal_Rela *relocs;
420 {
421 const Elf_Internal_Rela *rel, *relend;
422 struct elf_link_hash_entry **sym_hashes;
423 Elf_Internal_Shdr *symtab_hdr;
424 bfd_vma *local_plt_offsets;
425 asection *splt;
426 bfd *dynobj;
427
428 if (info->relocatable)
429 return TRUE;
430
431 symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
432 sym_hashes = elf_sym_hashes (abfd);
433 local_plt_offsets = elf_local_got_offsets (abfd);
434 splt = NULL;
435 dynobj = elf_hash_table(info)->dynobj;
436
437 relend = relocs + sec->reloc_count;
438 for (rel = relocs; rel < relend; ++rel)
439 {
440 unsigned long r_symndx;
441 struct elf_link_hash_entry *h;
442 bfd_vma *offset;
443
444 r_symndx = ELF32_R_SYM (rel->r_info);
445 if (r_symndx < symtab_hdr->sh_info)
446 h = NULL;
447 else
448 {
449 h = sym_hashes[r_symndx - symtab_hdr->sh_info];
450 while (h->root.type == bfd_link_hash_indirect
451 || h->root.type == bfd_link_hash_warning)
452 h = (struct elf_link_hash_entry *) h->root.u.i.link;
453 }
454
455 switch (ELF32_R_TYPE (rel->r_info))
456 {
457 /* This relocation describes a 16-bit pointer to a function.
458 We may need to allocate a thunk in low memory; reserve memory
459 for it now. */
460 case R_XSTORMY16_FPTR16:
461 if (rel->r_addend != 0)
462 {
463 (*info->callbacks->warning)
464 (info, _("non-zero addend in @fptr reloc"), 0,
465 abfd, 0, 0);
466 }
467
468 if (dynobj == NULL)
469 elf_hash_table (info)->dynobj = dynobj = abfd;
470 if (splt == NULL)
471 {
472 splt = bfd_get_section_by_name (dynobj, ".plt");
473 if (splt == NULL)
474 {
475 splt = bfd_make_section (dynobj, ".plt");
476 if (splt == NULL
477 || ! bfd_set_section_flags (dynobj, splt,
478 (SEC_ALLOC
479 | SEC_LOAD
480 | SEC_HAS_CONTENTS
481 | SEC_IN_MEMORY
482 | SEC_LINKER_CREATED
483 | SEC_READONLY
484 | SEC_CODE))
485 || ! bfd_set_section_alignment (dynobj, splt, 1))
486 return FALSE;
487 }
488 }
489
490 if (h != NULL)
491 offset = &h->plt.offset;
492 else
493 {
494 if (local_plt_offsets == NULL)
495 {
496 size_t size;
497 unsigned int i;
498
499 size = symtab_hdr->sh_info * sizeof (bfd_vma);
500 local_plt_offsets = (bfd_vma *) bfd_alloc (abfd, size);
501 if (local_plt_offsets == NULL)
502 return FALSE;
503 elf_local_got_offsets (abfd) = local_plt_offsets;
504
505 for (i = 0; i < symtab_hdr->sh_info; i++)
506 local_plt_offsets[i] = (bfd_vma) -1;
507 }
508 offset = &local_plt_offsets[r_symndx];
509 }
510
511 if (*offset == (bfd_vma) -1)
512 {
513 *offset = splt->size;
514 splt->size += 4;
515 }
516 break;
517
518 /* This relocation describes the C++ object vtable hierarchy.
519 Reconstruct it for later use during GC. */
520 case R_XSTORMY16_GNU_VTINHERIT:
521 if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
522 return FALSE;
523 break;
524
525 /* This relocation describes which C++ vtable entries are actually
526 used. Record for later use during GC. */
527 case R_XSTORMY16_GNU_VTENTRY:
528 if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
529 return FALSE;
530 break;
531 }
532 }
533
534 return TRUE;
535 }
536
537 /* A subroutine of xstormy16_elf_relax_section. If the global symbol H
538 is within the low 64k, remove any entry for it in the plt. */
539
540 struct relax_plt_data
541 {
542 asection *splt;
543 bfd_boolean *again;
544 };
545
546 static bfd_boolean
547 xstormy16_relax_plt_check (h, xdata)
548 struct elf_link_hash_entry *h;
549 PTR xdata;
550 {
551 struct relax_plt_data *data = (struct relax_plt_data *) xdata;
552
553 if (h->root.type == bfd_link_hash_warning)
554 h = (struct elf_link_hash_entry *) h->root.u.i.link;
555
556 if (h->plt.offset != (bfd_vma) -1)
557 {
558 bfd_vma address;
559
560 if (h->root.type == bfd_link_hash_undefined
561 || h->root.type == bfd_link_hash_undefweak)
562 address = 0;
563 else
564 address = (h->root.u.def.section->output_section->vma
565 + h->root.u.def.section->output_offset
566 + h->root.u.def.value);
567
568 if (address <= 0xffff)
569 {
570 h->plt.offset = -1;
571 data->splt->size -= 4;
572 *data->again = TRUE;
573 }
574 }
575
576 return TRUE;
577 }
578
579 /* A subroutine of xstormy16_elf_relax_section. If the global symbol H
580 previously had a plt entry, give it a new entry offset. */
581
582 static bfd_boolean
583 xstormy16_relax_plt_realloc (h, xdata)
584 struct elf_link_hash_entry *h;
585 PTR xdata;
586 {
587 bfd_vma *entry = (bfd_vma *) xdata;
588
589 if (h->root.type == bfd_link_hash_warning)
590 h = (struct elf_link_hash_entry *) h->root.u.i.link;
591
592 if (h->plt.offset != (bfd_vma) -1)
593 {
594 h->plt.offset = *entry;
595 *entry += 4;
596 }
597
598 return TRUE;
599 }
600
601 static bfd_boolean
602 xstormy16_elf_relax_section (dynobj, splt, info, again)
603 bfd *dynobj;
604 asection *splt;
605 struct bfd_link_info *info;
606 bfd_boolean *again;
607 {
608 struct relax_plt_data relax_plt_data;
609 bfd *ibfd;
610
611 /* Assume nothing changes. */
612 *again = FALSE;
613
614 if (info->relocatable)
615 return TRUE;
616
617 /* We only relax the .plt section at the moment. */
618 if (dynobj != elf_hash_table (info)->dynobj
619 || strcmp (splt->name, ".plt") != 0)
620 return TRUE;
621
622 /* Quick check for an empty plt. */
623 if (splt->size == 0)
624 return TRUE;
625
626 /* Map across all global symbols; see which ones happen to
627 fall in the low 64k. */
628 relax_plt_data.splt = splt;
629 relax_plt_data.again = again;
630 elf_link_hash_traverse (elf_hash_table (info), xstormy16_relax_plt_check,
631 &relax_plt_data);
632
633 /* Likewise for local symbols, though that's somewhat less convenient
634 as we have to walk the list of input bfds and swap in symbol data. */
635 for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
636 {
637 bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
638 Elf_Internal_Shdr *symtab_hdr;
639 Elf_Internal_Sym *isymbuf = NULL;
640 unsigned int idx;
641
642 if (! local_plt_offsets)
643 continue;
644
645 symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
646 if (symtab_hdr->sh_info != 0)
647 {
648 isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
649 if (isymbuf == NULL)
650 isymbuf = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
651 symtab_hdr->sh_info, 0,
652 NULL, NULL, NULL);
653 if (isymbuf == NULL)
654 return FALSE;
655 }
656
657 for (idx = 0; idx < symtab_hdr->sh_info; ++idx)
658 {
659 Elf_Internal_Sym *isym;
660 asection *tsec;
661 bfd_vma address;
662
663 if (local_plt_offsets[idx] == (bfd_vma) -1)
664 continue;
665
666 isym = &isymbuf[idx];
667 if (isym->st_shndx == SHN_UNDEF)
668 continue;
669 else if (isym->st_shndx == SHN_ABS)
670 tsec = bfd_abs_section_ptr;
671 else if (isym->st_shndx == SHN_COMMON)
672 tsec = bfd_com_section_ptr;
673 else
674 tsec = bfd_section_from_elf_index (ibfd, isym->st_shndx);
675
676 address = (tsec->output_section->vma
677 + tsec->output_offset
678 + isym->st_value);
679 if (address <= 0xffff)
680 {
681 local_plt_offsets[idx] = -1;
682 splt->size -= 4;
683 *again = TRUE;
684 }
685 }
686
687 if (isymbuf != NULL
688 && symtab_hdr->contents != (unsigned char *) isymbuf)
689 {
690 if (! info->keep_memory)
691 free (isymbuf);
692 else
693 {
694 /* Cache the symbols for elf_link_input_bfd. */
695 symtab_hdr->contents = (unsigned char *) isymbuf;
696 }
697 }
698 }
699
700 /* If we changed anything, walk the symbols again to reallocate
701 .plt entry addresses. */
702 if (*again && splt->size > 0)
703 {
704 bfd_vma entry = 0;
705
706 elf_link_hash_traverse (elf_hash_table (info),
707 xstormy16_relax_plt_realloc, &entry);
708
709 for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
710 {
711 bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
712 unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info;
713 unsigned int idx;
714
715 if (! local_plt_offsets)
716 continue;
717
718 for (idx = 0; idx < nlocals; ++idx)
719 if (local_plt_offsets[idx] != (bfd_vma) -1)
720 {
721 local_plt_offsets[idx] = entry;
722 entry += 4;
723 }
724 }
725 }
726
727 return TRUE;
728 }
729
730 static bfd_boolean
731 xstormy16_elf_always_size_sections (output_bfd, info)
732 bfd *output_bfd ATTRIBUTE_UNUSED;
733 struct bfd_link_info *info;
734 {
735 bfd *dynobj;
736 asection *splt;
737
738 if (info->relocatable)
739 return TRUE;
740
741 dynobj = elf_hash_table (info)->dynobj;
742 if (dynobj == NULL)
743 return TRUE;
744
745 splt = bfd_get_section_by_name (dynobj, ".plt");
746 BFD_ASSERT (splt != NULL);
747
748 splt->contents = (bfd_byte *) bfd_zalloc (dynobj, splt->size);
749 if (splt->contents == NULL)
750 return FALSE;
751
752 return TRUE;
753 }
754 \f
755 /* Relocate an XSTORMY16 ELF section.
756
757 The RELOCATE_SECTION function is called by the new ELF backend linker
758 to handle the relocations for a section.
759
760 The relocs are always passed as Rela structures; if the section
761 actually uses Rel structures, the r_addend field will always be
762 zero.
763
764 This function is responsible for adjusting the section contents as
765 necessary, and (if using Rela relocs and generating a relocatable
766 output file) adjusting the reloc addend as necessary.
767
768 This function does not have to worry about setting the reloc
769 address or the reloc symbol index.
770
771 LOCAL_SYMS is a pointer to the swapped in local symbols.
772
773 LOCAL_SECTIONS is an array giving the section in the input file
774 corresponding to the st_shndx field of each local symbol.
775
776 The global hash table entry for the global symbols can be found
777 via elf_sym_hashes (input_bfd).
778
779 When generating relocatable output, this function must handle
780 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
781 going to be the section symbol corresponding to the output
782 section, which means that the addend must be adjusted
783 accordingly. */
784
785 static bfd_boolean
786 xstormy16_elf_relocate_section (output_bfd, info, input_bfd, input_section,
787 contents, relocs, local_syms, local_sections)
788 bfd * output_bfd ATTRIBUTE_UNUSED;
789 struct bfd_link_info * info;
790 bfd * input_bfd;
791 asection * input_section;
792 bfd_byte * contents;
793 Elf_Internal_Rela * relocs;
794 Elf_Internal_Sym * local_syms;
795 asection ** local_sections;
796 {
797 Elf_Internal_Shdr * symtab_hdr;
798 struct elf_link_hash_entry ** sym_hashes;
799 Elf_Internal_Rela * rel;
800 Elf_Internal_Rela * relend;
801 bfd *dynobj;
802 asection *splt;
803
804 if (info->relocatable)
805 return TRUE;
806
807 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
808 sym_hashes = elf_sym_hashes (input_bfd);
809 relend = relocs + input_section->reloc_count;
810
811 dynobj = elf_hash_table (info)->dynobj;
812 splt = NULL;
813 if (dynobj != NULL)
814 splt = bfd_get_section_by_name (dynobj, ".plt");
815
816 for (rel = relocs; rel < relend; rel ++)
817 {
818 reloc_howto_type * howto;
819 unsigned long r_symndx;
820 Elf_Internal_Sym * sym;
821 asection * sec;
822 struct elf_link_hash_entry * h;
823 bfd_vma relocation;
824 bfd_reloc_status_type r;
825 const char * name = NULL;
826 int r_type;
827
828 r_type = ELF32_R_TYPE (rel->r_info);
829
830 if ( r_type == R_XSTORMY16_GNU_VTINHERIT
831 || r_type == R_XSTORMY16_GNU_VTENTRY)
832 continue;
833
834 r_symndx = ELF32_R_SYM (rel->r_info);
835 howto = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info);
836 h = NULL;
837 sym = NULL;
838 sec = NULL;
839
840 if (r_symndx < symtab_hdr->sh_info)
841 {
842 sym = local_syms + r_symndx;
843 sec = local_sections [r_symndx];
844 relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
845
846 name = bfd_elf_string_from_elf_section
847 (input_bfd, symtab_hdr->sh_link, sym->st_name);
848 name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
849 }
850 else
851 {
852 bfd_boolean unresolved_reloc, warned;
853
854 RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
855 r_symndx, symtab_hdr, sym_hashes,
856 h, sec, relocation,
857 unresolved_reloc, warned);
858 }
859
860 switch (ELF32_R_TYPE (rel->r_info))
861 {
862 case R_XSTORMY16_24:
863 {
864 bfd_vma reloc = relocation + rel->r_addend;
865 unsigned int x;
866
867 x = bfd_get_32 (input_bfd, contents + rel->r_offset);
868 x &= 0x0000ff00;
869 x |= reloc & 0xff;
870 x |= (reloc << 8) & 0xffff0000;
871 bfd_put_32 (input_bfd, x, contents + rel->r_offset);
872
873 if (reloc & ~0xffffff)
874 r = bfd_reloc_overflow;
875 else
876 r = bfd_reloc_ok;
877 break;
878 }
879
880 case R_XSTORMY16_FPTR16:
881 {
882 bfd_vma *plt_offset;
883
884 if (h != NULL)
885 plt_offset = &h->plt.offset;
886 else
887 plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
888
889 if (relocation <= 0xffff)
890 {
891 /* If the symbol is in range for a 16-bit address, we should
892 have deallocated the plt entry in relax_section. */
893 BFD_ASSERT (*plt_offset == (bfd_vma) -1);
894 }
895 else
896 {
897 /* If the symbol is out of range for a 16-bit address,
898 we must have allocated a plt entry. */
899 BFD_ASSERT (*plt_offset != (bfd_vma) -1);
900
901 /* If this is the first time we've processed this symbol,
902 fill in the plt entry with the correct symbol address. */
903 if ((*plt_offset & 1) == 0)
904 {
905 unsigned int x;
906
907 x = 0x00000200; /* jmpf */
908 x |= relocation & 0xff;
909 x |= (relocation << 8) & 0xffff0000;
910 bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
911 *plt_offset |= 1;
912 }
913
914 relocation = (splt->output_section->vma
915 + splt->output_offset
916 + (*plt_offset & -2));
917 }
918 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
919 contents, rel->r_offset,
920 relocation, 0);
921 break;
922 }
923
924 default:
925 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
926 contents, rel->r_offset,
927 relocation, rel->r_addend);
928 break;
929 }
930
931 if (r != bfd_reloc_ok)
932 {
933 const char * msg = (const char *) NULL;
934
935 switch (r)
936 {
937 case bfd_reloc_overflow:
938 r = info->callbacks->reloc_overflow
939 (info, name, howto->name, (bfd_vma) 0,
940 input_bfd, input_section, rel->r_offset);
941 break;
942
943 case bfd_reloc_undefined:
944 r = info->callbacks->undefined_symbol
945 (info, name, input_bfd, input_section, rel->r_offset,
946 TRUE);
947 break;
948
949 case bfd_reloc_outofrange:
950 msg = _("internal error: out of range error");
951 break;
952
953 case bfd_reloc_notsupported:
954 msg = _("internal error: unsupported relocation error");
955 break;
956
957 case bfd_reloc_dangerous:
958 msg = _("internal error: dangerous relocation");
959 break;
960
961 default:
962 msg = _("internal error: unknown error");
963 break;
964 }
965
966 if (msg)
967 r = info->callbacks->warning
968 (info, msg, name, input_bfd, input_section, rel->r_offset);
969
970 if (! r)
971 return FALSE;
972 }
973 }
974
975 return TRUE;
976 }
977
978 /* This must exist if dynobj is ever set. */
979
980 static bfd_boolean
981 xstormy16_elf_finish_dynamic_sections (abfd, info)
982 bfd *abfd ATTRIBUTE_UNUSED;
983 struct bfd_link_info *info;
984 {
985 bfd *dynobj;
986 asection *splt;
987
988 /* As an extra sanity check, verify that all plt entries have
989 been filled in. */
990
991 if ((dynobj = elf_hash_table (info)->dynobj) != NULL
992 && (splt = bfd_get_section_by_name (dynobj, ".plt")) != NULL)
993 {
994 bfd_byte *contents = splt->contents;
995 unsigned int i, size = splt->size;
996 for (i = 0; i < size; i += 4)
997 {
998 unsigned int x = bfd_get_32 (dynobj, contents + i);
999 BFD_ASSERT (x != 0);
1000 }
1001 }
1002
1003 return TRUE;
1004 }
1005 \f
1006 /* Return the section that should be marked against GC for a given
1007 relocation. */
1008
1009 static asection *
1010 xstormy16_elf_gc_mark_hook (sec, info, rel, h, sym)
1011 asection * sec;
1012 struct bfd_link_info * info ATTRIBUTE_UNUSED;
1013 Elf_Internal_Rela * rel;
1014 struct elf_link_hash_entry * h;
1015 Elf_Internal_Sym * sym;
1016 {
1017 if (h != NULL)
1018 {
1019 switch (ELF32_R_TYPE (rel->r_info))
1020 {
1021 case R_XSTORMY16_GNU_VTINHERIT:
1022 case R_XSTORMY16_GNU_VTENTRY:
1023 break;
1024
1025 default:
1026 switch (h->root.type)
1027 {
1028 case bfd_link_hash_defined:
1029 case bfd_link_hash_defweak:
1030 return h->root.u.def.section;
1031
1032 case bfd_link_hash_common:
1033 return h->root.u.c.p->section;
1034
1035 default:
1036 break;
1037 }
1038 }
1039 }
1040 else
1041 return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
1042
1043 return NULL;
1044 }
1045
1046 /* Update the got entry reference counts for the section being removed. */
1047
1048 static bfd_boolean
1049 xstormy16_elf_gc_sweep_hook (abfd, info, sec, relocs)
1050 bfd * abfd ATTRIBUTE_UNUSED;
1051 struct bfd_link_info * info ATTRIBUTE_UNUSED;
1052 asection * sec ATTRIBUTE_UNUSED;
1053 const Elf_Internal_Rela * relocs ATTRIBUTE_UNUSED;
1054 {
1055 return TRUE;
1056 }
1057 \f
1058 #define ELF_ARCH bfd_arch_xstormy16
1059 #define ELF_MACHINE_CODE EM_XSTORMY16
1060 #define ELF_MAXPAGESIZE 0x100
1061
1062 #define TARGET_LITTLE_SYM bfd_elf32_xstormy16_vec
1063 #define TARGET_LITTLE_NAME "elf32-xstormy16"
1064
1065 #define elf_info_to_howto_rel NULL
1066 #define elf_info_to_howto xstormy16_info_to_howto_rela
1067 #define elf_backend_relocate_section xstormy16_elf_relocate_section
1068 #define elf_backend_gc_mark_hook xstormy16_elf_gc_mark_hook
1069 #define elf_backend_gc_sweep_hook xstormy16_elf_gc_sweep_hook
1070 #define elf_backend_check_relocs xstormy16_elf_check_relocs
1071 #define elf_backend_always_size_sections \
1072 xstormy16_elf_always_size_sections
1073 #define elf_backend_finish_dynamic_sections \
1074 xstormy16_elf_finish_dynamic_sections
1075
1076 #define elf_backend_can_gc_sections 1
1077 #define elf_backend_rela_normal 1
1078
1079 #define bfd_elf32_bfd_reloc_type_lookup xstormy16_reloc_type_lookup
1080 #define bfd_elf32_bfd_relax_section xstormy16_elf_relax_section
1081
1082 #include "elf32-target.h"