bfd/
[deliverable/binutils-gdb.git] / bfd / elf32-xstormy16.c
CommitLineData
93fbbb04 1/* XSTORMY16-specific support for 32-bit ELF.
b2a8e766 2 Copyright 2000, 2001, 2002, 2003, 2004 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
947216bf 31 PARAMS ((bfd *, arelent *, Elf_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));
b34976b6 36static bfd_boolean xstormy16_elf_check_relocs
93fbbb04
GK
37 PARAMS ((bfd *, struct bfd_link_info *, asection *,
38 const Elf_Internal_Rela *));
b34976b6 39static bfd_boolean xstormy16_relax_plt_check
93fbbb04 40 PARAMS ((struct elf_link_hash_entry *, PTR));
b34976b6 41static bfd_boolean xstormy16_relax_plt_realloc
93fbbb04 42 PARAMS ((struct elf_link_hash_entry *, PTR));
b34976b6 43static bfd_boolean xstormy16_elf_relax_section
93fbbb04 44 PARAMS ((bfd *abfd, asection *sec, struct bfd_link_info *link_info,
b34976b6
AM
45 bfd_boolean *again));
46static bfd_boolean xstormy16_elf_always_size_sections
93fbbb04 47 PARAMS ((bfd *, struct bfd_link_info *));
b34976b6 48static bfd_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 **));
b34976b6 51static bfd_boolean xstormy16_elf_finish_dynamic_sections
93fbbb04 52 PARAMS((bfd *, struct bfd_link_info *));
b34976b6 53static bfd_boolean xstormy16_elf_gc_sweep_hook
93fbbb04
GK
54 PARAMS ((bfd *, struct bfd_link_info *, asection *,
55 const Elf_Internal_Rela *));
56static asection * xstormy16_elf_gc_mark_hook
1e2f5b6e 57 PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
93fbbb04
GK
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 */
b34976b6 67 FALSE, /* pc_relative */
93fbbb04
GK
68 0, /* bitpos */
69 complain_overflow_bitfield, /* complain_on_overflow */
70 bfd_elf_generic_reloc, /* special_function */
71 "R_XSTORMY16_NONE", /* name */
b34976b6 72 FALSE, /* partial_inplace */
93fbbb04
GK
73 0, /* src_mask */
74 0, /* dst_mask */
b34976b6 75 FALSE), /* pcrel_offset */
93fbbb04
GK
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 */
b34976b6 82 FALSE, /* pc_relative */
93fbbb04
GK
83 0, /* bitpos */
84 complain_overflow_dont, /* complain_on_overflow */
85 bfd_elf_generic_reloc, /* special_function */
86 "R_XSTORMY16_32", /* name */
b34976b6 87 FALSE, /* partial_inplace */
93fbbb04
GK
88 0, /* src_mask */
89 0xffffffff, /* dst_mask */
b34976b6 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 */
b34976b6 97 FALSE, /* pc_relative */
93fbbb04 98 0, /* bitpos */
0afb2dc0 99 complain_overflow_bitfield, /* complain_on_overflow */
93fbbb04
GK
100 bfd_elf_generic_reloc, /* special_function */
101 "R_XSTORMY16_16", /* name */
b34976b6 102 FALSE, /* partial_inplace */
93fbbb04 103 0, /* src_mask */
4d2e1ff0 104 0xffff, /* dst_mask */
b34976b6 105 FALSE), /* pcrel_offset */
cedb70c5 106
93fbbb04 107 /* An 8 bit absolute relocation. */
4d2e1ff0 108 HOWTO (R_XSTORMY16_8, /* type */
93fbbb04
GK
109 0, /* rightshift */
110 0, /* size (0 = byte, 1 = short, 2 = long) */
111 8, /* bitsize */
b34976b6 112 FALSE, /* pc_relative */
93fbbb04 113 0, /* bitpos */
4d2e1ff0 114 complain_overflow_unsigned, /* complain_on_overflow */
93fbbb04
GK
115 bfd_elf_generic_reloc, /* special_function */
116 "R_XSTORMY16_8", /* name */
b34976b6 117 FALSE, /* partial_inplace */
93fbbb04 118 0, /* src_mask */
4d2e1ff0 119 0xff, /* dst_mask */
b34976b6 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 */
b34976b6 127 TRUE, /* pc_relative */
93fbbb04
GK
128 0, /* bitpos */
129 complain_overflow_dont, /* complain_on_overflow */
130 bfd_elf_generic_reloc, /* special_function */
131 "R_XSTORMY16_PC32", /* name */
b34976b6 132 FALSE, /* partial_inplace */
93fbbb04
GK
133 0, /* src_mask */
134 0xffffffff, /* dst_mask */
b34976b6 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 */
b34976b6 142 TRUE, /* pc_relative */
93fbbb04
GK
143 0, /* bitpos */
144 complain_overflow_signed, /* complain_on_overflow */
145 bfd_elf_generic_reloc, /* special_function */
146 "R_XSTORMY16_PC16", /* name */
b34976b6 147 FALSE, /* partial_inplace */
93fbbb04
GK
148 0, /* src_mask */
149 0xffffffff, /* dst_mask */
b34976b6 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 */
b34976b6 157 TRUE, /* pc_relative */
93fbbb04
GK
158 0, /* bitpos */
159 complain_overflow_signed, /* complain_on_overflow */
160 bfd_elf_generic_reloc, /* special_function */
161 "R_XSTORMY16_PC8", /* name */
b34976b6 162 FALSE, /* partial_inplace */
93fbbb04
GK
163 0, /* src_mask */
164 0xffffffff, /* dst_mask */
b34976b6 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 */
b34976b6 172 TRUE, /* pc_relative */
93fbbb04
GK
173 1, /* bitpos */
174 complain_overflow_signed, /* complain_on_overflow */
175 bfd_elf_generic_reloc, /* special_function */
176 "R_XSTORMY16_REL_12", /* name */
5c9e189c 177 FALSE, /* partial_inplace */
93fbbb04 178 0, /* src_mask */
60e42408 179 0x0ffe, /* dst_mask */
b34976b6 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 */
b34976b6 187 FALSE, /* pc_relative */
93fbbb04
GK
188 0, /* bitpos */
189 complain_overflow_unsigned, /* complain_on_overflow */
190 xstormy16_elf_24_reloc, /* special_function */
191 "R_XSTORMY16_24", /* name */
b34976b6 192 TRUE, /* partial_inplace */
93fbbb04
GK
193 0, /* src_mask */
194 0xffff00ff, /* dst_mask */
b34976b6 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 */
b34976b6 202 FALSE, /* pc_relative */
93fbbb04
GK
203 0, /* bitpos */
204 complain_overflow_bitfield, /* complain_on_overflow */
205 bfd_elf_generic_reloc, /* special_function */
206 "R_XSTORMY16_FPTR16", /* name */
b34976b6 207 FALSE, /* partial_inplace */
93fbbb04
GK
208 0, /* src_mask */
209 0xffffffff, /* dst_mask */
b34976b6 210 FALSE), /* pcrel_offset */
46f2b541
DD
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 */
5fd63999
DD
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 */
93fbbb04 256};
cedb70c5 257
93fbbb04
GK
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 */
b34976b6 265 FALSE, /* pc_relative */
93fbbb04
GK
266 0, /* bitpos */
267 complain_overflow_dont, /* complain_on_overflow */
268 NULL, /* special_function */
269 "R_XSTORMY16_GNU_VTINHERIT", /* name */
b34976b6 270 FALSE, /* partial_inplace */
93fbbb04
GK
271 0, /* src_mask */
272 0, /* dst_mask */
b34976b6 273 FALSE), /* pcrel_offset */
93fbbb04
GK
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 */
b34976b6 280 FALSE, /* pc_relative */
93fbbb04
GK
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 */
b34976b6 285 FALSE, /* partial_inplace */
93fbbb04
GK
286 0, /* src_mask */
287 0, /* dst_mask */
b34976b6 288 FALSE), /* pcrel_offset */
cedb70c5 289
93fbbb04
GK
290};
291\f
292/* Map BFD reloc types to XSTORMY16 ELF reloc types. */
293
1f7fd478 294typedef struct xstormy16_reloc_map
93fbbb04 295{
1f7fd478
NC
296 bfd_reloc_code_real_type bfd_reloc_val;
297 unsigned int xstormy16_reloc_val;
298 reloc_howto_type * table;
299} reloc_map;
93fbbb04 300
1f7fd478 301static const reloc_map xstormy16_reloc_map [] =
93fbbb04 302{
1f7fd478
NC
303 { BFD_RELOC_NONE, R_XSTORMY16_NONE, xstormy16_elf_howto_table },
304 { BFD_RELOC_32, R_XSTORMY16_32, xstormy16_elf_howto_table },
305 { BFD_RELOC_16, R_XSTORMY16_16, xstormy16_elf_howto_table },
306 { BFD_RELOC_8, R_XSTORMY16_8, xstormy16_elf_howto_table },
307 { BFD_RELOC_32_PCREL, R_XSTORMY16_PC32, xstormy16_elf_howto_table },
308 { BFD_RELOC_16_PCREL, R_XSTORMY16_PC16, xstormy16_elf_howto_table },
309 { BFD_RELOC_8_PCREL, R_XSTORMY16_PC8, xstormy16_elf_howto_table },
310 { BFD_RELOC_XSTORMY16_REL_12, R_XSTORMY16_REL_12, xstormy16_elf_howto_table },
311 { BFD_RELOC_XSTORMY16_24, R_XSTORMY16_24, xstormy16_elf_howto_table },
312 { BFD_RELOC_XSTORMY16_FPTR16, R_XSTORMY16_FPTR16, xstormy16_elf_howto_table },
46f2b541
DD
313 { BFD_RELOC_LO16, R_XSTORMY16_LO16, xstormy16_elf_howto_table },
314 { BFD_RELOC_HI16, R_XSTORMY16_HI16, xstormy16_elf_howto_table },
5fd63999 315 { BFD_RELOC_XSTORMY16_12, R_XSTORMY16_12, xstormy16_elf_howto_table },
1f7fd478
NC
316 { BFD_RELOC_VTABLE_INHERIT, R_XSTORMY16_GNU_VTINHERIT, xstormy16_elf_howto_table2 },
317 { BFD_RELOC_VTABLE_ENTRY, R_XSTORMY16_GNU_VTENTRY, xstormy16_elf_howto_table2 },
93fbbb04
GK
318};
319
320static reloc_howto_type *
321xstormy16_reloc_type_lookup (abfd, code)
322 bfd * abfd ATTRIBUTE_UNUSED;
323 bfd_reloc_code_real_type code;
324{
325 unsigned int i;
326
1f7fd478
NC
327 for (i = ARRAY_SIZE (xstormy16_reloc_map); --i;)
328 {
329 const reloc_map * entry;
330
331 entry = xstormy16_reloc_map + i;
332
333 if (entry->bfd_reloc_val == code)
334 return entry->table + (entry->xstormy16_reloc_val
335 - entry->table[0].type);
336 }
cedb70c5 337
93fbbb04
GK
338 return NULL;
339}
340
341/* Set the howto pointer for an XSTORMY16 ELF reloc. */
342
343static void
344xstormy16_info_to_howto_rela (abfd, cache_ptr, dst)
345 bfd * abfd ATTRIBUTE_UNUSED;
346 arelent * cache_ptr;
947216bf 347 Elf_Internal_Rela * dst;
93fbbb04
GK
348{
349 unsigned int r_type = ELF32_R_TYPE (dst->r_info);
350
5fd63999 351 if (r_type <= (unsigned int) R_XSTORMY16_12)
93fbbb04
GK
352 cache_ptr->howto = &xstormy16_elf_howto_table [r_type];
353 else if (r_type - R_XSTORMY16_GNU_VTINHERIT
354 <= (unsigned int) R_XSTORMY16_GNU_VTENTRY)
355 cache_ptr->howto
356 = &xstormy16_elf_howto_table2 [r_type - R_XSTORMY16_GNU_VTINHERIT];
357 else
358 abort ();
359}
360
361/* Handle the R_XSTORMY16_24 reloc, which has an odd bit arrangement. */
362
363static bfd_reloc_status_type
364xstormy16_elf_24_reloc (abfd, reloc_entry, symbol, data, input_section,
365 output_bfd, error_message)
366 bfd *abfd;
367 arelent *reloc_entry;
368 asymbol *symbol;
369 PTR data;
370 asection *input_section;
371 bfd *output_bfd;
372 char **error_message ATTRIBUTE_UNUSED;
373{
374 bfd_vma relocation, x;
eea6121a 375 bfd_size_type sz;
93fbbb04
GK
376
377 if (output_bfd != NULL)
378 {
379 reloc_entry->address += input_section->output_offset;
380 return bfd_reloc_ok;
381 }
382
eea6121a
AM
383 sz = input_section->rawsize ? input_section->rawsize : input_section->size;
384 if (reloc_entry->address > sz)
93fbbb04
GK
385 return bfd_reloc_outofrange;
386
387 if (bfd_is_com_section (symbol->section))
388 relocation = 0;
389 else
390 relocation = symbol->value;
391
392 relocation += symbol->section->output_section->vma;
393 relocation += symbol->section->output_offset;
394 relocation += reloc_entry->addend;
395
396 x = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
397 x &= 0x0000ff00;
398 x |= relocation & 0xff;
399 x |= (relocation << 8) & 0xffff0000;
400 bfd_put_32 (abfd, x, (bfd_byte *) data + reloc_entry->address);
401
402 if (relocation & ~ (bfd_vma) 0xffffff)
403 return bfd_reloc_overflow;
404
405 return bfd_reloc_ok;
406}
407\f
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
b34976b6 414static bfd_boolean
93fbbb04
GK
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
1049f94e 428 if (info->relocatable)
b34976b6 429 return TRUE;
93fbbb04
GK
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))
b34976b6 486 return FALSE;
93fbbb04
GK
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)
b34976b6 502 return FALSE;
93fbbb04 503 elf_local_got_offsets (abfd) = local_plt_offsets;
cedb70c5 504
93fbbb04
GK
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 {
eea6121a
AM
513 *offset = splt->size;
514 splt->size += 4;
93fbbb04
GK
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:
c152c796 521 if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
b34976b6 522 return FALSE;
93fbbb04 523 break;
cedb70c5 524
93fbbb04
GK
525 /* This relocation describes which C++ vtable entries are actually
526 used. Record for later use during GC. */
527 case R_XSTORMY16_GNU_VTENTRY:
c152c796 528 if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
b34976b6 529 return FALSE;
93fbbb04
GK
530 break;
531 }
532 }
533
b34976b6 534 return TRUE;
93fbbb04
GK
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;
b34976b6 543 bfd_boolean *again;
93fbbb04
GK
544};
545
b34976b6 546static bfd_boolean
93fbbb04
GK
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
e92d460e
AM
553 if (h->root.type == bfd_link_hash_warning)
554 h = (struct elf_link_hash_entry *) h->root.u.i.link;
555
93fbbb04
GK
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;
eea6121a 571 data->splt->size -= 4;
b34976b6 572 *data->again = TRUE;
93fbbb04
GK
573 }
574 }
575
b34976b6 576 return TRUE;
93fbbb04
GK
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
b34976b6 582static bfd_boolean
93fbbb04
GK
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
e92d460e
AM
589 if (h->root.type == bfd_link_hash_warning)
590 h = (struct elf_link_hash_entry *) h->root.u.i.link;
591
93fbbb04
GK
592 if (h->plt.offset != (bfd_vma) -1)
593 {
594 h->plt.offset = *entry;
595 *entry += 4;
596 }
597
b34976b6 598 return TRUE;
93fbbb04
GK
599}
600
b34976b6 601static bfd_boolean
93fbbb04
GK
602xstormy16_elf_relax_section (dynobj, splt, info, again)
603 bfd *dynobj;
604 asection *splt;
605 struct bfd_link_info *info;
b34976b6 606 bfd_boolean *again;
93fbbb04
GK
607{
608 struct relax_plt_data relax_plt_data;
609 bfd *ibfd;
610
611 /* Assume nothing changes. */
b34976b6 612 *again = FALSE;
93fbbb04 613
1049f94e 614 if (info->relocatable)
b34976b6 615 return TRUE;
93fbbb04
GK
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)
b34976b6 620 return TRUE;
93fbbb04
GK
621
622 /* Quick check for an empty plt. */
eea6121a 623 if (splt->size == 0)
b34976b6 624 return TRUE;
93fbbb04 625
cedb70c5 626 /* Map across all global symbols; see which ones happen to
93fbbb04
GK
627 fall in the low 64k. */
628 relax_plt_data.splt = splt;
629 relax_plt_data.again = again;
630 elf_link_hash_traverse (elf_hash_table (info), xstormy16_relax_plt_check,
631 &relax_plt_data);
632
633 /* Likewise for local symbols, though that's somewhat less convenient
6cdc0ccc 634 as we have to walk the list of input bfds and swap in symbol data. */
93fbbb04
GK
635 for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
636 {
637 bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
638 Elf_Internal_Shdr *symtab_hdr;
6cdc0ccc 639 Elf_Internal_Sym *isymbuf = NULL;
93fbbb04
GK
640 unsigned int idx;
641
642 if (! local_plt_offsets)
643 continue;
644
645 symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
6cdc0ccc 646 if (symtab_hdr->sh_info != 0)
93fbbb04 647 {
6cdc0ccc
AM
648 isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
649 if (isymbuf == NULL)
650 isymbuf = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
651 symtab_hdr->sh_info, 0,
652 NULL, NULL, NULL);
653 if (isymbuf == NULL)
b34976b6 654 return FALSE;
9ad5cbcf
AM
655 }
656
93fbbb04
GK
657 for (idx = 0; idx < symtab_hdr->sh_info; ++idx)
658 {
6cdc0ccc 659 Elf_Internal_Sym *isym;
93fbbb04
GK
660 asection *tsec;
661 bfd_vma address;
662
663 if (local_plt_offsets[idx] == (bfd_vma) -1)
664 continue;
665
6cdc0ccc
AM
666 isym = &isymbuf[idx];
667 if (isym->st_shndx == SHN_UNDEF)
93fbbb04 668 continue;
6cdc0ccc 669 else if (isym->st_shndx == SHN_ABS)
93fbbb04 670 tsec = bfd_abs_section_ptr;
6cdc0ccc 671 else if (isym->st_shndx == SHN_COMMON)
9ad5cbcf 672 tsec = bfd_com_section_ptr;
93fbbb04 673 else
6cdc0ccc 674 tsec = bfd_section_from_elf_index (ibfd, isym->st_shndx);
93fbbb04
GK
675
676 address = (tsec->output_section->vma
677 + tsec->output_offset
6cdc0ccc 678 + isym->st_value);
93fbbb04
GK
679 if (address <= 0xffff)
680 {
681 local_plt_offsets[idx] = -1;
eea6121a 682 splt->size -= 4;
b34976b6 683 *again = TRUE;
93fbbb04
GK
684 }
685 }
686
6cdc0ccc
AM
687 if (isymbuf != NULL
688 && symtab_hdr->contents != (unsigned char *) isymbuf)
689 {
690 if (! info->keep_memory)
691 free (isymbuf);
692 else
693 {
694 /* Cache the symbols for elf_link_input_bfd. */
695 symtab_hdr->contents = (unsigned char *) isymbuf;
696 }
697 }
93fbbb04
GK
698 }
699
700 /* If we changed anything, walk the symbols again to reallocate
701 .plt entry addresses. */
eea6121a 702 if (*again && splt->size > 0)
93fbbb04
GK
703 {
704 bfd_vma entry = 0;
705
706 elf_link_hash_traverse (elf_hash_table (info),
707 xstormy16_relax_plt_realloc, &entry);
708
709 for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
710 {
711 bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
712 unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info;
713 unsigned int idx;
714
715 if (! local_plt_offsets)
716 continue;
717
718 for (idx = 0; idx < nlocals; ++idx)
719 if (local_plt_offsets[idx] != (bfd_vma) -1)
720 {
721 local_plt_offsets[idx] = entry;
722 entry += 4;
723 }
724 }
725 }
726
b34976b6 727 return TRUE;
93fbbb04
GK
728}
729
b34976b6 730static bfd_boolean
93fbbb04
GK
731xstormy16_elf_always_size_sections (output_bfd, info)
732 bfd *output_bfd ATTRIBUTE_UNUSED;
733 struct bfd_link_info *info;
734{
735 bfd *dynobj;
736 asection *splt;
737
1049f94e 738 if (info->relocatable)
b34976b6 739 return TRUE;
93fbbb04
GK
740
741 dynobj = elf_hash_table (info)->dynobj;
742 if (dynobj == NULL)
b34976b6 743 return TRUE;
93fbbb04
GK
744
745 splt = bfd_get_section_by_name (dynobj, ".plt");
746 BFD_ASSERT (splt != NULL);
747
eea6121a 748 splt->contents = (bfd_byte *) bfd_zalloc (dynobj, splt->size);
93fbbb04 749 if (splt->contents == NULL)
b34976b6 750 return FALSE;
93fbbb04 751
b34976b6 752 return TRUE;
93fbbb04
GK
753}
754\f
755/* Relocate an XSTORMY16 ELF section.
93fbbb04
GK
756
757 The RELOCATE_SECTION function is called by the new ELF backend linker
758 to handle the relocations for a section.
759
760 The relocs are always passed as Rela structures; if the section
761 actually uses Rel structures, the r_addend field will always be
762 zero.
763
764 This function is responsible for adjusting the section contents as
1049f94e 765 necessary, and (if using Rela relocs and generating a relocatable
93fbbb04
GK
766 output file) adjusting the reloc addend as necessary.
767
768 This function does not have to worry about setting the reloc
769 address or the reloc symbol index.
770
771 LOCAL_SYMS is a pointer to the swapped in local symbols.
772
773 LOCAL_SECTIONS is an array giving the section in the input file
774 corresponding to the st_shndx field of each local symbol.
775
776 The global hash table entry for the global symbols can be found
777 via elf_sym_hashes (input_bfd).
778
1049f94e 779 When generating relocatable output, this function must handle
93fbbb04
GK
780 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
781 going to be the section symbol corresponding to the output
782 section, which means that the addend must be adjusted
783 accordingly. */
784
b34976b6 785static bfd_boolean
93fbbb04
GK
786xstormy16_elf_relocate_section (output_bfd, info, input_bfd, input_section,
787 contents, relocs, local_syms, local_sections)
788 bfd * output_bfd ATTRIBUTE_UNUSED;
789 struct bfd_link_info * info;
790 bfd * input_bfd;
791 asection * input_section;
792 bfd_byte * contents;
793 Elf_Internal_Rela * relocs;
794 Elf_Internal_Sym * local_syms;
795 asection ** local_sections;
796{
797 Elf_Internal_Shdr * symtab_hdr;
798 struct elf_link_hash_entry ** sym_hashes;
799 Elf_Internal_Rela * rel;
800 Elf_Internal_Rela * relend;
801 bfd *dynobj;
802 asection *splt;
803
1049f94e 804 if (info->relocatable)
b34976b6 805 return TRUE;
b491616a 806
93fbbb04
GK
807 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
808 sym_hashes = elf_sym_hashes (input_bfd);
809 relend = relocs + input_section->reloc_count;
810
811 dynobj = elf_hash_table (info)->dynobj;
812 splt = NULL;
813 if (dynobj != NULL)
814 splt = bfd_get_section_by_name (dynobj, ".plt");
815
816 for (rel = relocs; rel < relend; rel ++)
817 {
818 reloc_howto_type * howto;
819 unsigned long r_symndx;
820 Elf_Internal_Sym * sym;
821 asection * sec;
822 struct elf_link_hash_entry * h;
823 bfd_vma relocation;
824 bfd_reloc_status_type r;
825 const char * name = NULL;
826 int r_type;
cedb70c5 827
93fbbb04 828 r_type = ELF32_R_TYPE (rel->r_info);
cedb70c5 829
93fbbb04
GK
830 if ( r_type == R_XSTORMY16_GNU_VTINHERIT
831 || r_type == R_XSTORMY16_GNU_VTENTRY)
832 continue;
cedb70c5 833
93fbbb04 834 r_symndx = ELF32_R_SYM (rel->r_info);
93fbbb04
GK
835 howto = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info);
836 h = NULL;
837 sym = NULL;
838 sec = NULL;
cedb70c5 839
93fbbb04
GK
840 if (r_symndx < symtab_hdr->sh_info)
841 {
842 sym = local_syms + r_symndx;
843 sec = local_sections [r_symndx];
8517fae7 844 relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
cedb70c5 845
93fbbb04
GK
846 name = bfd_elf_string_from_elf_section
847 (input_bfd, symtab_hdr->sh_link, sym->st_name);
848 name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
849 }
850 else
851 {
59c2e50f 852 bfd_boolean unresolved_reloc, warned;
cedb70c5 853
b2a8e766
AM
854 RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
855 r_symndx, symtab_hdr, sym_hashes,
856 h, sec, relocation,
857 unresolved_reloc, warned);
93fbbb04 858 }
cedb70c5 859
93fbbb04
GK
860 switch (ELF32_R_TYPE (rel->r_info))
861 {
862 case R_XSTORMY16_24:
863 {
864 bfd_vma reloc = relocation + rel->r_addend;
865 unsigned int x;
cedb70c5 866
93fbbb04
GK
867 x = bfd_get_32 (input_bfd, contents + rel->r_offset);
868 x &= 0x0000ff00;
869 x |= reloc & 0xff;
870 x |= (reloc << 8) & 0xffff0000;
871 bfd_put_32 (input_bfd, x, contents + rel->r_offset);
872
873 if (reloc & ~0xffffff)
874 r = bfd_reloc_overflow;
875 else
876 r = bfd_reloc_ok;
877 break;
878 }
879
880 case R_XSTORMY16_FPTR16:
881 {
882 bfd_vma *plt_offset;
883
884 if (h != NULL)
885 plt_offset = &h->plt.offset;
886 else
887 plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
888
889 if (relocation <= 0xffff)
890 {
891 /* If the symbol is in range for a 16-bit address, we should
892 have deallocated the plt entry in relax_section. */
893 BFD_ASSERT (*plt_offset == (bfd_vma) -1);
894 }
895 else
896 {
897 /* If the symbol is out of range for a 16-bit address,
898 we must have allocated a plt entry. */
899 BFD_ASSERT (*plt_offset != (bfd_vma) -1);
900
901 /* If this is the first time we've processed this symbol,
902 fill in the plt entry with the correct symbol address. */
903 if ((*plt_offset & 1) == 0)
904 {
905 unsigned int x;
906
907 x = 0x00000200; /* jmpf */
908 x |= relocation & 0xff;
909 x |= (relocation << 8) & 0xffff0000;
910 bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
911 *plt_offset |= 1;
912 }
913
914 relocation = (splt->output_section->vma
915 + splt->output_offset
916 + (*plt_offset & -2));
917 }
918 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
919 contents, rel->r_offset,
920 relocation, 0);
921 break;
922 }
923
924 default:
925 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
926 contents, rel->r_offset,
927 relocation, rel->r_addend);
928 break;
929 }
930
931 if (r != bfd_reloc_ok)
932 {
933 const char * msg = (const char *) NULL;
934
935 switch (r)
936 {
937 case bfd_reloc_overflow:
938 r = info->callbacks->reloc_overflow
939 (info, name, howto->name, (bfd_vma) 0,
940 input_bfd, input_section, rel->r_offset);
941 break;
cedb70c5 942
93fbbb04
GK
943 case bfd_reloc_undefined:
944 r = info->callbacks->undefined_symbol
945 (info, name, input_bfd, input_section, rel->r_offset,
b34976b6 946 TRUE);
93fbbb04 947 break;
cedb70c5 948
93fbbb04
GK
949 case bfd_reloc_outofrange:
950 msg = _("internal error: out of range error");
951 break;
952
953 case bfd_reloc_notsupported:
954 msg = _("internal error: unsupported relocation error");
955 break;
956
957 case bfd_reloc_dangerous:
958 msg = _("internal error: dangerous relocation");
959 break;
960
961 default:
962 msg = _("internal error: unknown error");
963 break;
964 }
965
966 if (msg)
967 r = info->callbacks->warning
968 (info, msg, name, input_bfd, input_section, rel->r_offset);
969
970 if (! r)
b34976b6 971 return FALSE;
93fbbb04
GK
972 }
973 }
974
b34976b6 975 return TRUE;
93fbbb04
GK
976}
977
978/* This must exist if dynobj is ever set. */
979
b34976b6 980static bfd_boolean
93fbbb04
GK
981xstormy16_elf_finish_dynamic_sections (abfd, info)
982 bfd *abfd ATTRIBUTE_UNUSED;
983 struct bfd_link_info *info;
984{
985 bfd *dynobj;
986 asection *splt;
987
988 /* As an extra sanity check, verify that all plt entries have
989 been filled in. */
990
991 if ((dynobj = elf_hash_table (info)->dynobj) != NULL
992 && (splt = bfd_get_section_by_name (dynobj, ".plt")) != NULL)
993 {
994 bfd_byte *contents = splt->contents;
eea6121a 995 unsigned int i, size = splt->size;
93fbbb04
GK
996 for (i = 0; i < size; i += 4)
997 {
998 unsigned int x = bfd_get_32 (dynobj, contents + i);
999 BFD_ASSERT (x != 0);
1000 }
1001 }
1002
b34976b6 1003 return TRUE;
93fbbb04
GK
1004}
1005\f
1006/* Return the section that should be marked against GC for a given
1007 relocation. */
1008
1009static asection *
1e2f5b6e
AM
1010xstormy16_elf_gc_mark_hook (sec, info, rel, h, sym)
1011 asection * sec;
93fbbb04
GK
1012 struct bfd_link_info * info ATTRIBUTE_UNUSED;
1013 Elf_Internal_Rela * rel;
1014 struct elf_link_hash_entry * h;
1015 Elf_Internal_Sym * sym;
1016{
1017 if (h != NULL)
1018 {
1019 switch (ELF32_R_TYPE (rel->r_info))
1020 {
1021 case R_XSTORMY16_GNU_VTINHERIT:
1022 case R_XSTORMY16_GNU_VTENTRY:
1023 break;
1024
1025 default:
1026 switch (h->root.type)
1027 {
1028 case bfd_link_hash_defined:
1029 case bfd_link_hash_defweak:
1030 return h->root.u.def.section;
1031
1032 case bfd_link_hash_common:
1033 return h->root.u.c.p->section;
1034
1035 default:
1036 break;
1037 }
1038 }
1039 }
1040 else
1e2f5b6e 1041 return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
93fbbb04
GK
1042
1043 return NULL;
1044}
1045
1046/* Update the got entry reference counts for the section being removed. */
1047
b34976b6 1048static bfd_boolean
93fbbb04
GK
1049xstormy16_elf_gc_sweep_hook (abfd, info, sec, relocs)
1050 bfd * abfd ATTRIBUTE_UNUSED;
1051 struct bfd_link_info * info ATTRIBUTE_UNUSED;
1052 asection * sec ATTRIBUTE_UNUSED;
1053 const Elf_Internal_Rela * relocs ATTRIBUTE_UNUSED;
1054{
b34976b6 1055 return TRUE;
93fbbb04
GK
1056}
1057\f
1058#define ELF_ARCH bfd_arch_xstormy16
1059#define ELF_MACHINE_CODE EM_XSTORMY16
1060#define ELF_MAXPAGESIZE 0x100
1061
1062#define TARGET_LITTLE_SYM bfd_elf32_xstormy16_vec
1063#define TARGET_LITTLE_NAME "elf32-xstormy16"
1064
1065#define elf_info_to_howto_rel NULL
1066#define elf_info_to_howto xstormy16_info_to_howto_rela
1067#define elf_backend_relocate_section xstormy16_elf_relocate_section
1068#define elf_backend_gc_mark_hook xstormy16_elf_gc_mark_hook
1069#define elf_backend_gc_sweep_hook xstormy16_elf_gc_sweep_hook
1070#define elf_backend_check_relocs xstormy16_elf_check_relocs
1071#define elf_backend_always_size_sections \
1072 xstormy16_elf_always_size_sections
1073#define elf_backend_finish_dynamic_sections \
1074 xstormy16_elf_finish_dynamic_sections
1075
1076#define elf_backend_can_gc_sections 1
b491616a 1077#define elf_backend_rela_normal 1
93fbbb04
GK
1078
1079#define bfd_elf32_bfd_reloc_type_lookup xstormy16_reloc_type_lookup
1080#define bfd_elf32_bfd_relax_section xstormy16_elf_relax_section
1081
1082#include "elf32-target.h"
This page took 0.207479 seconds and 4 git commands to generate.