elf32-xstormy16.c revision 1.1.1.1 1 /* Xstormy16-specific support for 32-bit ELF.
2 Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2010, 2011, 2012
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 /* PR15323, ref flags aren't set for references in the same
444 object. */
445 h->root.non_ir_ref = 1;
446 }
447
448 switch (ELF32_R_TYPE (rel->r_info))
449 {
450 /* This relocation describes a 16-bit pointer to a function.
451 We may need to allocate a thunk in low memory; reserve memory
452 for it now. */
453 case R_XSTORMY16_FPTR16:
454 if (rel->r_addend != 0)
455 {
456 (*info->callbacks->warning)
457 (info, _("non-zero addend in @fptr reloc"), 0,
458 abfd, 0, 0);
459 }
460
461 if (dynobj == NULL)
462 elf_hash_table (info)->dynobj = dynobj = abfd;
463 if (splt == NULL)
464 {
465 splt = bfd_get_linker_section (dynobj, ".plt");
466 if (splt == NULL)
467 {
468 flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
469 | SEC_IN_MEMORY | SEC_LINKER_CREATED
470 | SEC_READONLY | SEC_CODE);
471
472 splt = bfd_make_section_anyway_with_flags (dynobj, ".plt",
473 flags);
474 if (splt == NULL
475 || ! bfd_set_section_alignment (dynobj, splt, 1))
476 return FALSE;
477 }
478 }
479
480 if (h != NULL)
481 offset = &h->plt.offset;
482 else
483 {
484 if (local_plt_offsets == NULL)
485 {
486 size_t size;
487 unsigned int i;
488
489 size = symtab_hdr->sh_info * sizeof (bfd_vma);
490 local_plt_offsets = bfd_alloc (abfd, size);
491 if (local_plt_offsets == NULL)
492 return FALSE;
493 elf_local_got_offsets (abfd) = local_plt_offsets;
494
495 for (i = 0; i < symtab_hdr->sh_info; i++)
496 local_plt_offsets[i] = (bfd_vma) -1;
497 }
498 offset = &local_plt_offsets[r_symndx];
499 }
500
501 if (*offset == (bfd_vma) -1)
502 {
503 *offset = splt->size;
504 splt->size += 4;
505 }
506 break;
507
508 /* This relocation describes the C++ object vtable hierarchy.
509 Reconstruct it for later use during GC. */
510 case R_XSTORMY16_GNU_VTINHERIT:
511 if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
512 return FALSE;
513 break;
514
515 /* This relocation describes which C++ vtable entries are actually
516 used. Record for later use during GC. */
517 case R_XSTORMY16_GNU_VTENTRY:
518 BFD_ASSERT (h != NULL);
519 if (h != NULL
520 && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
521 return FALSE;
522 break;
523 }
524 }
525
526 return TRUE;
527 }
528
529 /* A subroutine of xstormy16_elf_relax_section. If the global symbol H
530 is within the low 64k, remove any entry for it in the plt. */
531
532 struct relax_plt_data
533 {
534 asection *splt;
535 bfd_boolean *again;
536 };
537
538 static bfd_boolean
539 xstormy16_relax_plt_check (struct elf_link_hash_entry *h, void * xdata)
540 {
541 struct relax_plt_data *data = (struct relax_plt_data *) xdata;
542
543 if (h->plt.offset != (bfd_vma) -1)
544 {
545 bfd_vma address;
546
547 if (h->root.type == bfd_link_hash_undefined
548 || h->root.type == bfd_link_hash_undefweak)
549 address = 0;
550 else
551 address = (h->root.u.def.section->output_section->vma
552 + h->root.u.def.section->output_offset
553 + h->root.u.def.value);
554
555 if (address <= 0xffff)
556 {
557 h->plt.offset = -1;
558 data->splt->size -= 4;
559 *data->again = TRUE;
560 }
561 }
562
563 return TRUE;
564 }
565
566 /* A subroutine of xstormy16_elf_relax_section. If the global symbol H
567 previously had a plt entry, give it a new entry offset. */
568
569 static bfd_boolean
570 xstormy16_relax_plt_realloc (struct elf_link_hash_entry *h, void * xdata)
571 {
572 bfd_vma *entry = (bfd_vma *) xdata;
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 (bfd *dynobj,
585 asection *splt,
586 struct bfd_link_info *info,
587 bfd_boolean *again)
588 {
589 struct relax_plt_data relax_plt_data;
590 bfd *ibfd;
591
592 /* Assume nothing changes. */
593 *again = FALSE;
594
595 if (info->relocatable)
596 return TRUE;
597
598 /* We only relax the .plt section at the moment. */
599 if (dynobj != elf_hash_table (info)->dynobj
600 || strcmp (splt->name, ".plt") != 0)
601 return TRUE;
602
603 /* Quick check for an empty plt. */
604 if (splt->size == 0)
605 return TRUE;
606
607 /* Map across all global symbols; see which ones happen to
608 fall in the low 64k. */
609 relax_plt_data.splt = splt;
610 relax_plt_data.again = again;
611 elf_link_hash_traverse (elf_hash_table (info), xstormy16_relax_plt_check,
612 &relax_plt_data);
613
614 /* Likewise for local symbols, though that's somewhat less convenient
615 as we have to walk the list of input bfds and swap in symbol data. */
616 for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
617 {
618 bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
619 Elf_Internal_Shdr *symtab_hdr;
620 Elf_Internal_Sym *isymbuf = NULL;
621 unsigned int idx;
622
623 if (! local_plt_offsets)
624 continue;
625
626 symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
627 if (symtab_hdr->sh_info != 0)
628 {
629 isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
630 if (isymbuf == NULL)
631 isymbuf = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
632 symtab_hdr->sh_info, 0,
633 NULL, NULL, NULL);
634 if (isymbuf == NULL)
635 return FALSE;
636 }
637
638 for (idx = 0; idx < symtab_hdr->sh_info; ++idx)
639 {
640 Elf_Internal_Sym *isym;
641 asection *tsec;
642 bfd_vma address;
643
644 if (local_plt_offsets[idx] == (bfd_vma) -1)
645 continue;
646
647 isym = &isymbuf[idx];
648 if (isym->st_shndx == SHN_UNDEF)
649 continue;
650 else if (isym->st_shndx == SHN_ABS)
651 tsec = bfd_abs_section_ptr;
652 else if (isym->st_shndx == SHN_COMMON)
653 tsec = bfd_com_section_ptr;
654 else
655 tsec = bfd_section_from_elf_index (ibfd, isym->st_shndx);
656
657 address = (tsec->output_section->vma
658 + tsec->output_offset
659 + isym->st_value);
660 if (address <= 0xffff)
661 {
662 local_plt_offsets[idx] = -1;
663 splt->size -= 4;
664 *again = TRUE;
665 }
666 }
667
668 if (isymbuf != NULL
669 && symtab_hdr->contents != (unsigned char *) isymbuf)
670 {
671 if (! info->keep_memory)
672 free (isymbuf);
673 else
674 {
675 /* Cache the symbols for elf_link_input_bfd. */
676 symtab_hdr->contents = (unsigned char *) isymbuf;
677 }
678 }
679 }
680
681 /* If we changed anything, walk the symbols again to reallocate
682 .plt entry addresses. */
683 if (*again && splt->size > 0)
684 {
685 bfd_vma entry = 0;
686
687 elf_link_hash_traverse (elf_hash_table (info),
688 xstormy16_relax_plt_realloc, &entry);
689
690 for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
691 {
692 bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
693 unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info;
694 unsigned int idx;
695
696 if (! local_plt_offsets)
697 continue;
698
699 for (idx = 0; idx < nlocals; ++idx)
700 if (local_plt_offsets[idx] != (bfd_vma) -1)
701 {
702 local_plt_offsets[idx] = entry;
703 entry += 4;
704 }
705 }
706 }
707
708 return TRUE;
709 }
710
711 static bfd_boolean
712 xstormy16_elf_always_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
713 struct bfd_link_info *info)
714 {
715 bfd *dynobj;
716 asection *splt;
717
718 if (info->relocatable)
719 return TRUE;
720
721 dynobj = elf_hash_table (info)->dynobj;
722 if (dynobj == NULL)
723 return TRUE;
724
725 splt = bfd_get_linker_section (dynobj, ".plt");
726 BFD_ASSERT (splt != NULL);
727
728 splt->contents = bfd_zalloc (dynobj, splt->size);
729 if (splt->contents == NULL)
730 return FALSE;
731
732 return TRUE;
733 }
734
735 /* Relocate an XSTORMY16 ELF section.
737
738 The RELOCATE_SECTION function is called by the new ELF backend linker
739 to handle the relocations for a section.
740
741 The relocs are always passed as Rela structures; if the section
742 actually uses Rel structures, the r_addend field will always be
743 zero.
744
745 This function is responsible for adjusting the section contents as
746 necessary, and (if using Rela relocs and generating a relocatable
747 output file) adjusting the reloc addend as necessary.
748
749 This function does not have to worry about setting the reloc
750 address or the reloc symbol index.
751
752 LOCAL_SYMS is a pointer to the swapped in local symbols.
753
754 LOCAL_SECTIONS is an array giving the section in the input file
755 corresponding to the st_shndx field of each local symbol.
756
757 The global hash table entry for the global symbols can be found
758 via elf_sym_hashes (input_bfd).
759
760 When generating relocatable output, this function must handle
761 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
762 going to be the section symbol corresponding to the output
763 section, which means that the addend must be adjusted
764 accordingly. */
765
766 static bfd_boolean
767 xstormy16_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED,
768 struct bfd_link_info * info,
769 bfd * input_bfd,
770 asection * input_section,
771 bfd_byte * contents,
772 Elf_Internal_Rela * relocs,
773 Elf_Internal_Sym * local_syms,
774 asection ** local_sections)
775 {
776 Elf_Internal_Shdr * symtab_hdr;
777 struct elf_link_hash_entry ** sym_hashes;
778 Elf_Internal_Rela * rel;
779 Elf_Internal_Rela * relend;
780 bfd *dynobj;
781 asection *splt;
782
783 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
784 sym_hashes = elf_sym_hashes (input_bfd);
785 relend = relocs + input_section->reloc_count;
786
787 dynobj = elf_hash_table (info)->dynobj;
788 splt = NULL;
789 if (dynobj != NULL)
790 splt = bfd_get_linker_section (dynobj, ".plt");
791
792 for (rel = relocs; rel < relend; rel ++)
793 {
794 reloc_howto_type * howto;
795 unsigned long r_symndx;
796 Elf_Internal_Sym * sym;
797 asection * sec;
798 struct elf_link_hash_entry * h;
799 bfd_vma relocation;
800 bfd_reloc_status_type r;
801 const char * name = NULL;
802 int r_type;
803
804 r_type = ELF32_R_TYPE (rel->r_info);
805
806 if ( r_type == R_XSTORMY16_GNU_VTINHERIT
807 || r_type == R_XSTORMY16_GNU_VTENTRY)
808 continue;
809
810 r_symndx = ELF32_R_SYM (rel->r_info);
811 howto = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info);
812 h = NULL;
813 sym = NULL;
814 sec = NULL;
815
816 if (r_symndx < symtab_hdr->sh_info)
817 {
818 sym = local_syms + r_symndx;
819 sec = local_sections [r_symndx];
820 relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
821 }
822 else
823 {
824 bfd_boolean unresolved_reloc, warned, ignored;
825
826 RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
827 r_symndx, symtab_hdr, sym_hashes,
828 h, sec, relocation,
829 unresolved_reloc, warned, ignored);
830 }
831
832 if (sec != NULL && discarded_section (sec))
833 RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
834 rel, 1, relend, howto, 0, contents);
835
836 if (info->relocatable)
837 continue;
838
839 if (h != NULL)
840 name = h->root.root.string;
841 else
842 {
843 name = (bfd_elf_string_from_elf_section
844 (input_bfd, symtab_hdr->sh_link, sym->st_name));
845 if (name == NULL || *name == '\0')
846 name = bfd_section_name (input_bfd, sec);
847 }
848
849 switch (ELF32_R_TYPE (rel->r_info))
850 {
851 case R_XSTORMY16_24:
852 {
853 bfd_vma reloc = relocation + rel->r_addend;
854 unsigned int x;
855
856 x = bfd_get_32 (input_bfd, contents + rel->r_offset);
857 x &= 0x0000ff00;
858 x |= reloc & 0xff;
859 x |= (reloc << 8) & 0xffff0000;
860 bfd_put_32 (input_bfd, x, contents + rel->r_offset);
861
862 if (reloc & ~0xffffff)
863 r = bfd_reloc_overflow;
864 else
865 r = bfd_reloc_ok;
866 break;
867 }
868
869 case R_XSTORMY16_FPTR16:
870 {
871 bfd_vma *plt_offset;
872
873 if (h != NULL)
874 plt_offset = &h->plt.offset;
875 else
876 plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
877
878 if (relocation <= 0xffff)
879 {
880 /* If the symbol is in range for a 16-bit address, we should
881 have deallocated the plt entry in relax_section. */
882 BFD_ASSERT (*plt_offset == (bfd_vma) -1);
883 }
884 else
885 {
886 /* If the symbol is out of range for a 16-bit address,
887 we must have allocated a plt entry. */
888 BFD_ASSERT (*plt_offset != (bfd_vma) -1);
889
890 /* If this is the first time we've processed this symbol,
891 fill in the plt entry with the correct symbol address. */
892 if ((*plt_offset & 1) == 0)
893 {
894 unsigned int x;
895
896 x = 0x00000200; /* jmpf */
897 x |= relocation & 0xff;
898 x |= (relocation << 8) & 0xffff0000;
899 bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
900 *plt_offset |= 1;
901 }
902
903 relocation = (splt->output_section->vma
904 + splt->output_offset
905 + (*plt_offset & -2));
906 }
907 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
908 contents, rel->r_offset,
909 relocation, 0);
910 break;
911 }
912
913 default:
914 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
915 contents, rel->r_offset,
916 relocation, rel->r_addend);
917 break;
918 }
919
920 if (r != bfd_reloc_ok)
921 {
922 const char * msg = NULL;
923
924 switch (r)
925 {
926 case bfd_reloc_overflow:
927 r = info->callbacks->reloc_overflow
928 (info, (h ? &h->root : NULL), name, howto->name,
929 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
930 break;
931
932 case bfd_reloc_undefined:
933 r = info->callbacks->undefined_symbol
934 (info, name, input_bfd, input_section, rel->r_offset,
935 TRUE);
936 break;
937
938 case bfd_reloc_outofrange:
939 msg = _("internal error: out of range error");
940 break;
941
942 case bfd_reloc_notsupported:
943 msg = _("internal error: unsupported relocation error");
944 break;
945
946 case bfd_reloc_dangerous:
947 msg = _("internal error: dangerous relocation");
948 break;
949
950 default:
951 msg = _("internal error: unknown error");
952 break;
953 }
954
955 if (msg)
956 r = info->callbacks->warning
957 (info, msg, name, input_bfd, input_section, rel->r_offset);
958
959 if (! r)
960 return FALSE;
961 }
962 }
963
964 return TRUE;
965 }
966
967 /* This must exist if dynobj is ever set. */
968
969 static bfd_boolean
970 xstormy16_elf_finish_dynamic_sections (bfd *abfd ATTRIBUTE_UNUSED,
971 struct bfd_link_info *info)
972 {
973 bfd *dynobj;
974 asection *splt;
975
976 /* As an extra sanity check, verify that all plt entries have
977 been filled in. */
978
979 if ((dynobj = elf_hash_table (info)->dynobj) != NULL
980 && (splt = bfd_get_linker_section (dynobj, ".plt")) != NULL)
981 {
982 bfd_byte *contents = splt->contents;
983 unsigned int i, size = splt->size;
984
985 for (i = 0; i < size; i += 4)
986 {
987 unsigned int x = bfd_get_32 (dynobj, contents + i);
988
989 BFD_ASSERT (x != 0);
990 }
991 }
992
993 return TRUE;
994 }
995
996 /* Return the section that should be marked against GC for a given
998 relocation. */
999
1000 static asection *
1001 xstormy16_elf_gc_mark_hook (asection *sec,
1002 struct bfd_link_info *info,
1003 Elf_Internal_Rela *rel,
1004 struct elf_link_hash_entry *h,
1005 Elf_Internal_Sym *sym)
1006 {
1007 if (h != NULL)
1008 switch (ELF32_R_TYPE (rel->r_info))
1009 {
1010 case R_XSTORMY16_GNU_VTINHERIT:
1011 case R_XSTORMY16_GNU_VTENTRY:
1012 return NULL;
1013 }
1014
1015 return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
1016 }
1017
1018 #define ELF_ARCH bfd_arch_xstormy16
1020 #define ELF_MACHINE_CODE EM_XSTORMY16
1021 #define ELF_MAXPAGESIZE 0x100
1022
1023 #define TARGET_LITTLE_SYM bfd_elf32_xstormy16_vec
1024 #define TARGET_LITTLE_NAME "elf32-xstormy16"
1025
1026 #define elf_info_to_howto_rel NULL
1027 #define elf_info_to_howto xstormy16_info_to_howto_rela
1028 #define elf_backend_relocate_section xstormy16_elf_relocate_section
1029 #define elf_backend_gc_mark_hook xstormy16_elf_gc_mark_hook
1030 #define elf_backend_check_relocs xstormy16_elf_check_relocs
1031 #define elf_backend_always_size_sections \
1032 xstormy16_elf_always_size_sections
1033 #define elf_backend_omit_section_dynsym \
1034 ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
1035 #define elf_backend_finish_dynamic_sections \
1036 xstormy16_elf_finish_dynamic_sections
1037
1038 #define elf_backend_can_gc_sections 1
1039 #define elf_backend_rela_normal 1
1040
1041 #define bfd_elf32_bfd_reloc_type_lookup xstormy16_reloc_type_lookup
1042 #define bfd_elf32_bfd_reloc_name_lookup \
1043 xstormy16_reloc_name_lookup
1044 #define bfd_elf32_bfd_relax_section xstormy16_elf_relax_section
1045
1046 #include "elf32-target.h"
1047