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