* ld-arm/arm-elf.exp: Add arm-static-app test.
[binutils.git] / bfd / elf32-xstormy16.c
blob1377ff2517b45ca07658698ab4fb9232302f4c84
1 /* XSTORMY16-specific support for 32-bit ELF.
2 Copyright 2000, 2001, 2002, 2003 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 *, 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 *));
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 0xffff, /* 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_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 */
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 FALSE, /* partial_inplace */
178 0, /* src_mask */
179 0x0ffe, /* 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 */
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 */
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 */
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 */
258 static reloc_howto_type xstormy16_elf_howto_table2 [] =
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 */
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 */
292 /* Map BFD reloc types to XSTORMY16 ELF reloc types. */
294 typedef struct xstormy16_reloc_map
296 bfd_reloc_code_real_type bfd_reloc_val;
297 unsigned int xstormy16_reloc_val;
298 reloc_howto_type * table;
299 } reloc_map;
301 static const reloc_map xstormy16_reloc_map [] =
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 },
320 static reloc_howto_type *
321 xstormy16_reloc_type_lookup (abfd, code)
322 bfd * abfd ATTRIBUTE_UNUSED;
323 bfd_reloc_code_real_type code;
325 unsigned int i;
327 for (i = ARRAY_SIZE (xstormy16_reloc_map); --i;)
329 const reloc_map * entry;
331 entry = xstormy16_reloc_map + i;
333 if (entry->bfd_reloc_val == code)
334 return entry->table + (entry->xstormy16_reloc_val
335 - entry->table[0].type);
338 return NULL;
341 /* Set the howto pointer for an XSTORMY16 ELF reloc. */
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;
349 unsigned int r_type = ELF32_R_TYPE (dst->r_info);
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 ();
361 /* Handle the R_XSTORMY16_24 reloc, which has an odd bit arrangement. */
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;
374 bfd_vma relocation, x;
376 if (output_bfd != NULL)
378 reloc_entry->address += input_section->output_offset;
379 return bfd_reloc_ok;
382 if (reloc_entry->address > input_section->_cooked_size)
383 return bfd_reloc_outofrange;
385 if (bfd_is_com_section (symbol->section))
386 relocation = 0;
387 else
388 relocation = symbol->value;
390 relocation += symbol->section->output_section->vma;
391 relocation += symbol->section->output_offset;
392 relocation += reloc_entry->addend;
394 x = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
395 x &= 0x0000ff00;
396 x |= relocation & 0xff;
397 x |= (relocation << 8) & 0xffff0000;
398 bfd_put_32 (abfd, x, (bfd_byte *) data + reloc_entry->address);
400 if (relocation & ~ (bfd_vma) 0xffffff)
401 return bfd_reloc_overflow;
403 return bfd_reloc_ok;
406 /* We support 16-bit pointers to code above 64k by generating a thunk
407 below 64k containing a JMPF instruction to the final address. We
408 cannot, unfortunately, minimize the number of thunks unless the
409 -relax switch is given, as otherwise we have no idea where the
410 sections will fall in the address space. */
412 static bfd_boolean
413 xstormy16_elf_check_relocs (abfd, info, sec, relocs)
414 bfd *abfd;
415 struct bfd_link_info *info;
416 asection *sec;
417 const Elf_Internal_Rela *relocs;
419 const Elf_Internal_Rela *rel, *relend;
420 struct elf_link_hash_entry **sym_hashes;
421 Elf_Internal_Shdr *symtab_hdr;
422 bfd_vma *local_plt_offsets;
423 asection *splt;
424 bfd *dynobj;
426 if (info->relocatable)
427 return TRUE;
429 symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
430 sym_hashes = elf_sym_hashes (abfd);
431 local_plt_offsets = elf_local_got_offsets (abfd);
432 splt = NULL;
433 dynobj = elf_hash_table(info)->dynobj;
435 relend = relocs + sec->reloc_count;
436 for (rel = relocs; rel < relend; ++rel)
438 unsigned long r_symndx;
439 struct elf_link_hash_entry *h;
440 bfd_vma *offset;
442 r_symndx = ELF32_R_SYM (rel->r_info);
443 if (r_symndx < symtab_hdr->sh_info)
444 h = NULL;
445 else
447 h = sym_hashes[r_symndx - symtab_hdr->sh_info];
448 while (h->root.type == bfd_link_hash_indirect
449 || h->root.type == bfd_link_hash_warning)
450 h = (struct elf_link_hash_entry *) h->root.u.i.link;
453 switch (ELF32_R_TYPE (rel->r_info))
455 /* This relocation describes a 16-bit pointer to a function.
456 We may need to allocate a thunk in low memory; reserve memory
457 for it now. */
458 case R_XSTORMY16_FPTR16:
459 if (rel->r_addend != 0)
461 (*info->callbacks->warning)
462 (info, _("non-zero addend in @fptr reloc"), 0,
463 abfd, 0, 0);
466 if (dynobj == NULL)
467 elf_hash_table (info)->dynobj = dynobj = abfd;
468 if (splt == NULL)
470 splt = bfd_get_section_by_name (dynobj, ".plt");
471 if (splt == NULL)
473 splt = bfd_make_section (dynobj, ".plt");
474 if (splt == NULL
475 || ! bfd_set_section_flags (dynobj, splt,
476 (SEC_ALLOC
477 | SEC_LOAD
478 | SEC_HAS_CONTENTS
479 | SEC_IN_MEMORY
480 | SEC_LINKER_CREATED
481 | SEC_READONLY
482 | SEC_CODE))
483 || ! bfd_set_section_alignment (dynobj, splt, 1))
484 return FALSE;
488 if (h != NULL)
489 offset = &h->plt.offset;
490 else
492 if (local_plt_offsets == NULL)
494 size_t size;
495 unsigned int i;
497 size = symtab_hdr->sh_info * sizeof (bfd_vma);
498 local_plt_offsets = (bfd_vma *) bfd_alloc (abfd, size);
499 if (local_plt_offsets == NULL)
500 return FALSE;
501 elf_local_got_offsets (abfd) = local_plt_offsets;
503 for (i = 0; i < symtab_hdr->sh_info; i++)
504 local_plt_offsets[i] = (bfd_vma) -1;
506 offset = &local_plt_offsets[r_symndx];
509 if (*offset == (bfd_vma) -1)
511 *offset = splt->_raw_size;
512 splt->_raw_size += 4;
514 break;
516 /* This relocation describes the C++ object vtable hierarchy.
517 Reconstruct it for later use during GC. */
518 case R_XSTORMY16_GNU_VTINHERIT:
519 if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
520 return FALSE;
521 break;
523 /* This relocation describes which C++ vtable entries are actually
524 used. Record for later use during GC. */
525 case R_XSTORMY16_GNU_VTENTRY:
526 if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
527 return FALSE;
528 break;
532 return TRUE;
535 /* A subroutine of xstormy16_elf_relax_section. If the global symbol H
536 is within the low 64k, remove any entry for it in the plt. */
538 struct relax_plt_data
540 asection *splt;
541 bfd_boolean *again;
544 static bfd_boolean
545 xstormy16_relax_plt_check (h, xdata)
546 struct elf_link_hash_entry *h;
547 PTR xdata;
549 struct relax_plt_data *data = (struct relax_plt_data *) xdata;
551 if (h->root.type == bfd_link_hash_warning)
552 h = (struct elf_link_hash_entry *) h->root.u.i.link;
554 if (h->plt.offset != (bfd_vma) -1)
556 bfd_vma address;
558 if (h->root.type == bfd_link_hash_undefined
559 || h->root.type == bfd_link_hash_undefweak)
560 address = 0;
561 else
562 address = (h->root.u.def.section->output_section->vma
563 + h->root.u.def.section->output_offset
564 + h->root.u.def.value);
566 if (address <= 0xffff)
568 h->plt.offset = -1;
569 data->splt->_cooked_size -= 4;
570 *data->again = TRUE;
574 return TRUE;
577 /* A subroutine of xstormy16_elf_relax_section. If the global symbol H
578 previously had a plt entry, give it a new entry offset. */
580 static bfd_boolean
581 xstormy16_relax_plt_realloc (h, xdata)
582 struct elf_link_hash_entry *h;
583 PTR xdata;
585 bfd_vma *entry = (bfd_vma *) xdata;
587 if (h->root.type == bfd_link_hash_warning)
588 h = (struct elf_link_hash_entry *) h->root.u.i.link;
590 if (h->plt.offset != (bfd_vma) -1)
592 h->plt.offset = *entry;
593 *entry += 4;
596 return TRUE;
599 static bfd_boolean
600 xstormy16_elf_relax_section (dynobj, splt, info, again)
601 bfd *dynobj;
602 asection *splt;
603 struct bfd_link_info *info;
604 bfd_boolean *again;
606 struct relax_plt_data relax_plt_data;
607 bfd *ibfd;
609 /* Assume nothing changes. */
610 *again = FALSE;
612 if (info->relocatable)
613 return TRUE;
615 /* We only relax the .plt section at the moment. */
616 if (dynobj != elf_hash_table (info)->dynobj
617 || strcmp (splt->name, ".plt") != 0)
618 return TRUE;
620 /* Quick check for an empty plt. */
621 if (splt->_raw_size == 0)
622 return TRUE;
624 /* If this is the first time we have been called for this section,
625 initialize the cooked size. */
626 if (splt->_cooked_size == 0)
627 splt->_cooked_size = splt->_raw_size;
629 /* Map across all global symbols; see which ones happen to
630 fall in the low 64k. */
631 relax_plt_data.splt = splt;
632 relax_plt_data.again = again;
633 elf_link_hash_traverse (elf_hash_table (info), xstormy16_relax_plt_check,
634 &relax_plt_data);
636 /* Likewise for local symbols, though that's somewhat less convenient
637 as we have to walk the list of input bfds and swap in symbol data. */
638 for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
640 bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
641 Elf_Internal_Shdr *symtab_hdr;
642 Elf_Internal_Sym *isymbuf = NULL;
643 unsigned int idx;
645 if (! local_plt_offsets)
646 continue;
648 symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
649 if (symtab_hdr->sh_info != 0)
651 isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
652 if (isymbuf == NULL)
653 isymbuf = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
654 symtab_hdr->sh_info, 0,
655 NULL, NULL, NULL);
656 if (isymbuf == NULL)
657 return FALSE;
660 for (idx = 0; idx < symtab_hdr->sh_info; ++idx)
662 Elf_Internal_Sym *isym;
663 asection *tsec;
664 bfd_vma address;
666 if (local_plt_offsets[idx] == (bfd_vma) -1)
667 continue;
669 isym = &isymbuf[idx];
670 if (isym->st_shndx == SHN_UNDEF)
671 continue;
672 else if (isym->st_shndx == SHN_ABS)
673 tsec = bfd_abs_section_ptr;
674 else if (isym->st_shndx == SHN_COMMON)
675 tsec = bfd_com_section_ptr;
676 else
677 tsec = bfd_section_from_elf_index (ibfd, isym->st_shndx);
679 address = (tsec->output_section->vma
680 + tsec->output_offset
681 + isym->st_value);
682 if (address <= 0xffff)
684 local_plt_offsets[idx] = -1;
685 splt->_cooked_size -= 4;
686 *again = TRUE;
690 if (isymbuf != NULL
691 && symtab_hdr->contents != (unsigned char *) isymbuf)
693 if (! info->keep_memory)
694 free (isymbuf);
695 else
697 /* Cache the symbols for elf_link_input_bfd. */
698 symtab_hdr->contents = (unsigned char *) isymbuf;
703 /* If we changed anything, walk the symbols again to reallocate
704 .plt entry addresses. */
705 if (*again && splt->_cooked_size > 0)
707 bfd_vma entry = 0;
709 elf_link_hash_traverse (elf_hash_table (info),
710 xstormy16_relax_plt_realloc, &entry);
712 for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
714 bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
715 unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info;
716 unsigned int idx;
718 if (! local_plt_offsets)
719 continue;
721 for (idx = 0; idx < nlocals; ++idx)
722 if (local_plt_offsets[idx] != (bfd_vma) -1)
724 local_plt_offsets[idx] = entry;
725 entry += 4;
730 splt->_raw_size = splt->_cooked_size;
731 return TRUE;
734 static bfd_boolean
735 xstormy16_elf_always_size_sections (output_bfd, info)
736 bfd *output_bfd ATTRIBUTE_UNUSED;
737 struct bfd_link_info *info;
739 bfd *dynobj;
740 asection *splt;
742 if (info->relocatable)
743 return TRUE;
745 dynobj = elf_hash_table (info)->dynobj;
746 if (dynobj == NULL)
747 return TRUE;
749 splt = bfd_get_section_by_name (dynobj, ".plt");
750 BFD_ASSERT (splt != NULL);
752 splt->contents = (bfd_byte *) bfd_zalloc (dynobj, splt->_raw_size);
753 if (splt->contents == NULL)
754 return FALSE;
756 return TRUE;
759 /* Relocate an XSTORMY16 ELF section.
761 The RELOCATE_SECTION function is called by the new ELF backend linker
762 to handle the relocations for a section.
764 The relocs are always passed as Rela structures; if the section
765 actually uses Rel structures, the r_addend field will always be
766 zero.
768 This function is responsible for adjusting the section contents as
769 necessary, and (if using Rela relocs and generating a relocatable
770 output file) adjusting the reloc addend as necessary.
772 This function does not have to worry about setting the reloc
773 address or the reloc symbol index.
775 LOCAL_SYMS is a pointer to the swapped in local symbols.
777 LOCAL_SECTIONS is an array giving the section in the input file
778 corresponding to the st_shndx field of each local symbol.
780 The global hash table entry for the global symbols can be found
781 via elf_sym_hashes (input_bfd).
783 When generating relocatable output, this function must handle
784 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
785 going to be the section symbol corresponding to the output
786 section, which means that the addend must be adjusted
787 accordingly. */
789 static bfd_boolean
790 xstormy16_elf_relocate_section (output_bfd, info, input_bfd, input_section,
791 contents, relocs, local_syms, local_sections)
792 bfd * output_bfd ATTRIBUTE_UNUSED;
793 struct bfd_link_info * info;
794 bfd * input_bfd;
795 asection * input_section;
796 bfd_byte * contents;
797 Elf_Internal_Rela * relocs;
798 Elf_Internal_Sym * local_syms;
799 asection ** local_sections;
801 Elf_Internal_Shdr * symtab_hdr;
802 struct elf_link_hash_entry ** sym_hashes;
803 Elf_Internal_Rela * rel;
804 Elf_Internal_Rela * relend;
805 bfd *dynobj;
806 asection *splt;
808 if (info->relocatable)
809 return TRUE;
811 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
812 sym_hashes = elf_sym_hashes (input_bfd);
813 relend = relocs + input_section->reloc_count;
815 dynobj = elf_hash_table (info)->dynobj;
816 splt = NULL;
817 if (dynobj != NULL)
818 splt = bfd_get_section_by_name (dynobj, ".plt");
820 for (rel = relocs; rel < relend; rel ++)
822 reloc_howto_type * howto;
823 unsigned long r_symndx;
824 Elf_Internal_Sym * sym;
825 asection * sec;
826 struct elf_link_hash_entry * h;
827 bfd_vma relocation;
828 bfd_reloc_status_type r;
829 const char * name = NULL;
830 int r_type;
832 r_type = ELF32_R_TYPE (rel->r_info);
834 if ( r_type == R_XSTORMY16_GNU_VTINHERIT
835 || r_type == R_XSTORMY16_GNU_VTENTRY)
836 continue;
838 r_symndx = ELF32_R_SYM (rel->r_info);
839 howto = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info);
840 h = NULL;
841 sym = NULL;
842 sec = NULL;
844 if (r_symndx < symtab_hdr->sh_info)
846 sym = local_syms + r_symndx;
847 sec = local_sections [r_symndx];
848 relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
850 name = bfd_elf_string_from_elf_section
851 (input_bfd, symtab_hdr->sh_link, sym->st_name);
852 name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
854 else
856 h = sym_hashes [r_symndx - symtab_hdr->sh_info];
858 while (h->root.type == bfd_link_hash_indirect
859 || h->root.type == bfd_link_hash_warning)
860 h = (struct elf_link_hash_entry *) h->root.u.i.link;
862 name = h->root.root.string;
864 if (h->root.type == bfd_link_hash_defined
865 || h->root.type == bfd_link_hash_defweak)
867 sec = h->root.u.def.section;
868 relocation = (h->root.u.def.value
869 + sec->output_section->vma
870 + sec->output_offset);
872 else if (h->root.type == bfd_link_hash_undefweak)
874 relocation = 0;
876 else
878 if (! ((*info->callbacks->undefined_symbol)
879 (info, h->root.root.string, input_bfd,
880 input_section, rel->r_offset, TRUE)))
881 return FALSE;
882 relocation = 0;
886 switch (ELF32_R_TYPE (rel->r_info))
888 case R_XSTORMY16_24:
890 bfd_vma reloc = relocation + rel->r_addend;
891 unsigned int x;
893 x = bfd_get_32 (input_bfd, contents + rel->r_offset);
894 x &= 0x0000ff00;
895 x |= reloc & 0xff;
896 x |= (reloc << 8) & 0xffff0000;
897 bfd_put_32 (input_bfd, x, contents + rel->r_offset);
899 if (reloc & ~0xffffff)
900 r = bfd_reloc_overflow;
901 else
902 r = bfd_reloc_ok;
903 break;
906 case R_XSTORMY16_FPTR16:
908 bfd_vma *plt_offset;
910 if (h != NULL)
911 plt_offset = &h->plt.offset;
912 else
913 plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
915 if (relocation <= 0xffff)
917 /* If the symbol is in range for a 16-bit address, we should
918 have deallocated the plt entry in relax_section. */
919 BFD_ASSERT (*plt_offset == (bfd_vma) -1);
921 else
923 /* If the symbol is out of range for a 16-bit address,
924 we must have allocated a plt entry. */
925 BFD_ASSERT (*plt_offset != (bfd_vma) -1);
927 /* If this is the first time we've processed this symbol,
928 fill in the plt entry with the correct symbol address. */
929 if ((*plt_offset & 1) == 0)
931 unsigned int x;
933 x = 0x00000200; /* jmpf */
934 x |= relocation & 0xff;
935 x |= (relocation << 8) & 0xffff0000;
936 bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
937 *plt_offset |= 1;
940 relocation = (splt->output_section->vma
941 + splt->output_offset
942 + (*plt_offset & -2));
944 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
945 contents, rel->r_offset,
946 relocation, 0);
947 break;
950 default:
951 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
952 contents, rel->r_offset,
953 relocation, rel->r_addend);
954 break;
957 if (r != bfd_reloc_ok)
959 const char * msg = (const char *) NULL;
961 switch (r)
963 case bfd_reloc_overflow:
964 r = info->callbacks->reloc_overflow
965 (info, name, howto->name, (bfd_vma) 0,
966 input_bfd, input_section, rel->r_offset);
967 break;
969 case bfd_reloc_undefined:
970 r = info->callbacks->undefined_symbol
971 (info, name, input_bfd, input_section, rel->r_offset,
972 TRUE);
973 break;
975 case bfd_reloc_outofrange:
976 msg = _("internal error: out of range error");
977 break;
979 case bfd_reloc_notsupported:
980 msg = _("internal error: unsupported relocation error");
981 break;
983 case bfd_reloc_dangerous:
984 msg = _("internal error: dangerous relocation");
985 break;
987 default:
988 msg = _("internal error: unknown error");
989 break;
992 if (msg)
993 r = info->callbacks->warning
994 (info, msg, name, input_bfd, input_section, rel->r_offset);
996 if (! r)
997 return FALSE;
1001 return TRUE;
1004 /* This must exist if dynobj is ever set. */
1006 static bfd_boolean
1007 xstormy16_elf_finish_dynamic_sections (abfd, info)
1008 bfd *abfd ATTRIBUTE_UNUSED;
1009 struct bfd_link_info *info;
1011 bfd *dynobj;
1012 asection *splt;
1014 /* As an extra sanity check, verify that all plt entries have
1015 been filled in. */
1017 if ((dynobj = elf_hash_table (info)->dynobj) != NULL
1018 && (splt = bfd_get_section_by_name (dynobj, ".plt")) != NULL)
1020 bfd_byte *contents = splt->contents;
1021 unsigned int i, size = splt->_raw_size;
1022 for (i = 0; i < size; i += 4)
1024 unsigned int x = bfd_get_32 (dynobj, contents + i);
1025 BFD_ASSERT (x != 0);
1029 return TRUE;
1032 /* Return the section that should be marked against GC for a given
1033 relocation. */
1035 static asection *
1036 xstormy16_elf_gc_mark_hook (sec, info, rel, h, sym)
1037 asection * sec;
1038 struct bfd_link_info * info ATTRIBUTE_UNUSED;
1039 Elf_Internal_Rela * rel;
1040 struct elf_link_hash_entry * h;
1041 Elf_Internal_Sym * sym;
1043 if (h != NULL)
1045 switch (ELF32_R_TYPE (rel->r_info))
1047 case R_XSTORMY16_GNU_VTINHERIT:
1048 case R_XSTORMY16_GNU_VTENTRY:
1049 break;
1051 default:
1052 switch (h->root.type)
1054 case bfd_link_hash_defined:
1055 case bfd_link_hash_defweak:
1056 return h->root.u.def.section;
1058 case bfd_link_hash_common:
1059 return h->root.u.c.p->section;
1061 default:
1062 break;
1066 else
1067 return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
1069 return NULL;
1072 /* Update the got entry reference counts for the section being removed. */
1074 static bfd_boolean
1075 xstormy16_elf_gc_sweep_hook (abfd, info, sec, relocs)
1076 bfd * abfd ATTRIBUTE_UNUSED;
1077 struct bfd_link_info * info ATTRIBUTE_UNUSED;
1078 asection * sec ATTRIBUTE_UNUSED;
1079 const Elf_Internal_Rela * relocs ATTRIBUTE_UNUSED;
1081 return TRUE;
1084 #define ELF_ARCH bfd_arch_xstormy16
1085 #define ELF_MACHINE_CODE EM_XSTORMY16
1086 #define ELF_MAXPAGESIZE 0x100
1088 #define TARGET_LITTLE_SYM bfd_elf32_xstormy16_vec
1089 #define TARGET_LITTLE_NAME "elf32-xstormy16"
1091 #define elf_info_to_howto_rel NULL
1092 #define elf_info_to_howto xstormy16_info_to_howto_rela
1093 #define elf_backend_relocate_section xstormy16_elf_relocate_section
1094 #define elf_backend_gc_mark_hook xstormy16_elf_gc_mark_hook
1095 #define elf_backend_gc_sweep_hook xstormy16_elf_gc_sweep_hook
1096 #define elf_backend_check_relocs xstormy16_elf_check_relocs
1097 #define elf_backend_always_size_sections \
1098 xstormy16_elf_always_size_sections
1099 #define elf_backend_finish_dynamic_sections \
1100 xstormy16_elf_finish_dynamic_sections
1102 #define elf_backend_can_gc_sections 1
1103 #define elf_backend_rela_normal 1
1105 #define bfd_elf32_bfd_reloc_type_lookup xstormy16_reloc_type_lookup
1106 #define bfd_elf32_bfd_relax_section xstormy16_elf_relax_section
1108 #include "elf32-target.h"