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