source: trunk/binutils/bfd/elf32-xstormy16.c@ 3232

Last change on this file since 3232 was 607, checked in by bird, 22 years ago

Initial revision

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