* as.c (main): Don't reference _bfd_chunksize.
[binutils.git] / bfd / elf32-xstormy16.c
blob484acdded4713d8322615d5dc02bee58d5ad11f0
1 /* XSTORMY16-specific support for 32-bit ELF.
2 Copyright (C) 2000, 2001, 2002 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"
25 #include "libiberty.h"
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 *, Elf32_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 boolean xstormy16_elf_check_relocs
37 PARAMS ((bfd *, struct bfd_link_info *, asection *,
38 const Elf_Internal_Rela *));
39 static boolean xstormy16_relax_plt_check
40 PARAMS ((struct elf_link_hash_entry *, PTR));
41 static boolean xstormy16_relax_plt_realloc
42 PARAMS ((struct elf_link_hash_entry *, PTR));
43 static boolean xstormy16_elf_relax_section
44 PARAMS ((bfd *abfd, asection *sec, struct bfd_link_info *link_info,
45 boolean *again));
46 static boolean xstormy16_elf_always_size_sections
47 PARAMS ((bfd *, struct bfd_link_info *));
48 static 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 boolean xstormy16_elf_finish_dynamic_sections
52 PARAMS((bfd *, struct bfd_link_info *));
53 static 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 ((bfd *, struct bfd_link_info *, Elf_Internal_Rela *,
58 struct elf_link_hash_entry *, Elf_Internal_Sym *));
60 static reloc_howto_type xstormy16_elf_howto_table [] =
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 */
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 */
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 0xffffffff, /* dst_mask */
105 false), /* pcrel_offset */
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_bitfield, /* complain_on_overflow */
115 bfd_elf_generic_reloc, /* special_function */
116 "R_XSTORMY16_8", /* name */
117 false, /* partial_inplace */
118 0, /* src_mask */
119 0xffffffff, /* dst_mask */
120 false), /* pcrel_offset */
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 */
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 */
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 */
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 true, /* partial_inplace */
178 0, /* src_mask */
179 0x0fff, /* dst_mask */
180 true), /* pcrel_offset */
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 */
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 */
213 static reloc_howto_type xstormy16_elf_howto_table2 [] =
215 /* GNU extension to record C++ vtable hierarchy */
216 HOWTO (R_XSTORMY16_GNU_VTINHERIT, /* type */
217 0, /* rightshift */
218 2, /* size (0 = byte, 1 = short, 2 = long) */
219 0, /* bitsize */
220 false, /* pc_relative */
221 0, /* bitpos */
222 complain_overflow_dont, /* complain_on_overflow */
223 NULL, /* special_function */
224 "R_XSTORMY16_GNU_VTINHERIT", /* name */
225 false, /* partial_inplace */
226 0, /* src_mask */
227 0, /* dst_mask */
228 false), /* pcrel_offset */
230 /* GNU extension to record C++ vtable member usage */
231 HOWTO (R_XSTORMY16_GNU_VTENTRY, /* type */
232 0, /* rightshift */
233 2, /* size (0 = byte, 1 = short, 2 = long) */
234 0, /* bitsize */
235 false, /* pc_relative */
236 0, /* bitpos */
237 complain_overflow_dont, /* complain_on_overflow */
238 _bfd_elf_rel_vtable_reloc_fn, /* special_function */
239 "R_XSTORMY16_GNU_VTENTRY", /* name */
240 false, /* partial_inplace */
241 0, /* src_mask */
242 0, /* dst_mask */
243 false), /* pcrel_offset */
247 /* Map BFD reloc types to XSTORMY16 ELF reloc types. */
249 typedef struct xstormy16_reloc_map
251 bfd_reloc_code_real_type bfd_reloc_val;
252 unsigned int xstormy16_reloc_val;
253 reloc_howto_type * table;
254 } reloc_map;
256 static const reloc_map xstormy16_reloc_map [] =
258 { BFD_RELOC_NONE, R_XSTORMY16_NONE, xstormy16_elf_howto_table },
259 { BFD_RELOC_32, R_XSTORMY16_32, xstormy16_elf_howto_table },
260 { BFD_RELOC_16, R_XSTORMY16_16, xstormy16_elf_howto_table },
261 { BFD_RELOC_8, R_XSTORMY16_8, xstormy16_elf_howto_table },
262 { BFD_RELOC_32_PCREL, R_XSTORMY16_PC32, xstormy16_elf_howto_table },
263 { BFD_RELOC_16_PCREL, R_XSTORMY16_PC16, xstormy16_elf_howto_table },
264 { BFD_RELOC_8_PCREL, R_XSTORMY16_PC8, xstormy16_elf_howto_table },
265 { BFD_RELOC_XSTORMY16_REL_12, R_XSTORMY16_REL_12, xstormy16_elf_howto_table },
266 { BFD_RELOC_XSTORMY16_24, R_XSTORMY16_24, xstormy16_elf_howto_table },
267 { BFD_RELOC_XSTORMY16_FPTR16, R_XSTORMY16_FPTR16, xstormy16_elf_howto_table },
268 { BFD_RELOC_VTABLE_INHERIT, R_XSTORMY16_GNU_VTINHERIT, xstormy16_elf_howto_table2 },
269 { BFD_RELOC_VTABLE_ENTRY, R_XSTORMY16_GNU_VTENTRY, xstormy16_elf_howto_table2 },
272 static reloc_howto_type *
273 xstormy16_reloc_type_lookup (abfd, code)
274 bfd * abfd ATTRIBUTE_UNUSED;
275 bfd_reloc_code_real_type code;
277 unsigned int i;
279 for (i = ARRAY_SIZE (xstormy16_reloc_map); --i;)
281 const reloc_map * entry;
283 entry = xstormy16_reloc_map + i;
285 if (entry->bfd_reloc_val == code)
286 return entry->table + (entry->xstormy16_reloc_val
287 - entry->table[0].type);
290 return NULL;
293 /* Set the howto pointer for an XSTORMY16 ELF reloc. */
295 static void
296 xstormy16_info_to_howto_rela (abfd, cache_ptr, dst)
297 bfd * abfd ATTRIBUTE_UNUSED;
298 arelent * cache_ptr;
299 Elf32_Internal_Rela * dst;
301 unsigned int r_type = ELF32_R_TYPE (dst->r_info);
303 if (r_type <= (unsigned int) R_XSTORMY16_FPTR16)
304 cache_ptr->howto = &xstormy16_elf_howto_table [r_type];
305 else if (r_type - R_XSTORMY16_GNU_VTINHERIT
306 <= (unsigned int) R_XSTORMY16_GNU_VTENTRY)
307 cache_ptr->howto
308 = &xstormy16_elf_howto_table2 [r_type - R_XSTORMY16_GNU_VTINHERIT];
309 else
310 abort ();
313 /* Handle the R_XSTORMY16_24 reloc, which has an odd bit arrangement. */
315 static bfd_reloc_status_type
316 xstormy16_elf_24_reloc (abfd, reloc_entry, symbol, data, input_section,
317 output_bfd, error_message)
318 bfd *abfd;
319 arelent *reloc_entry;
320 asymbol *symbol;
321 PTR data;
322 asection *input_section;
323 bfd *output_bfd;
324 char **error_message ATTRIBUTE_UNUSED;
326 bfd_vma relocation, x;
328 if (output_bfd != NULL)
330 reloc_entry->address += input_section->output_offset;
331 return bfd_reloc_ok;
334 if (reloc_entry->address > input_section->_cooked_size)
335 return bfd_reloc_outofrange;
337 if (bfd_is_com_section (symbol->section))
338 relocation = 0;
339 else
340 relocation = symbol->value;
342 relocation += symbol->section->output_section->vma;
343 relocation += symbol->section->output_offset;
344 relocation += reloc_entry->addend;
346 x = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
347 x &= 0x0000ff00;
348 x |= relocation & 0xff;
349 x |= (relocation << 8) & 0xffff0000;
350 bfd_put_32 (abfd, x, (bfd_byte *) data + reloc_entry->address);
352 if (relocation & ~ (bfd_vma) 0xffffff)
353 return bfd_reloc_overflow;
355 return bfd_reloc_ok;
358 /* We support 16-bit pointers to code above 64k by generating a thunk
359 below 64k containing a JMPF instruction to the final address. We
360 cannot, unfortunately, minimize the number of thunks unless the
361 -relax switch is given, as otherwise we have no idea where the
362 sections will fall in the address space. */
364 static boolean
365 xstormy16_elf_check_relocs (abfd, info, sec, relocs)
366 bfd *abfd;
367 struct bfd_link_info *info;
368 asection *sec;
369 const Elf_Internal_Rela *relocs;
371 const Elf_Internal_Rela *rel, *relend;
372 struct elf_link_hash_entry **sym_hashes;
373 Elf_Internal_Shdr *symtab_hdr;
374 bfd_vma *local_plt_offsets;
375 asection *splt;
376 bfd *dynobj;
378 if (info->relocateable)
379 return true;
381 symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
382 sym_hashes = elf_sym_hashes (abfd);
383 local_plt_offsets = elf_local_got_offsets (abfd);
384 splt = NULL;
385 dynobj = elf_hash_table(info)->dynobj;
387 relend = relocs + sec->reloc_count;
388 for (rel = relocs; rel < relend; ++rel)
390 unsigned long r_symndx;
391 struct elf_link_hash_entry *h;
392 bfd_vma *offset;
394 r_symndx = ELF32_R_SYM (rel->r_info);
395 if (r_symndx < symtab_hdr->sh_info)
396 h = NULL;
397 else
399 h = sym_hashes[r_symndx - symtab_hdr->sh_info];
400 while (h->root.type == bfd_link_hash_indirect
401 || h->root.type == bfd_link_hash_warning)
402 h = (struct elf_link_hash_entry *) h->root.u.i.link;
405 switch (ELF32_R_TYPE (rel->r_info))
407 /* This relocation describes a 16-bit pointer to a function.
408 We may need to allocate a thunk in low memory; reserve memory
409 for it now. */
410 case R_XSTORMY16_FPTR16:
411 if (rel->r_addend != 0)
413 (*info->callbacks->warning)
414 (info, _("non-zero addend in @fptr reloc"), 0,
415 abfd, 0, 0);
418 if (dynobj == NULL)
419 elf_hash_table (info)->dynobj = dynobj = abfd;
420 if (splt == NULL)
422 splt = bfd_get_section_by_name (dynobj, ".plt");
423 if (splt == NULL)
425 splt = bfd_make_section (dynobj, ".plt");
426 if (splt == NULL
427 || ! bfd_set_section_flags (dynobj, splt,
428 (SEC_ALLOC
429 | SEC_LOAD
430 | SEC_HAS_CONTENTS
431 | SEC_IN_MEMORY
432 | SEC_LINKER_CREATED
433 | SEC_READONLY
434 | SEC_CODE))
435 || ! bfd_set_section_alignment (dynobj, splt, 1))
436 return false;
440 if (h != NULL)
441 offset = &h->plt.offset;
442 else
444 if (local_plt_offsets == NULL)
446 size_t size;
447 unsigned int i;
449 size = symtab_hdr->sh_info * sizeof (bfd_vma);
450 local_plt_offsets = (bfd_vma *) bfd_alloc (abfd, size);
451 if (local_plt_offsets == NULL)
452 return false;
453 elf_local_got_offsets (abfd) = local_plt_offsets;
455 for (i = 0; i < symtab_hdr->sh_info; i++)
456 local_plt_offsets[i] = (bfd_vma) -1;
458 offset = &local_plt_offsets[r_symndx];
461 if (*offset == (bfd_vma) -1)
463 *offset = splt->_raw_size;
464 splt->_raw_size += 4;
466 break;
468 /* This relocation describes the C++ object vtable hierarchy.
469 Reconstruct it for later use during GC. */
470 case R_XSTORMY16_GNU_VTINHERIT:
471 if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
472 return false;
473 break;
475 /* This relocation describes which C++ vtable entries are actually
476 used. Record for later use during GC. */
477 case R_XSTORMY16_GNU_VTENTRY:
478 if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
479 return false;
480 break;
484 return true;
487 /* A subroutine of xstormy16_elf_relax_section. If the global symbol H
488 is within the low 64k, remove any entry for it in the plt. */
490 struct relax_plt_data
492 asection *splt;
493 boolean *again;
496 static boolean
497 xstormy16_relax_plt_check (h, xdata)
498 struct elf_link_hash_entry *h;
499 PTR xdata;
501 struct relax_plt_data *data = (struct relax_plt_data *) xdata;
503 if (h->root.type == bfd_link_hash_warning)
504 h = (struct elf_link_hash_entry *) h->root.u.i.link;
506 if (h->plt.offset != (bfd_vma) -1)
508 bfd_vma address;
510 if (h->root.type == bfd_link_hash_undefined
511 || h->root.type == bfd_link_hash_undefweak)
512 address = 0;
513 else
514 address = (h->root.u.def.section->output_section->vma
515 + h->root.u.def.section->output_offset
516 + h->root.u.def.value);
518 if (address <= 0xffff)
520 h->plt.offset = -1;
521 data->splt->_cooked_size -= 4;
522 *data->again = true;
526 return true;
529 /* A subroutine of xstormy16_elf_relax_section. If the global symbol H
530 previously had a plt entry, give it a new entry offset. */
532 static boolean
533 xstormy16_relax_plt_realloc (h, xdata)
534 struct elf_link_hash_entry *h;
535 PTR xdata;
537 bfd_vma *entry = (bfd_vma *) xdata;
539 if (h->root.type == bfd_link_hash_warning)
540 h = (struct elf_link_hash_entry *) h->root.u.i.link;
542 if (h->plt.offset != (bfd_vma) -1)
544 h->plt.offset = *entry;
545 *entry += 4;
548 return true;
551 static boolean
552 xstormy16_elf_relax_section (dynobj, splt, info, again)
553 bfd *dynobj;
554 asection *splt;
555 struct bfd_link_info *info;
556 boolean *again;
558 struct relax_plt_data relax_plt_data;
559 bfd *ibfd;
561 /* Assume nothing changes. */
562 *again = false;
564 if (info->relocateable)
565 return true;
567 /* We only relax the .plt section at the moment. */
568 if (dynobj != elf_hash_table (info)->dynobj
569 || strcmp (splt->name, ".plt") != 0)
570 return true;
572 /* Quick check for an empty plt. */
573 if (splt->_raw_size == 0)
574 return true;
576 /* If this is the first time we have been called for this section,
577 initialize the cooked size. */
578 if (splt->_cooked_size == 0)
579 splt->_cooked_size = splt->_raw_size;
581 /* Map across all global symbols; see which ones happen to
582 fall in the low 64k. */
583 relax_plt_data.splt = splt;
584 relax_plt_data.again = again;
585 elf_link_hash_traverse (elf_hash_table (info), xstormy16_relax_plt_check,
586 &relax_plt_data);
588 /* Likewise for local symbols, though that's somewhat less convenient
589 as we have walk the list of input bfds and swap in symbol data. */
590 for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
592 bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
593 Elf_Internal_Shdr *symtab_hdr;
594 Elf_Internal_Shdr *shndx_hdr;
595 Elf32_External_Sym *extsyms;
596 Elf_External_Sym_Shndx *shndx_buf;
597 unsigned int idx;
599 if (! local_plt_offsets)
600 continue;
602 symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
603 shndx_hdr = &elf_tdata (ibfd)->symtab_shndx_hdr;
605 if (symtab_hdr->contents != NULL)
606 extsyms = (Elf32_External_Sym *) symtab_hdr->contents;
607 else
609 bfd_size_type amt;
611 amt = symtab_hdr->sh_info;
612 amt *= sizeof (Elf32_External_Sym);
613 extsyms = (Elf32_External_Sym *) bfd_malloc (amt);
614 if (extsyms == NULL)
615 return false;
616 if (bfd_seek (ibfd, symtab_hdr->sh_offset, SEEK_SET) != 0
617 || bfd_bread ((PTR) extsyms, amt, ibfd) != amt)
619 error_ret_free_extsyms:
620 free (extsyms);
621 return false;
625 shndx_buf = NULL;
626 if (shndx_hdr->sh_size != 0)
628 bfd_size_type amt;
630 amt = symtab_hdr->sh_info;
631 amt *= sizeof (Elf_External_Sym_Shndx);
632 shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
633 if (shndx_buf == NULL)
634 goto error_ret_free_extsyms;
635 if (bfd_seek (ibfd, shndx_hdr->sh_offset, SEEK_SET) != 0
636 || bfd_bread ((PTR) shndx_buf, amt, ibfd) != amt)
638 free (shndx_buf);
639 goto error_ret_free_extsyms;
641 shndx_hdr->contents = (bfd_byte *) shndx_buf;
644 for (idx = 0; idx < symtab_hdr->sh_info; ++idx)
646 Elf_External_Sym_Shndx *shndx;
647 Elf_Internal_Sym isym;
648 asection *tsec;
649 bfd_vma address;
651 if (local_plt_offsets[idx] == (bfd_vma) -1)
652 continue;
654 shndx = shndx_buf;
655 if (shndx != NULL)
656 shndx += idx;
657 bfd_elf32_swap_symbol_in (ibfd, extsyms + idx, shndx, &isym);
658 if (isym.st_shndx == SHN_UNDEF)
659 continue;
660 else if (isym.st_shndx == SHN_ABS)
661 tsec = bfd_abs_section_ptr;
662 else if (isym.st_shndx == SHN_COMMON)
663 tsec = bfd_com_section_ptr;
664 else
665 tsec = bfd_section_from_elf_index (ibfd, isym.st_shndx);
667 address = (tsec->output_section->vma
668 + tsec->output_offset
669 + isym.st_value);
670 if (address <= 0xffff)
672 local_plt_offsets[idx] = -1;
673 splt->_cooked_size -= 4;
674 *again = true;
678 if (shndx_buf != NULL)
679 free (shndx_buf);
681 if ((Elf32_External_Sym *) symtab_hdr->contents != extsyms)
682 free (extsyms);
685 /* If we changed anything, walk the symbols again to reallocate
686 .plt entry addresses. */
687 if (*again && splt->_cooked_size > 0)
689 bfd_vma entry = 0;
691 elf_link_hash_traverse (elf_hash_table (info),
692 xstormy16_relax_plt_realloc, &entry);
694 for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
696 bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
697 unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info;
698 unsigned int idx;
700 if (! local_plt_offsets)
701 continue;
703 for (idx = 0; idx < nlocals; ++idx)
704 if (local_plt_offsets[idx] != (bfd_vma) -1)
706 local_plt_offsets[idx] = entry;
707 entry += 4;
712 splt->_raw_size = splt->_cooked_size;
713 return true;
716 static boolean
717 xstormy16_elf_always_size_sections (output_bfd, info)
718 bfd *output_bfd ATTRIBUTE_UNUSED;
719 struct bfd_link_info *info;
721 bfd *dynobj;
722 asection *splt;
724 if (info->relocateable)
725 return true;
727 dynobj = elf_hash_table (info)->dynobj;
728 if (dynobj == NULL)
729 return true;
731 splt = bfd_get_section_by_name (dynobj, ".plt");
732 BFD_ASSERT (splt != NULL);
734 splt->contents = (bfd_byte *) bfd_zalloc (dynobj, splt->_raw_size);
735 if (splt->contents == NULL)
736 return false;
738 return true;
741 /* Relocate an XSTORMY16 ELF section.
742 There is some attempt to make this function usable for many architectures,
743 both USE_REL and USE_RELA ['twould be nice if such a critter existed],
744 if only to serve as a learning tool.
746 The RELOCATE_SECTION function is called by the new ELF backend linker
747 to handle the relocations for a section.
749 The relocs are always passed as Rela structures; if the section
750 actually uses Rel structures, the r_addend field will always be
751 zero.
753 This function is responsible for adjusting the section contents as
754 necessary, and (if using Rela relocs and generating a relocateable
755 output file) adjusting the reloc addend as necessary.
757 This function does not have to worry about setting the reloc
758 address or the reloc symbol index.
760 LOCAL_SYMS is a pointer to the swapped in local symbols.
762 LOCAL_SECTIONS is an array giving the section in the input file
763 corresponding to the st_shndx field of each local symbol.
765 The global hash table entry for the global symbols can be found
766 via elf_sym_hashes (input_bfd).
768 When generating relocateable output, this function must handle
769 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
770 going to be the section symbol corresponding to the output
771 section, which means that the addend must be adjusted
772 accordingly. */
774 static boolean
775 xstormy16_elf_relocate_section (output_bfd, info, input_bfd, input_section,
776 contents, relocs, local_syms, local_sections)
777 bfd * output_bfd ATTRIBUTE_UNUSED;
778 struct bfd_link_info * info;
779 bfd * input_bfd;
780 asection * input_section;
781 bfd_byte * contents;
782 Elf_Internal_Rela * relocs;
783 Elf_Internal_Sym * local_syms;
784 asection ** local_sections;
786 Elf_Internal_Shdr * symtab_hdr;
787 struct elf_link_hash_entry ** sym_hashes;
788 Elf_Internal_Rela * rel;
789 Elf_Internal_Rela * relend;
790 bfd *dynobj;
791 asection *splt;
793 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
794 sym_hashes = elf_sym_hashes (input_bfd);
795 relend = relocs + input_section->reloc_count;
797 dynobj = elf_hash_table (info)->dynobj;
798 splt = NULL;
799 if (dynobj != NULL)
800 splt = bfd_get_section_by_name (dynobj, ".plt");
802 for (rel = relocs; rel < relend; rel ++)
804 reloc_howto_type * howto;
805 unsigned long r_symndx;
806 Elf_Internal_Sym * sym;
807 asection * sec;
808 struct elf_link_hash_entry * h;
809 bfd_vma relocation;
810 bfd_reloc_status_type r;
811 const char * name = NULL;
812 int r_type;
814 r_type = ELF32_R_TYPE (rel->r_info);
816 if ( r_type == R_XSTORMY16_GNU_VTINHERIT
817 || r_type == R_XSTORMY16_GNU_VTENTRY)
818 continue;
820 r_symndx = ELF32_R_SYM (rel->r_info);
822 if (info->relocateable)
824 /* This is a relocateable link. We don't have to change
825 anything, unless the reloc is against a section symbol,
826 in which case we have to adjust according to where the
827 section symbol winds up in the output section. */
828 if (r_symndx < symtab_hdr->sh_info)
830 sym = local_syms + r_symndx;
832 if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
834 sec = local_sections [r_symndx];
835 rel->r_addend += sec->output_offset + sym->st_value;
839 continue;
842 /* This is a final link. */
843 howto = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info);
844 h = NULL;
845 sym = NULL;
846 sec = NULL;
848 if (r_symndx < symtab_hdr->sh_info)
850 sym = local_syms + r_symndx;
851 sec = local_sections [r_symndx];
852 relocation = (sec->output_section->vma
853 + sec->output_offset
854 + sym->st_value);
856 name = bfd_elf_string_from_elf_section
857 (input_bfd, symtab_hdr->sh_link, sym->st_name);
858 name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
860 else
862 h = sym_hashes [r_symndx - symtab_hdr->sh_info];
864 while (h->root.type == bfd_link_hash_indirect
865 || h->root.type == bfd_link_hash_warning)
866 h = (struct elf_link_hash_entry *) h->root.u.i.link;
868 name = h->root.root.string;
870 if (h->root.type == bfd_link_hash_defined
871 || h->root.type == bfd_link_hash_defweak)
873 sec = h->root.u.def.section;
874 relocation = (h->root.u.def.value
875 + sec->output_section->vma
876 + sec->output_offset);
878 else if (h->root.type == bfd_link_hash_undefweak)
880 relocation = 0;
882 else
884 if (! ((*info->callbacks->undefined_symbol)
885 (info, h->root.root.string, input_bfd,
886 input_section, rel->r_offset, true)))
887 return false;
888 relocation = 0;
892 switch (ELF32_R_TYPE (rel->r_info))
894 case R_XSTORMY16_24:
896 bfd_vma reloc = relocation + rel->r_addend;
897 unsigned int x;
899 x = bfd_get_32 (input_bfd, contents + rel->r_offset);
900 x &= 0x0000ff00;
901 x |= reloc & 0xff;
902 x |= (reloc << 8) & 0xffff0000;
903 bfd_put_32 (input_bfd, x, contents + rel->r_offset);
905 if (reloc & ~0xffffff)
906 r = bfd_reloc_overflow;
907 else
908 r = bfd_reloc_ok;
909 break;
912 case R_XSTORMY16_FPTR16:
914 bfd_vma *plt_offset;
916 if (h != NULL)
917 plt_offset = &h->plt.offset;
918 else
919 plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
921 if (relocation <= 0xffff)
923 /* If the symbol is in range for a 16-bit address, we should
924 have deallocated the plt entry in relax_section. */
925 BFD_ASSERT (*plt_offset == (bfd_vma) -1);
927 else
929 /* If the symbol is out of range for a 16-bit address,
930 we must have allocated a plt entry. */
931 BFD_ASSERT (*plt_offset != (bfd_vma) -1);
933 /* If this is the first time we've processed this symbol,
934 fill in the plt entry with the correct symbol address. */
935 if ((*plt_offset & 1) == 0)
937 unsigned int x;
939 x = 0x00000200; /* jmpf */
940 x |= relocation & 0xff;
941 x |= (relocation << 8) & 0xffff0000;
942 bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
943 *plt_offset |= 1;
946 relocation = (splt->output_section->vma
947 + splt->output_offset
948 + (*plt_offset & -2));
950 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
951 contents, rel->r_offset,
952 relocation, 0);
953 break;
956 default:
957 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
958 contents, rel->r_offset,
959 relocation, rel->r_addend);
960 break;
963 if (r != bfd_reloc_ok)
965 const char * msg = (const char *) NULL;
967 switch (r)
969 case bfd_reloc_overflow:
970 r = info->callbacks->reloc_overflow
971 (info, name, howto->name, (bfd_vma) 0,
972 input_bfd, input_section, rel->r_offset);
973 break;
975 case bfd_reloc_undefined:
976 r = info->callbacks->undefined_symbol
977 (info, name, input_bfd, input_section, rel->r_offset,
978 true);
979 break;
981 case bfd_reloc_outofrange:
982 msg = _("internal error: out of range error");
983 break;
985 case bfd_reloc_notsupported:
986 msg = _("internal error: unsupported relocation error");
987 break;
989 case bfd_reloc_dangerous:
990 msg = _("internal error: dangerous relocation");
991 break;
993 default:
994 msg = _("internal error: unknown error");
995 break;
998 if (msg)
999 r = info->callbacks->warning
1000 (info, msg, name, input_bfd, input_section, rel->r_offset);
1002 if (! r)
1003 return false;
1007 return true;
1010 /* This must exist if dynobj is ever set. */
1012 static boolean
1013 xstormy16_elf_finish_dynamic_sections (abfd, info)
1014 bfd *abfd ATTRIBUTE_UNUSED;
1015 struct bfd_link_info *info;
1017 bfd *dynobj;
1018 asection *splt;
1020 /* As an extra sanity check, verify that all plt entries have
1021 been filled in. */
1023 if ((dynobj = elf_hash_table (info)->dynobj) != NULL
1024 && (splt = bfd_get_section_by_name (dynobj, ".plt")) != NULL)
1026 bfd_byte *contents = splt->contents;
1027 unsigned int i, size = splt->_raw_size;
1028 for (i = 0; i < size; i += 4)
1030 unsigned int x = bfd_get_32 (dynobj, contents + i);
1031 BFD_ASSERT (x != 0);
1035 return true;
1038 /* Return the section that should be marked against GC for a given
1039 relocation. */
1041 static asection *
1042 xstormy16_elf_gc_mark_hook (abfd, info, rel, h, sym)
1043 bfd * abfd;
1044 struct bfd_link_info * info ATTRIBUTE_UNUSED;
1045 Elf_Internal_Rela * rel;
1046 struct elf_link_hash_entry * h;
1047 Elf_Internal_Sym * sym;
1049 if (h != NULL)
1051 switch (ELF32_R_TYPE (rel->r_info))
1053 case R_XSTORMY16_GNU_VTINHERIT:
1054 case R_XSTORMY16_GNU_VTENTRY:
1055 break;
1057 default:
1058 switch (h->root.type)
1060 case bfd_link_hash_defined:
1061 case bfd_link_hash_defweak:
1062 return h->root.u.def.section;
1064 case bfd_link_hash_common:
1065 return h->root.u.c.p->section;
1067 default:
1068 break;
1072 else
1074 return bfd_section_from_elf_index (abfd, sym->st_shndx);
1077 return NULL;
1080 /* Update the got entry reference counts for the section being removed. */
1082 static boolean
1083 xstormy16_elf_gc_sweep_hook (abfd, info, sec, relocs)
1084 bfd * abfd ATTRIBUTE_UNUSED;
1085 struct bfd_link_info * info ATTRIBUTE_UNUSED;
1086 asection * sec ATTRIBUTE_UNUSED;
1087 const Elf_Internal_Rela * relocs ATTRIBUTE_UNUSED;
1089 return true;
1092 #define ELF_ARCH bfd_arch_xstormy16
1093 #define ELF_MACHINE_CODE EM_XSTORMY16
1094 #define ELF_MAXPAGESIZE 0x100
1096 #define TARGET_LITTLE_SYM bfd_elf32_xstormy16_vec
1097 #define TARGET_LITTLE_NAME "elf32-xstormy16"
1099 #define elf_info_to_howto_rel NULL
1100 #define elf_info_to_howto xstormy16_info_to_howto_rela
1101 #define elf_backend_relocate_section xstormy16_elf_relocate_section
1102 #define elf_backend_gc_mark_hook xstormy16_elf_gc_mark_hook
1103 #define elf_backend_gc_sweep_hook xstormy16_elf_gc_sweep_hook
1104 #define elf_backend_check_relocs xstormy16_elf_check_relocs
1105 #define elf_backend_always_size_sections \
1106 xstormy16_elf_always_size_sections
1107 #define elf_backend_finish_dynamic_sections \
1108 xstormy16_elf_finish_dynamic_sections
1110 #define elf_backend_can_gc_sections 1
1112 #define bfd_elf32_bfd_reloc_type_lookup xstormy16_reloc_type_lookup
1113 #define bfd_elf32_bfd_relax_section xstormy16_elf_relax_section
1115 #include "elf32-target.h"