* elf32-arc.c: Fix formatting.
[deliverable/binutils-gdb.git] / bfd / elf32-xstormy16.c
CommitLineData
93fbbb04 1/* XSTORMY16-specific support for 32-bit ELF.
1f7fd478 2 Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
93fbbb04
GK
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"
1f7fd478 25#include "libiberty.h"
93fbbb04
GK
26
27/* Forward declarations. */
28static reloc_howto_type * xstormy16_reloc_type_lookup
29 PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
cedb70c5 30static void xstormy16_info_to_howto_rela
93fbbb04 31 PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
cedb70c5 32static bfd_reloc_status_type xstormy16_elf_24_reloc
93fbbb04
GK
33 PARAMS ((bfd *abfd, arelent *reloc_entry, asymbol *symbol,
34 PTR data, asection *input_section, bfd *output_bfd,
35 char **error_message));
36static boolean xstormy16_elf_check_relocs
37 PARAMS ((bfd *, struct bfd_link_info *, asection *,
38 const Elf_Internal_Rela *));
39static boolean xstormy16_relax_plt_check
40 PARAMS ((struct elf_link_hash_entry *, PTR));
41static boolean xstormy16_relax_plt_realloc
42 PARAMS ((struct elf_link_hash_entry *, PTR));
43static boolean xstormy16_elf_relax_section
44 PARAMS ((bfd *abfd, asection *sec, struct bfd_link_info *link_info,
45 boolean *again));
46static boolean xstormy16_elf_always_size_sections
47 PARAMS ((bfd *, struct bfd_link_info *));
cedb70c5 48static boolean xstormy16_elf_relocate_section
93fbbb04
GK
49 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
50 Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
51static boolean xstormy16_elf_finish_dynamic_sections
52 PARAMS((bfd *, struct bfd_link_info *));
53static 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 ((bfd *, 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 */
cedb70c5 91
93fbbb04
GK
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 */
cedb70c5 106
93fbbb04
GK
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 */
cedb70c5 121
93fbbb04
GK
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 */
cedb70c5 136
93fbbb04
GK
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 */
cedb70c5 151
93fbbb04
GK
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 */
cedb70c5 166
93fbbb04
GK
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 */
cedb70c5 181
93fbbb04
GK
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 */
cedb70c5 196
93fbbb04
GK
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};
cedb70c5 212
93fbbb04
GK
213static 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 */
cedb70c5 244
93fbbb04
GK
245};
246\f
247/* Map BFD reloc types to XSTORMY16 ELF reloc types. */
248
1f7fd478 249typedef struct xstormy16_reloc_map
93fbbb04 250{
1f7fd478
NC
251 bfd_reloc_code_real_type bfd_reloc_val;
252 unsigned int xstormy16_reloc_val;
253 reloc_howto_type * table;
254} reloc_map;
93fbbb04 255
1f7fd478 256static const reloc_map xstormy16_reloc_map [] =
93fbbb04 257{
1f7fd478
NC
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 },
93fbbb04
GK
270};
271
272static reloc_howto_type *
273xstormy16_reloc_type_lookup (abfd, code)
274 bfd * abfd ATTRIBUTE_UNUSED;
275 bfd_reloc_code_real_type code;
276{
277 unsigned int i;
278
1f7fd478
NC
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 }
cedb70c5 289
93fbbb04
GK
290 return NULL;
291}
292
293/* Set the howto pointer for an XSTORMY16 ELF reloc. */
294
295static void
296xstormy16_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
315static bfd_reloc_status_type
316xstormy16_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
364static boolean
365xstormy16_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;
cedb70c5 454
93fbbb04
GK
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;
cedb70c5 474
93fbbb04
GK
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
490struct relax_plt_data
491{
492 asection *splt;
493 boolean *again;
494};
495
496static boolean
497xstormy16_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
e92d460e
AM
503 if (h->root.type == bfd_link_hash_warning)
504 h = (struct elf_link_hash_entry *) h->root.u.i.link;
505
93fbbb04
GK
506 if (h->plt.offset != (bfd_vma) -1)
507 {
508 bfd_vma address;
509
510 if (h->root.type == bfd_link_hash_undefined
511 || h->root.type == bfd_link_hash_undefweak)
512 address = 0;
513 else
514 address = (h->root.u.def.section->output_section->vma
515 + h->root.u.def.section->output_offset
516 + h->root.u.def.value);
517
518 if (address <= 0xffff)
519 {
520 h->plt.offset = -1;
521 data->splt->_cooked_size -= 4;
522 *data->again = true;
523 }
524 }
525
526 return true;
527}
528
529/* A subroutine of xstormy16_elf_relax_section. If the global symbol H
530 previously had a plt entry, give it a new entry offset. */
531
532static boolean
533xstormy16_relax_plt_realloc (h, xdata)
534 struct elf_link_hash_entry *h;
535 PTR xdata;
536{
537 bfd_vma *entry = (bfd_vma *) xdata;
538
e92d460e
AM
539 if (h->root.type == bfd_link_hash_warning)
540 h = (struct elf_link_hash_entry *) h->root.u.i.link;
541
93fbbb04
GK
542 if (h->plt.offset != (bfd_vma) -1)
543 {
544 h->plt.offset = *entry;
545 *entry += 4;
546 }
547
548 return true;
549}
550
551static boolean
552xstormy16_elf_relax_section (dynobj, splt, info, again)
553 bfd *dynobj;
554 asection *splt;
555 struct bfd_link_info *info;
556 boolean *again;
557{
558 struct relax_plt_data relax_plt_data;
559 bfd *ibfd;
560
561 /* Assume nothing changes. */
562 *again = false;
563
564 if (info->relocateable)
565 return true;
566
567 /* We only relax the .plt section at the moment. */
568 if (dynobj != elf_hash_table (info)->dynobj
569 || strcmp (splt->name, ".plt") != 0)
570 return true;
571
572 /* Quick check for an empty plt. */
573 if (splt->_raw_size == 0)
574 return true;
575
576 /* If this is the first time we have been called for this section,
577 initialize the cooked size. */
578 if (splt->_cooked_size == 0)
579 splt->_cooked_size = splt->_raw_size;
580
cedb70c5 581 /* Map across all global symbols; see which ones happen to
93fbbb04
GK
582 fall in the low 64k. */
583 relax_plt_data.splt = splt;
584 relax_plt_data.again = again;
585 elf_link_hash_traverse (elf_hash_table (info), xstormy16_relax_plt_check,
586 &relax_plt_data);
587
588 /* Likewise for local symbols, though that's somewhat less convenient
589 as we have walk the list of input bfds and swap in symbol data. */
590 for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
591 {
592 bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
593 Elf_Internal_Shdr *symtab_hdr;
9ad5cbcf 594 Elf_Internal_Shdr *shndx_hdr;
93fbbb04 595 Elf32_External_Sym *extsyms;
9ad5cbcf 596 Elf_External_Sym_Shndx *shndx_buf;
93fbbb04
GK
597 unsigned int idx;
598
599 if (! local_plt_offsets)
600 continue;
601
602 symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
9ad5cbcf 603 shndx_hdr = &elf_tdata (ibfd)->symtab_shndx_hdr;
93fbbb04
GK
604
605 if (symtab_hdr->contents != NULL)
606 extsyms = (Elf32_External_Sym *) symtab_hdr->contents;
607 else
608 {
9ad5cbcf
AM
609 bfd_size_type amt;
610
611 amt = symtab_hdr->sh_info;
612 amt *= sizeof (Elf32_External_Sym);
613 extsyms = (Elf32_External_Sym *) bfd_malloc (amt);
93fbbb04
GK
614 if (extsyms == NULL)
615 return false;
616 if (bfd_seek (ibfd, symtab_hdr->sh_offset, SEEK_SET) != 0
9ad5cbcf 617 || bfd_bread ((PTR) extsyms, amt, ibfd) != amt)
93fbbb04 618 {
9ad5cbcf 619 error_ret_free_extsyms:
93fbbb04
GK
620 free (extsyms);
621 return false;
622 }
623 }
624
9ad5cbcf
AM
625 shndx_buf = NULL;
626 if (shndx_hdr->sh_size != 0)
627 {
628 bfd_size_type amt;
629
630 amt = symtab_hdr->sh_info;
631 amt *= sizeof (Elf_External_Sym_Shndx);
632 shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
633 if (shndx_buf == NULL)
634 goto error_ret_free_extsyms;
635 if (bfd_seek (ibfd, shndx_hdr->sh_offset, SEEK_SET) != 0
636 || bfd_bread ((PTR) shndx_buf, amt, ibfd) != amt)
637 {
638 free (shndx_buf);
639 goto error_ret_free_extsyms;
640 }
641 shndx_hdr->contents = (bfd_byte *) shndx_buf;
642 }
643
93fbbb04
GK
644 for (idx = 0; idx < symtab_hdr->sh_info; ++idx)
645 {
9ad5cbcf 646 Elf_External_Sym_Shndx *shndx;
93fbbb04
GK
647 Elf_Internal_Sym isym;
648 asection *tsec;
649 bfd_vma address;
650
651 if (local_plt_offsets[idx] == (bfd_vma) -1)
652 continue;
653
9ad5cbcf
AM
654 shndx = shndx_buf;
655 if (shndx != NULL)
656 shndx += idx;
657 bfd_elf32_swap_symbol_in (ibfd, extsyms + idx, shndx, &isym);
93fbbb04
GK
658 if (isym.st_shndx == SHN_UNDEF)
659 continue;
93fbbb04
GK
660 else if (isym.st_shndx == SHN_ABS)
661 tsec = bfd_abs_section_ptr;
9ad5cbcf
AM
662 else if (isym.st_shndx == SHN_COMMON)
663 tsec = bfd_com_section_ptr;
93fbbb04 664 else
9ad5cbcf 665 tsec = bfd_section_from_elf_index (ibfd, isym.st_shndx);
93fbbb04
GK
666
667 address = (tsec->output_section->vma
668 + tsec->output_offset
669 + isym.st_value);
670 if (address <= 0xffff)
671 {
672 local_plt_offsets[idx] = -1;
673 splt->_cooked_size -= 4;
674 *again = true;
675 }
676 }
677
9ad5cbcf
AM
678 if (shndx_buf != NULL)
679 free (shndx_buf);
680
681 if ((Elf32_External_Sym *) symtab_hdr->contents != extsyms)
93fbbb04
GK
682 free (extsyms);
683 }
684
685 /* If we changed anything, walk the symbols again to reallocate
686 .plt entry addresses. */
687 if (*again && splt->_cooked_size > 0)
688 {
689 bfd_vma entry = 0;
690
691 elf_link_hash_traverse (elf_hash_table (info),
692 xstormy16_relax_plt_realloc, &entry);
693
694 for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
695 {
696 bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
697 unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info;
698 unsigned int idx;
699
700 if (! local_plt_offsets)
701 continue;
702
703 for (idx = 0; idx < nlocals; ++idx)
704 if (local_plt_offsets[idx] != (bfd_vma) -1)
705 {
706 local_plt_offsets[idx] = entry;
707 entry += 4;
708 }
709 }
710 }
711
712 splt->_raw_size = splt->_cooked_size;
713 return true;
714}
715
716static boolean
717xstormy16_elf_always_size_sections (output_bfd, info)
718 bfd *output_bfd ATTRIBUTE_UNUSED;
719 struct bfd_link_info *info;
720{
721 bfd *dynobj;
722 asection *splt;
723
724 if (info->relocateable)
725 return true;
726
727 dynobj = elf_hash_table (info)->dynobj;
728 if (dynobj == NULL)
729 return true;
730
731 splt = bfd_get_section_by_name (dynobj, ".plt");
732 BFD_ASSERT (splt != NULL);
733
734 splt->contents = (bfd_byte *) bfd_zalloc (dynobj, splt->_raw_size);
735 if (splt->contents == NULL)
736 return false;
737
738 return true;
739}
740\f
741/* Relocate an XSTORMY16 ELF section.
742 There is some attempt to make this function usable for many architectures,
743 both USE_REL and USE_RELA ['twould be nice if such a critter existed],
744 if only to serve as a learning tool.
745
746 The RELOCATE_SECTION function is called by the new ELF backend linker
747 to handle the relocations for a section.
748
749 The relocs are always passed as Rela structures; if the section
750 actually uses Rel structures, the r_addend field will always be
751 zero.
752
753 This function is responsible for adjusting the section contents as
754 necessary, and (if using Rela relocs and generating a relocateable
755 output file) adjusting the reloc addend as necessary.
756
757 This function does not have to worry about setting the reloc
758 address or the reloc symbol index.
759
760 LOCAL_SYMS is a pointer to the swapped in local symbols.
761
762 LOCAL_SECTIONS is an array giving the section in the input file
763 corresponding to the st_shndx field of each local symbol.
764
765 The global hash table entry for the global symbols can be found
766 via elf_sym_hashes (input_bfd).
767
768 When generating relocateable output, this function must handle
769 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
770 going to be the section symbol corresponding to the output
771 section, which means that the addend must be adjusted
772 accordingly. */
773
774static boolean
775xstormy16_elf_relocate_section (output_bfd, info, input_bfd, input_section,
776 contents, relocs, local_syms, local_sections)
777 bfd * output_bfd ATTRIBUTE_UNUSED;
778 struct bfd_link_info * info;
779 bfd * input_bfd;
780 asection * input_section;
781 bfd_byte * contents;
782 Elf_Internal_Rela * relocs;
783 Elf_Internal_Sym * local_syms;
784 asection ** local_sections;
785{
786 Elf_Internal_Shdr * symtab_hdr;
787 struct elf_link_hash_entry ** sym_hashes;
788 Elf_Internal_Rela * rel;
789 Elf_Internal_Rela * relend;
790 bfd *dynobj;
791 asection *splt;
792
b491616a
AM
793 if (info->relocateable)
794 return true;
795
93fbbb04
GK
796 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
797 sym_hashes = elf_sym_hashes (input_bfd);
798 relend = relocs + input_section->reloc_count;
799
800 dynobj = elf_hash_table (info)->dynobj;
801 splt = NULL;
802 if (dynobj != NULL)
803 splt = bfd_get_section_by_name (dynobj, ".plt");
804
805 for (rel = relocs; rel < relend; rel ++)
806 {
807 reloc_howto_type * howto;
808 unsigned long r_symndx;
809 Elf_Internal_Sym * sym;
810 asection * sec;
811 struct elf_link_hash_entry * h;
812 bfd_vma relocation;
813 bfd_reloc_status_type r;
814 const char * name = NULL;
815 int r_type;
cedb70c5 816
93fbbb04 817 r_type = ELF32_R_TYPE (rel->r_info);
cedb70c5 818
93fbbb04
GK
819 if ( r_type == R_XSTORMY16_GNU_VTINHERIT
820 || r_type == R_XSTORMY16_GNU_VTENTRY)
821 continue;
cedb70c5 822
93fbbb04 823 r_symndx = ELF32_R_SYM (rel->r_info);
93fbbb04
GK
824 howto = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info);
825 h = NULL;
826 sym = NULL;
827 sec = NULL;
cedb70c5 828
93fbbb04
GK
829 if (r_symndx < symtab_hdr->sh_info)
830 {
831 sym = local_syms + r_symndx;
832 sec = local_sections [r_symndx];
833 relocation = (sec->output_section->vma
834 + sec->output_offset
835 + sym->st_value);
cedb70c5 836
93fbbb04
GK
837 name = bfd_elf_string_from_elf_section
838 (input_bfd, symtab_hdr->sh_link, sym->st_name);
839 name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
840 }
841 else
842 {
843 h = sym_hashes [r_symndx - symtab_hdr->sh_info];
cedb70c5 844
93fbbb04
GK
845 while (h->root.type == bfd_link_hash_indirect
846 || h->root.type == bfd_link_hash_warning)
847 h = (struct elf_link_hash_entry *) h->root.u.i.link;
848
849 name = h->root.root.string;
cedb70c5 850
93fbbb04
GK
851 if (h->root.type == bfd_link_hash_defined
852 || h->root.type == bfd_link_hash_defweak)
853 {
854 sec = h->root.u.def.section;
855 relocation = (h->root.u.def.value
856 + sec->output_section->vma
857 + sec->output_offset);
858 }
859 else if (h->root.type == bfd_link_hash_undefweak)
860 {
861 relocation = 0;
862 }
863 else
864 {
865 if (! ((*info->callbacks->undefined_symbol)
866 (info, h->root.root.string, input_bfd,
867 input_section, rel->r_offset, true)))
868 return false;
869 relocation = 0;
870 }
871 }
cedb70c5 872
93fbbb04
GK
873 switch (ELF32_R_TYPE (rel->r_info))
874 {
875 case R_XSTORMY16_24:
876 {
877 bfd_vma reloc = relocation + rel->r_addend;
878 unsigned int x;
cedb70c5 879
93fbbb04
GK
880 x = bfd_get_32 (input_bfd, contents + rel->r_offset);
881 x &= 0x0000ff00;
882 x |= reloc & 0xff;
883 x |= (reloc << 8) & 0xffff0000;
884 bfd_put_32 (input_bfd, x, contents + rel->r_offset);
885
886 if (reloc & ~0xffffff)
887 r = bfd_reloc_overflow;
888 else
889 r = bfd_reloc_ok;
890 break;
891 }
892
893 case R_XSTORMY16_FPTR16:
894 {
895 bfd_vma *plt_offset;
896
897 if (h != NULL)
898 plt_offset = &h->plt.offset;
899 else
900 plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
901
902 if (relocation <= 0xffff)
903 {
904 /* If the symbol is in range for a 16-bit address, we should
905 have deallocated the plt entry in relax_section. */
906 BFD_ASSERT (*plt_offset == (bfd_vma) -1);
907 }
908 else
909 {
910 /* If the symbol is out of range for a 16-bit address,
911 we must have allocated a plt entry. */
912 BFD_ASSERT (*plt_offset != (bfd_vma) -1);
913
914 /* If this is the first time we've processed this symbol,
915 fill in the plt entry with the correct symbol address. */
916 if ((*plt_offset & 1) == 0)
917 {
918 unsigned int x;
919
920 x = 0x00000200; /* jmpf */
921 x |= relocation & 0xff;
922 x |= (relocation << 8) & 0xffff0000;
923 bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
924 *plt_offset |= 1;
925 }
926
927 relocation = (splt->output_section->vma
928 + splt->output_offset
929 + (*plt_offset & -2));
930 }
931 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
932 contents, rel->r_offset,
933 relocation, 0);
934 break;
935 }
936
937 default:
938 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
939 contents, rel->r_offset,
940 relocation, rel->r_addend);
941 break;
942 }
943
944 if (r != bfd_reloc_ok)
945 {
946 const char * msg = (const char *) NULL;
947
948 switch (r)
949 {
950 case bfd_reloc_overflow:
951 r = info->callbacks->reloc_overflow
952 (info, name, howto->name, (bfd_vma) 0,
953 input_bfd, input_section, rel->r_offset);
954 break;
cedb70c5 955
93fbbb04
GK
956 case bfd_reloc_undefined:
957 r = info->callbacks->undefined_symbol
958 (info, name, input_bfd, input_section, rel->r_offset,
959 true);
960 break;
cedb70c5 961
93fbbb04
GK
962 case bfd_reloc_outofrange:
963 msg = _("internal error: out of range error");
964 break;
965
966 case bfd_reloc_notsupported:
967 msg = _("internal error: unsupported relocation error");
968 break;
969
970 case bfd_reloc_dangerous:
971 msg = _("internal error: dangerous relocation");
972 break;
973
974 default:
975 msg = _("internal error: unknown error");
976 break;
977 }
978
979 if (msg)
980 r = info->callbacks->warning
981 (info, msg, name, input_bfd, input_section, rel->r_offset);
982
983 if (! r)
984 return false;
985 }
986 }
987
988 return true;
989}
990
991/* This must exist if dynobj is ever set. */
992
993static boolean
994xstormy16_elf_finish_dynamic_sections (abfd, info)
995 bfd *abfd ATTRIBUTE_UNUSED;
996 struct bfd_link_info *info;
997{
998 bfd *dynobj;
999 asection *splt;
1000
1001 /* As an extra sanity check, verify that all plt entries have
1002 been filled in. */
1003
1004 if ((dynobj = elf_hash_table (info)->dynobj) != NULL
1005 && (splt = bfd_get_section_by_name (dynobj, ".plt")) != NULL)
1006 {
1007 bfd_byte *contents = splt->contents;
1008 unsigned int i, size = splt->_raw_size;
1009 for (i = 0; i < size; i += 4)
1010 {
1011 unsigned int x = bfd_get_32 (dynobj, contents + i);
1012 BFD_ASSERT (x != 0);
1013 }
1014 }
1015
1016 return true;
1017}
1018\f
1019/* Return the section that should be marked against GC for a given
1020 relocation. */
1021
1022static asection *
1023xstormy16_elf_gc_mark_hook (abfd, info, rel, h, sym)
1024 bfd * abfd;
1025 struct bfd_link_info * info ATTRIBUTE_UNUSED;
1026 Elf_Internal_Rela * rel;
1027 struct elf_link_hash_entry * h;
1028 Elf_Internal_Sym * sym;
1029{
1030 if (h != NULL)
1031 {
1032 switch (ELF32_R_TYPE (rel->r_info))
1033 {
1034 case R_XSTORMY16_GNU_VTINHERIT:
1035 case R_XSTORMY16_GNU_VTENTRY:
1036 break;
1037
1038 default:
1039 switch (h->root.type)
1040 {
1041 case bfd_link_hash_defined:
1042 case bfd_link_hash_defweak:
1043 return h->root.u.def.section;
1044
1045 case bfd_link_hash_common:
1046 return h->root.u.c.p->section;
1047
1048 default:
1049 break;
1050 }
1051 }
1052 }
1053 else
1054 {
9ad5cbcf 1055 return bfd_section_from_elf_index (abfd, sym->st_shndx);
93fbbb04
GK
1056 }
1057
1058 return NULL;
1059}
1060
1061/* Update the got entry reference counts for the section being removed. */
1062
1063static boolean
1064xstormy16_elf_gc_sweep_hook (abfd, info, sec, relocs)
1065 bfd * abfd ATTRIBUTE_UNUSED;
1066 struct bfd_link_info * info ATTRIBUTE_UNUSED;
1067 asection * sec ATTRIBUTE_UNUSED;
1068 const Elf_Internal_Rela * relocs ATTRIBUTE_UNUSED;
1069{
1070 return true;
1071}
1072\f
1073#define ELF_ARCH bfd_arch_xstormy16
1074#define ELF_MACHINE_CODE EM_XSTORMY16
1075#define ELF_MAXPAGESIZE 0x100
1076
1077#define TARGET_LITTLE_SYM bfd_elf32_xstormy16_vec
1078#define TARGET_LITTLE_NAME "elf32-xstormy16"
1079
1080#define elf_info_to_howto_rel NULL
1081#define elf_info_to_howto xstormy16_info_to_howto_rela
1082#define elf_backend_relocate_section xstormy16_elf_relocate_section
1083#define elf_backend_gc_mark_hook xstormy16_elf_gc_mark_hook
1084#define elf_backend_gc_sweep_hook xstormy16_elf_gc_sweep_hook
1085#define elf_backend_check_relocs xstormy16_elf_check_relocs
1086#define elf_backend_always_size_sections \
1087 xstormy16_elf_always_size_sections
1088#define elf_backend_finish_dynamic_sections \
1089 xstormy16_elf_finish_dynamic_sections
1090
1091#define elf_backend_can_gc_sections 1
b491616a 1092#define elf_backend_rela_normal 1
93fbbb04
GK
1093
1094#define bfd_elf32_bfd_reloc_type_lookup xstormy16_reloc_type_lookup
1095#define bfd_elf32_bfd_relax_section xstormy16_elf_relax_section
1096
1097#include "elf32-target.h"
This page took 0.094724 seconds and 4 git commands to generate.