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