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