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