Support for more than 64k ELF sections.
[binutils.git] / bfd / elf32-xstormy16.c
blob5d3d171eeac3dec291bf1119641d7edb52fe18a1
1 /* XSTORMY16-specific support for 32-bit ELF.
2 Copyright (C) 2000, 2001 Free Software Foundation, Inc.
4 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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. */
20 #include "bfd.h"
21 #include "sysdep.h"
22 #include "libbfd.h"
23 #include "elf-bfd.h"
24 #include "elf/xstormy16.h"
26 /* Forward declarations. */
27 static reloc_howto_type * xstormy16_reloc_type_lookup
28 PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
29 static void xstormy16_info_to_howto_rela
30 PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
31 static bfd_reloc_status_type xstormy16_elf_24_reloc
32 PARAMS ((bfd *abfd, arelent *reloc_entry, asymbol *symbol,
33 PTR data, asection *input_section, bfd *output_bfd,
34 char **error_message));
35 static boolean xstormy16_elf_check_relocs
36 PARAMS ((bfd *, struct bfd_link_info *, asection *,
37 const Elf_Internal_Rela *));
38 static boolean xstormy16_relax_plt_check
39 PARAMS ((struct elf_link_hash_entry *, PTR));
40 static boolean xstormy16_relax_plt_realloc
41 PARAMS ((struct elf_link_hash_entry *, PTR));
42 static boolean xstormy16_elf_relax_section
43 PARAMS ((bfd *abfd, asection *sec, struct bfd_link_info *link_info,
44 boolean *again));
45 static boolean xstormy16_elf_always_size_sections
46 PARAMS ((bfd *, struct bfd_link_info *));
47 static boolean xstormy16_elf_relocate_section
48 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
49 Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
50 static boolean xstormy16_elf_finish_dynamic_sections
51 PARAMS((bfd *, struct bfd_link_info *));
52 static boolean xstormy16_elf_gc_sweep_hook
53 PARAMS ((bfd *, struct bfd_link_info *, asection *,
54 const Elf_Internal_Rela *));
55 static asection * xstormy16_elf_gc_mark_hook
56 PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Rela *,
57 struct elf_link_hash_entry *, Elf_Internal_Sym *));
59 static reloc_howto_type xstormy16_elf_howto_table [] =
61 /* This reloc does nothing. */
62 HOWTO (R_XSTORMY16_NONE, /* type */
63 0, /* rightshift */
64 2, /* size (0 = byte, 1 = short, 2 = long) */
65 32, /* bitsize */
66 false, /* pc_relative */
67 0, /* bitpos */
68 complain_overflow_bitfield, /* complain_on_overflow */
69 bfd_elf_generic_reloc, /* special_function */
70 "R_XSTORMY16_NONE", /* name */
71 false, /* partial_inplace */
72 0, /* src_mask */
73 0, /* dst_mask */
74 false), /* pcrel_offset */
76 /* A 32 bit absolute relocation. */
77 HOWTO (R_XSTORMY16_32, /* type */
78 0, /* rightshift */
79 2, /* size (0 = byte, 1 = short, 2 = long) */
80 32, /* bitsize */
81 false, /* pc_relative */
82 0, /* bitpos */
83 complain_overflow_dont, /* complain_on_overflow */
84 bfd_elf_generic_reloc, /* special_function */
85 "R_XSTORMY16_32", /* name */
86 false, /* partial_inplace */
87 0, /* src_mask */
88 0xffffffff, /* dst_mask */
89 false), /* pcrel_offset */
91 /* A 16 bit absolute relocation. */
92 HOWTO (R_XSTORMY16_16, /* type */
93 0, /* rightshift */
94 1, /* size (0 = byte, 1 = short, 2 = long) */
95 16, /* bitsize */
96 false, /* pc_relative */
97 0, /* bitpos */
98 complain_overflow_bitfield, /* complain_on_overflow */
99 bfd_elf_generic_reloc, /* special_function */
100 "R_XSTORMY16_16", /* name */
101 false, /* partial_inplace */
102 0, /* src_mask */
103 0xffffffff, /* dst_mask */
104 false), /* pcrel_offset */
106 /* An 8 bit absolute relocation. */
107 HOWTO (R_XSTORMY16_8, /* type */
108 0, /* rightshift */
109 0, /* size (0 = byte, 1 = short, 2 = long) */
110 8, /* bitsize */
111 false, /* pc_relative */
112 0, /* bitpos */
113 complain_overflow_bitfield, /* complain_on_overflow */
114 bfd_elf_generic_reloc, /* special_function */
115 "R_XSTORMY16_8", /* name */
116 false, /* partial_inplace */
117 0, /* src_mask */
118 0xffffffff, /* dst_mask */
119 false), /* pcrel_offset */
121 /* A 32 bit pc-relative relocation. */
122 HOWTO (R_XSTORMY16_PC32, /* type */
123 0, /* rightshift */
124 2, /* size (0 = byte, 1 = short, 2 = long) */
125 32, /* bitsize */
126 true, /* pc_relative */
127 0, /* bitpos */
128 complain_overflow_dont, /* complain_on_overflow */
129 bfd_elf_generic_reloc, /* special_function */
130 "R_XSTORMY16_PC32", /* name */
131 false, /* partial_inplace */
132 0, /* src_mask */
133 0xffffffff, /* dst_mask */
134 true), /* pcrel_offset */
136 /* A 16 bit pc-relative relocation. */
137 HOWTO (R_XSTORMY16_PC16, /* type */
138 0, /* rightshift */
139 1, /* size (0 = byte, 1 = short, 2 = long) */
140 16, /* bitsize */
141 true, /* pc_relative */
142 0, /* bitpos */
143 complain_overflow_signed, /* complain_on_overflow */
144 bfd_elf_generic_reloc, /* special_function */
145 "R_XSTORMY16_PC16", /* name */
146 false, /* partial_inplace */
147 0, /* src_mask */
148 0xffffffff, /* dst_mask */
149 true), /* pcrel_offset */
151 /* An 8 bit pc-relative relocation. */
152 HOWTO (R_XSTORMY16_PC8, /* type */
153 0, /* rightshift */
154 0, /* size (0 = byte, 1 = short, 2 = long) */
155 8, /* bitsize */
156 true, /* pc_relative */
157 0, /* bitpos */
158 complain_overflow_signed, /* complain_on_overflow */
159 bfd_elf_generic_reloc, /* special_function */
160 "R_XSTORMY16_PC8", /* name */
161 false, /* partial_inplace */
162 0, /* src_mask */
163 0xffffffff, /* dst_mask */
164 true), /* pcrel_offset */
166 /* A 12-bit pc-relative relocation suitable for the branch instructions. */
167 HOWTO (R_XSTORMY16_REL_12, /* type */
168 1, /* rightshift */
169 1, /* size (0 = byte, 1 = short, 2 = long) */
170 11, /* bitsize */
171 true, /* pc_relative */
172 1, /* bitpos */
173 complain_overflow_signed, /* complain_on_overflow */
174 bfd_elf_generic_reloc, /* special_function */
175 "R_XSTORMY16_REL_12", /* name */
176 true, /* partial_inplace */
177 0, /* src_mask */
178 0x0fff, /* dst_mask */
179 true), /* pcrel_offset */
181 /* A 24-bit absolute relocation suitable for the jump instructions. */
182 HOWTO (R_XSTORMY16_24, /* type */
183 0, /* rightshift */
184 2, /* size (0 = byte, 1 = short, 2 = long) */
185 24, /* bitsize */
186 false, /* pc_relative */
187 0, /* bitpos */
188 complain_overflow_unsigned, /* complain_on_overflow */
189 xstormy16_elf_24_reloc, /* special_function */
190 "R_XSTORMY16_24", /* name */
191 true, /* partial_inplace */
192 0, /* src_mask */
193 0xffff00ff, /* dst_mask */
194 true), /* pcrel_offset */
196 /* A 16 bit absolute relocation to a function pointer. */
197 HOWTO (R_XSTORMY16_FPTR16, /* type */
198 0, /* rightshift */
199 1, /* size (0 = byte, 1 = short, 2 = long) */
200 16, /* bitsize */
201 false, /* pc_relative */
202 0, /* bitpos */
203 complain_overflow_bitfield, /* complain_on_overflow */
204 bfd_elf_generic_reloc, /* special_function */
205 "R_XSTORMY16_FPTR16", /* name */
206 false, /* partial_inplace */
207 0, /* src_mask */
208 0xffffffff, /* dst_mask */
209 false), /* pcrel_offset */
212 static reloc_howto_type xstormy16_elf_howto_table2 [] =
214 /* GNU extension to record C++ vtable hierarchy */
215 HOWTO (R_XSTORMY16_GNU_VTINHERIT, /* type */
216 0, /* rightshift */
217 2, /* size (0 = byte, 1 = short, 2 = long) */
218 0, /* bitsize */
219 false, /* pc_relative */
220 0, /* bitpos */
221 complain_overflow_dont, /* complain_on_overflow */
222 NULL, /* special_function */
223 "R_XSTORMY16_GNU_VTINHERIT", /* name */
224 false, /* partial_inplace */
225 0, /* src_mask */
226 0, /* dst_mask */
227 false), /* pcrel_offset */
229 /* GNU extension to record C++ vtable member usage */
230 HOWTO (R_XSTORMY16_GNU_VTENTRY, /* type */
231 0, /* rightshift */
232 2, /* size (0 = byte, 1 = short, 2 = long) */
233 0, /* bitsize */
234 false, /* pc_relative */
235 0, /* bitpos */
236 complain_overflow_dont, /* complain_on_overflow */
237 _bfd_elf_rel_vtable_reloc_fn, /* special_function */
238 "R_XSTORMY16_GNU_VTENTRY", /* name */
239 false, /* partial_inplace */
240 0, /* src_mask */
241 0, /* dst_mask */
242 false), /* pcrel_offset */
246 /* Map BFD reloc types to XSTORMY16 ELF reloc types. */
248 struct xstormy16_reloc_map
250 bfd_reloc_code_real_type bfd_reloc_val;
251 unsigned int xstormy16_reloc_val;
254 static const struct xstormy16_reloc_map xstormy16_reloc_map [] =
256 { BFD_RELOC_NONE, R_XSTORMY16_NONE },
257 { BFD_RELOC_32, R_XSTORMY16_32 },
258 { BFD_RELOC_16, R_XSTORMY16_16 },
259 { BFD_RELOC_8, R_XSTORMY16_8 },
260 { BFD_RELOC_32_PCREL, R_XSTORMY16_PC32 },
261 { BFD_RELOC_16_PCREL, R_XSTORMY16_PC16 },
262 { BFD_RELOC_8_PCREL, R_XSTORMY16_PC8 },
263 { BFD_RELOC_XSTORMY16_REL_12, R_XSTORMY16_REL_12 },
264 { BFD_RELOC_XSTORMY16_24, R_XSTORMY16_24 },
265 { BFD_RELOC_XSTORMY16_FPTR16, R_XSTORMY16_FPTR16 },
266 { BFD_RELOC_VTABLE_INHERIT, R_XSTORMY16_GNU_VTINHERIT },
267 { BFD_RELOC_VTABLE_ENTRY, R_XSTORMY16_GNU_VTENTRY },
270 static reloc_howto_type *
271 xstormy16_reloc_type_lookup (abfd, code)
272 bfd * abfd ATTRIBUTE_UNUSED;
273 bfd_reloc_code_real_type code;
275 unsigned int i;
277 for (i = sizeof (xstormy16_reloc_map) / sizeof (xstormy16_reloc_map[0]);
278 --i;)
279 if (xstormy16_reloc_map [i].bfd_reloc_val == code)
280 return & xstormy16_elf_howto_table [xstormy16_reloc_map[i].xstormy16_reloc_val];
282 return NULL;
285 /* Set the howto pointer for an XSTORMY16 ELF reloc. */
287 static void
288 xstormy16_info_to_howto_rela (abfd, cache_ptr, dst)
289 bfd * abfd ATTRIBUTE_UNUSED;
290 arelent * cache_ptr;
291 Elf32_Internal_Rela * dst;
293 unsigned int r_type = ELF32_R_TYPE (dst->r_info);
295 if (r_type <= (unsigned int) R_XSTORMY16_FPTR16)
296 cache_ptr->howto = &xstormy16_elf_howto_table [r_type];
297 else if (r_type - R_XSTORMY16_GNU_VTINHERIT
298 <= (unsigned int) R_XSTORMY16_GNU_VTENTRY)
299 cache_ptr->howto
300 = &xstormy16_elf_howto_table2 [r_type - R_XSTORMY16_GNU_VTINHERIT];
301 else
302 abort ();
305 /* Handle the R_XSTORMY16_24 reloc, which has an odd bit arrangement. */
307 static bfd_reloc_status_type
308 xstormy16_elf_24_reloc (abfd, reloc_entry, symbol, data, input_section,
309 output_bfd, error_message)
310 bfd *abfd;
311 arelent *reloc_entry;
312 asymbol *symbol;
313 PTR data;
314 asection *input_section;
315 bfd *output_bfd;
316 char **error_message ATTRIBUTE_UNUSED;
318 bfd_vma relocation, x;
320 if (output_bfd != NULL)
322 reloc_entry->address += input_section->output_offset;
323 return bfd_reloc_ok;
326 if (reloc_entry->address > input_section->_cooked_size)
327 return bfd_reloc_outofrange;
329 if (bfd_is_com_section (symbol->section))
330 relocation = 0;
331 else
332 relocation = symbol->value;
334 relocation += symbol->section->output_section->vma;
335 relocation += symbol->section->output_offset;
336 relocation += reloc_entry->addend;
338 x = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
339 x &= 0x0000ff00;
340 x |= relocation & 0xff;
341 x |= (relocation << 8) & 0xffff0000;
342 bfd_put_32 (abfd, x, (bfd_byte *) data + reloc_entry->address);
344 if (relocation & ~ (bfd_vma) 0xffffff)
345 return bfd_reloc_overflow;
347 return bfd_reloc_ok;
350 /* We support 16-bit pointers to code above 64k by generating a thunk
351 below 64k containing a JMPF instruction to the final address. We
352 cannot, unfortunately, minimize the number of thunks unless the
353 -relax switch is given, as otherwise we have no idea where the
354 sections will fall in the address space. */
356 static boolean
357 xstormy16_elf_check_relocs (abfd, info, sec, relocs)
358 bfd *abfd;
359 struct bfd_link_info *info;
360 asection *sec;
361 const Elf_Internal_Rela *relocs;
363 const Elf_Internal_Rela *rel, *relend;
364 struct elf_link_hash_entry **sym_hashes;
365 Elf_Internal_Shdr *symtab_hdr;
366 bfd_vma *local_plt_offsets;
367 asection *splt;
368 bfd *dynobj;
370 if (info->relocateable)
371 return true;
373 symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
374 sym_hashes = elf_sym_hashes (abfd);
375 local_plt_offsets = elf_local_got_offsets (abfd);
376 splt = NULL;
377 dynobj = elf_hash_table(info)->dynobj;
379 relend = relocs + sec->reloc_count;
380 for (rel = relocs; rel < relend; ++rel)
382 unsigned long r_symndx;
383 struct elf_link_hash_entry *h;
384 bfd_vma *offset;
386 r_symndx = ELF32_R_SYM (rel->r_info);
387 if (r_symndx < symtab_hdr->sh_info)
388 h = NULL;
389 else
391 h = sym_hashes[r_symndx - symtab_hdr->sh_info];
392 while (h->root.type == bfd_link_hash_indirect
393 || h->root.type == bfd_link_hash_warning)
394 h = (struct elf_link_hash_entry *) h->root.u.i.link;
397 switch (ELF32_R_TYPE (rel->r_info))
399 /* This relocation describes a 16-bit pointer to a function.
400 We may need to allocate a thunk in low memory; reserve memory
401 for it now. */
402 case R_XSTORMY16_FPTR16:
403 if (rel->r_addend != 0)
405 (*info->callbacks->warning)
406 (info, _("non-zero addend in @fptr reloc"), 0,
407 abfd, 0, 0);
410 if (dynobj == NULL)
411 elf_hash_table (info)->dynobj = dynobj = abfd;
412 if (splt == NULL)
414 splt = bfd_get_section_by_name (dynobj, ".plt");
415 if (splt == NULL)
417 splt = bfd_make_section (dynobj, ".plt");
418 if (splt == NULL
419 || ! bfd_set_section_flags (dynobj, splt,
420 (SEC_ALLOC
421 | SEC_LOAD
422 | SEC_HAS_CONTENTS
423 | SEC_IN_MEMORY
424 | SEC_LINKER_CREATED
425 | SEC_READONLY
426 | SEC_CODE))
427 || ! bfd_set_section_alignment (dynobj, splt, 1))
428 return false;
432 if (h != NULL)
433 offset = &h->plt.offset;
434 else
436 if (local_plt_offsets == NULL)
438 size_t size;
439 unsigned int i;
441 size = symtab_hdr->sh_info * sizeof (bfd_vma);
442 local_plt_offsets = (bfd_vma *) bfd_alloc (abfd, size);
443 if (local_plt_offsets == NULL)
444 return false;
445 elf_local_got_offsets (abfd) = local_plt_offsets;
447 for (i = 0; i < symtab_hdr->sh_info; i++)
448 local_plt_offsets[i] = (bfd_vma) -1;
450 offset = &local_plt_offsets[r_symndx];
453 if (*offset == (bfd_vma) -1)
455 *offset = splt->_raw_size;
456 splt->_raw_size += 4;
458 break;
460 /* This relocation describes the C++ object vtable hierarchy.
461 Reconstruct it for later use during GC. */
462 case R_XSTORMY16_GNU_VTINHERIT:
463 if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
464 return false;
465 break;
467 /* This relocation describes which C++ vtable entries are actually
468 used. Record for later use during GC. */
469 case R_XSTORMY16_GNU_VTENTRY:
470 if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
471 return false;
472 break;
476 return true;
479 /* A subroutine of xstormy16_elf_relax_section. If the global symbol H
480 is within the low 64k, remove any entry for it in the plt. */
482 struct relax_plt_data
484 asection *splt;
485 boolean *again;
488 static boolean
489 xstormy16_relax_plt_check (h, xdata)
490 struct elf_link_hash_entry *h;
491 PTR xdata;
493 struct relax_plt_data *data = (struct relax_plt_data *) xdata;
495 if (h->plt.offset != (bfd_vma) -1)
497 bfd_vma address;
499 if (h->root.type == bfd_link_hash_undefined
500 || h->root.type == bfd_link_hash_undefweak)
501 address = 0;
502 else
503 address = (h->root.u.def.section->output_section->vma
504 + h->root.u.def.section->output_offset
505 + h->root.u.def.value);
507 if (address <= 0xffff)
509 h->plt.offset = -1;
510 data->splt->_cooked_size -= 4;
511 *data->again = true;
515 return true;
518 /* A subroutine of xstormy16_elf_relax_section. If the global symbol H
519 previously had a plt entry, give it a new entry offset. */
521 static boolean
522 xstormy16_relax_plt_realloc (h, xdata)
523 struct elf_link_hash_entry *h;
524 PTR xdata;
526 bfd_vma *entry = (bfd_vma *) xdata;
528 if (h->plt.offset != (bfd_vma) -1)
530 h->plt.offset = *entry;
531 *entry += 4;
534 return true;
537 static boolean
538 xstormy16_elf_relax_section (dynobj, splt, info, again)
539 bfd *dynobj;
540 asection *splt;
541 struct bfd_link_info *info;
542 boolean *again;
544 struct relax_plt_data relax_plt_data;
545 bfd *ibfd;
547 /* Assume nothing changes. */
548 *again = false;
550 if (info->relocateable)
551 return true;
553 /* We only relax the .plt section at the moment. */
554 if (dynobj != elf_hash_table (info)->dynobj
555 || strcmp (splt->name, ".plt") != 0)
556 return true;
558 /* Quick check for an empty plt. */
559 if (splt->_raw_size == 0)
560 return true;
562 /* If this is the first time we have been called for this section,
563 initialize the cooked size. */
564 if (splt->_cooked_size == 0)
565 splt->_cooked_size = splt->_raw_size;
567 /* Map across all global symbols; see which ones happen to
568 fall in the low 64k. */
569 relax_plt_data.splt = splt;
570 relax_plt_data.again = again;
571 elf_link_hash_traverse (elf_hash_table (info), xstormy16_relax_plt_check,
572 &relax_plt_data);
574 /* Likewise for local symbols, though that's somewhat less convenient
575 as we have walk the list of input bfds and swap in symbol data. */
576 for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
578 bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
579 Elf_Internal_Shdr *symtab_hdr;
580 Elf_Internal_Shdr *shndx_hdr;
581 Elf32_External_Sym *extsyms;
582 Elf_External_Sym_Shndx *shndx_buf;
583 unsigned int idx;
585 if (! local_plt_offsets)
586 continue;
588 symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
589 shndx_hdr = &elf_tdata (ibfd)->symtab_shndx_hdr;
591 if (symtab_hdr->contents != NULL)
592 extsyms = (Elf32_External_Sym *) symtab_hdr->contents;
593 else
595 bfd_size_type amt;
597 amt = symtab_hdr->sh_info;
598 amt *= sizeof (Elf32_External_Sym);
599 extsyms = (Elf32_External_Sym *) bfd_malloc (amt);
600 if (extsyms == NULL)
601 return false;
602 if (bfd_seek (ibfd, symtab_hdr->sh_offset, SEEK_SET) != 0
603 || bfd_bread ((PTR) extsyms, amt, ibfd) != amt)
605 error_ret_free_extsyms:
606 free (extsyms);
607 return false;
611 shndx_buf = NULL;
612 if (shndx_hdr->sh_size != 0)
614 bfd_size_type amt;
616 amt = symtab_hdr->sh_info;
617 amt *= sizeof (Elf_External_Sym_Shndx);
618 shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
619 if (shndx_buf == NULL)
620 goto error_ret_free_extsyms;
621 if (bfd_seek (ibfd, shndx_hdr->sh_offset, SEEK_SET) != 0
622 || bfd_bread ((PTR) shndx_buf, amt, ibfd) != amt)
624 free (shndx_buf);
625 goto error_ret_free_extsyms;
627 shndx_hdr->contents = (bfd_byte *) shndx_buf;
630 for (idx = 0; idx < symtab_hdr->sh_info; ++idx)
632 Elf_External_Sym_Shndx *shndx;
633 Elf_Internal_Sym isym;
634 asection *tsec;
635 bfd_vma address;
637 if (local_plt_offsets[idx] == (bfd_vma) -1)
638 continue;
640 shndx = shndx_buf;
641 if (shndx != NULL)
642 shndx += idx;
643 bfd_elf32_swap_symbol_in (ibfd, extsyms + idx, shndx, &isym);
644 if (isym.st_shndx == SHN_UNDEF)
645 continue;
646 else if (isym.st_shndx == SHN_ABS)
647 tsec = bfd_abs_section_ptr;
648 else if (isym.st_shndx == SHN_COMMON)
649 tsec = bfd_com_section_ptr;
650 else
651 tsec = bfd_section_from_elf_index (ibfd, isym.st_shndx);
653 address = (tsec->output_section->vma
654 + tsec->output_offset
655 + isym.st_value);
656 if (address <= 0xffff)
658 local_plt_offsets[idx] = -1;
659 splt->_cooked_size -= 4;
660 *again = true;
664 if (shndx_buf != NULL)
665 free (shndx_buf);
667 if ((Elf32_External_Sym *) symtab_hdr->contents != extsyms)
668 free (extsyms);
671 /* If we changed anything, walk the symbols again to reallocate
672 .plt entry addresses. */
673 if (*again && splt->_cooked_size > 0)
675 bfd_vma entry = 0;
677 elf_link_hash_traverse (elf_hash_table (info),
678 xstormy16_relax_plt_realloc, &entry);
680 for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
682 bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
683 unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info;
684 unsigned int idx;
686 if (! local_plt_offsets)
687 continue;
689 for (idx = 0; idx < nlocals; ++idx)
690 if (local_plt_offsets[idx] != (bfd_vma) -1)
692 local_plt_offsets[idx] = entry;
693 entry += 4;
698 splt->_raw_size = splt->_cooked_size;
699 return true;
702 static boolean
703 xstormy16_elf_always_size_sections (output_bfd, info)
704 bfd *output_bfd ATTRIBUTE_UNUSED;
705 struct bfd_link_info *info;
707 bfd *dynobj;
708 asection *splt;
710 if (info->relocateable)
711 return true;
713 dynobj = elf_hash_table (info)->dynobj;
714 if (dynobj == NULL)
715 return true;
717 splt = bfd_get_section_by_name (dynobj, ".plt");
718 BFD_ASSERT (splt != NULL);
720 splt->contents = (bfd_byte *) bfd_zalloc (dynobj, splt->_raw_size);
721 if (splt->contents == NULL)
722 return false;
724 return true;
727 /* Relocate an XSTORMY16 ELF section.
728 There is some attempt to make this function usable for many architectures,
729 both USE_REL and USE_RELA ['twould be nice if such a critter existed],
730 if only to serve as a learning tool.
732 The RELOCATE_SECTION function is called by the new ELF backend linker
733 to handle the relocations for a section.
735 The relocs are always passed as Rela structures; if the section
736 actually uses Rel structures, the r_addend field will always be
737 zero.
739 This function is responsible for adjusting the section contents as
740 necessary, and (if using Rela relocs and generating a relocateable
741 output file) adjusting the reloc addend as necessary.
743 This function does not have to worry about setting the reloc
744 address or the reloc symbol index.
746 LOCAL_SYMS is a pointer to the swapped in local symbols.
748 LOCAL_SECTIONS is an array giving the section in the input file
749 corresponding to the st_shndx field of each local symbol.
751 The global hash table entry for the global symbols can be found
752 via elf_sym_hashes (input_bfd).
754 When generating relocateable output, this function must handle
755 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
756 going to be the section symbol corresponding to the output
757 section, which means that the addend must be adjusted
758 accordingly. */
760 static boolean
761 xstormy16_elf_relocate_section (output_bfd, info, input_bfd, input_section,
762 contents, relocs, local_syms, local_sections)
763 bfd * output_bfd ATTRIBUTE_UNUSED;
764 struct bfd_link_info * info;
765 bfd * input_bfd;
766 asection * input_section;
767 bfd_byte * contents;
768 Elf_Internal_Rela * relocs;
769 Elf_Internal_Sym * local_syms;
770 asection ** local_sections;
772 Elf_Internal_Shdr * symtab_hdr;
773 struct elf_link_hash_entry ** sym_hashes;
774 Elf_Internal_Rela * rel;
775 Elf_Internal_Rela * relend;
776 bfd *dynobj;
777 asection *splt;
779 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
780 sym_hashes = elf_sym_hashes (input_bfd);
781 relend = relocs + input_section->reloc_count;
783 dynobj = elf_hash_table (info)->dynobj;
784 splt = NULL;
785 if (dynobj != NULL)
786 splt = bfd_get_section_by_name (dynobj, ".plt");
788 for (rel = relocs; rel < relend; rel ++)
790 reloc_howto_type * howto;
791 unsigned long r_symndx;
792 Elf_Internal_Sym * sym;
793 asection * sec;
794 struct elf_link_hash_entry * h;
795 bfd_vma relocation;
796 bfd_reloc_status_type r;
797 const char * name = NULL;
798 int r_type;
800 r_type = ELF32_R_TYPE (rel->r_info);
802 if ( r_type == R_XSTORMY16_GNU_VTINHERIT
803 || r_type == R_XSTORMY16_GNU_VTENTRY)
804 continue;
806 r_symndx = ELF32_R_SYM (rel->r_info);
808 if (info->relocateable)
810 /* This is a relocateable link. We don't have to change
811 anything, unless the reloc is against a section symbol,
812 in which case we have to adjust according to where the
813 section symbol winds up in the output section. */
814 if (r_symndx < symtab_hdr->sh_info)
816 sym = local_syms + r_symndx;
818 if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
820 sec = local_sections [r_symndx];
821 rel->r_addend += sec->output_offset + sym->st_value;
825 continue;
828 /* This is a final link. */
829 howto = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info);
830 h = NULL;
831 sym = NULL;
832 sec = NULL;
834 if (r_symndx < symtab_hdr->sh_info)
836 sym = local_syms + r_symndx;
837 sec = local_sections [r_symndx];
838 relocation = (sec->output_section->vma
839 + sec->output_offset
840 + sym->st_value);
842 name = bfd_elf_string_from_elf_section
843 (input_bfd, symtab_hdr->sh_link, sym->st_name);
844 name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
846 else
848 h = sym_hashes [r_symndx - symtab_hdr->sh_info];
850 while (h->root.type == bfd_link_hash_indirect
851 || h->root.type == bfd_link_hash_warning)
852 h = (struct elf_link_hash_entry *) h->root.u.i.link;
854 name = h->root.root.string;
856 if (h->root.type == bfd_link_hash_defined
857 || h->root.type == bfd_link_hash_defweak)
859 sec = h->root.u.def.section;
860 relocation = (h->root.u.def.value
861 + sec->output_section->vma
862 + sec->output_offset);
864 else if (h->root.type == bfd_link_hash_undefweak)
866 relocation = 0;
868 else
870 if (! ((*info->callbacks->undefined_symbol)
871 (info, h->root.root.string, input_bfd,
872 input_section, rel->r_offset, true)))
873 return false;
874 relocation = 0;
878 switch (ELF32_R_TYPE (rel->r_info))
880 case R_XSTORMY16_24:
882 bfd_vma reloc = relocation + rel->r_addend;
883 unsigned int x;
885 x = bfd_get_32 (input_bfd, contents + rel->r_offset);
886 x &= 0x0000ff00;
887 x |= reloc & 0xff;
888 x |= (reloc << 8) & 0xffff0000;
889 bfd_put_32 (input_bfd, x, contents + rel->r_offset);
891 if (reloc & ~0xffffff)
892 r = bfd_reloc_overflow;
893 else
894 r = bfd_reloc_ok;
895 break;
898 case R_XSTORMY16_FPTR16:
900 bfd_vma *plt_offset;
902 if (h != NULL)
903 plt_offset = &h->plt.offset;
904 else
905 plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
907 if (relocation <= 0xffff)
909 /* If the symbol is in range for a 16-bit address, we should
910 have deallocated the plt entry in relax_section. */
911 BFD_ASSERT (*plt_offset == (bfd_vma) -1);
913 else
915 /* If the symbol is out of range for a 16-bit address,
916 we must have allocated a plt entry. */
917 BFD_ASSERT (*plt_offset != (bfd_vma) -1);
919 /* If this is the first time we've processed this symbol,
920 fill in the plt entry with the correct symbol address. */
921 if ((*plt_offset & 1) == 0)
923 unsigned int x;
925 x = 0x00000200; /* jmpf */
926 x |= relocation & 0xff;
927 x |= (relocation << 8) & 0xffff0000;
928 bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
929 *plt_offset |= 1;
932 relocation = (splt->output_section->vma
933 + splt->output_offset
934 + (*plt_offset & -2));
936 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
937 contents, rel->r_offset,
938 relocation, 0);
939 break;
942 default:
943 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
944 contents, rel->r_offset,
945 relocation, rel->r_addend);
946 break;
949 if (r != bfd_reloc_ok)
951 const char * msg = (const char *) NULL;
953 switch (r)
955 case bfd_reloc_overflow:
956 r = info->callbacks->reloc_overflow
957 (info, name, howto->name, (bfd_vma) 0,
958 input_bfd, input_section, rel->r_offset);
959 break;
961 case bfd_reloc_undefined:
962 r = info->callbacks->undefined_symbol
963 (info, name, input_bfd, input_section, rel->r_offset,
964 true);
965 break;
967 case bfd_reloc_outofrange:
968 msg = _("internal error: out of range error");
969 break;
971 case bfd_reloc_notsupported:
972 msg = _("internal error: unsupported relocation error");
973 break;
975 case bfd_reloc_dangerous:
976 msg = _("internal error: dangerous relocation");
977 break;
979 default:
980 msg = _("internal error: unknown error");
981 break;
984 if (msg)
985 r = info->callbacks->warning
986 (info, msg, name, input_bfd, input_section, rel->r_offset);
988 if (! r)
989 return false;
993 return true;
996 /* This must exist if dynobj is ever set. */
998 static boolean
999 xstormy16_elf_finish_dynamic_sections (abfd, info)
1000 bfd *abfd ATTRIBUTE_UNUSED;
1001 struct bfd_link_info *info;
1003 bfd *dynobj;
1004 asection *splt;
1006 /* As an extra sanity check, verify that all plt entries have
1007 been filled in. */
1009 if ((dynobj = elf_hash_table (info)->dynobj) != NULL
1010 && (splt = bfd_get_section_by_name (dynobj, ".plt")) != NULL)
1012 bfd_byte *contents = splt->contents;
1013 unsigned int i, size = splt->_raw_size;
1014 for (i = 0; i < size; i += 4)
1016 unsigned int x = bfd_get_32 (dynobj, contents + i);
1017 BFD_ASSERT (x != 0);
1021 return true;
1024 /* Return the section that should be marked against GC for a given
1025 relocation. */
1027 static asection *
1028 xstormy16_elf_gc_mark_hook (abfd, info, rel, h, sym)
1029 bfd * abfd;
1030 struct bfd_link_info * info ATTRIBUTE_UNUSED;
1031 Elf_Internal_Rela * rel;
1032 struct elf_link_hash_entry * h;
1033 Elf_Internal_Sym * sym;
1035 if (h != NULL)
1037 switch (ELF32_R_TYPE (rel->r_info))
1039 case R_XSTORMY16_GNU_VTINHERIT:
1040 case R_XSTORMY16_GNU_VTENTRY:
1041 break;
1043 default:
1044 switch (h->root.type)
1046 case bfd_link_hash_defined:
1047 case bfd_link_hash_defweak:
1048 return h->root.u.def.section;
1050 case bfd_link_hash_common:
1051 return h->root.u.c.p->section;
1053 default:
1054 break;
1058 else
1060 return bfd_section_from_elf_index (abfd, sym->st_shndx);
1063 return NULL;
1066 /* Update the got entry reference counts for the section being removed. */
1068 static boolean
1069 xstormy16_elf_gc_sweep_hook (abfd, info, sec, relocs)
1070 bfd * abfd ATTRIBUTE_UNUSED;
1071 struct bfd_link_info * info ATTRIBUTE_UNUSED;
1072 asection * sec ATTRIBUTE_UNUSED;
1073 const Elf_Internal_Rela * relocs ATTRIBUTE_UNUSED;
1075 return true;
1078 #define ELF_ARCH bfd_arch_xstormy16
1079 #define ELF_MACHINE_CODE EM_XSTORMY16
1080 #define ELF_MAXPAGESIZE 0x100
1082 #define TARGET_LITTLE_SYM bfd_elf32_xstormy16_vec
1083 #define TARGET_LITTLE_NAME "elf32-xstormy16"
1085 #define elf_info_to_howto_rel NULL
1086 #define elf_info_to_howto xstormy16_info_to_howto_rela
1087 #define elf_backend_relocate_section xstormy16_elf_relocate_section
1088 #define elf_backend_gc_mark_hook xstormy16_elf_gc_mark_hook
1089 #define elf_backend_gc_sweep_hook xstormy16_elf_gc_sweep_hook
1090 #define elf_backend_check_relocs xstormy16_elf_check_relocs
1091 #define elf_backend_always_size_sections \
1092 xstormy16_elf_always_size_sections
1093 #define elf_backend_finish_dynamic_sections \
1094 xstormy16_elf_finish_dynamic_sections
1096 #define elf_backend_can_gc_sections 1
1098 #define bfd_elf32_bfd_reloc_type_lookup xstormy16_reloc_type_lookup
1099 #define bfd_elf32_bfd_relax_section xstormy16_elf_relax_section
1101 #include "elf32-target.h"