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