xref: /openbsd/gnu/usr.bin/binutils/bfd/elf32-sh64.c (revision cf2f2c56)
1d2201f2fSdrahn /* SuperH SH64-specific support for 32-bit ELF
2*cf2f2c56Smiod    Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
3d2201f2fSdrahn 
4d2201f2fSdrahn    This file is part of BFD, the Binary File Descriptor library.
5d2201f2fSdrahn 
6d2201f2fSdrahn    This program is free software; you can redistribute it and/or modify
7d2201f2fSdrahn    it under the terms of the GNU General Public License as published by
8d2201f2fSdrahn    the Free Software Foundation; either version 2 of the License, or
9d2201f2fSdrahn    (at your option) any later version.
10d2201f2fSdrahn 
11d2201f2fSdrahn    This program is distributed in the hope that it will be useful,
12d2201f2fSdrahn    but WITHOUT ANY WARRANTY; without even the implied warranty of
13d2201f2fSdrahn    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14d2201f2fSdrahn    GNU General Public License for more details.
15d2201f2fSdrahn 
16d2201f2fSdrahn    You should have received a copy of the GNU General Public License
17d2201f2fSdrahn    along with this program; if not, write to the Free Software
18d2201f2fSdrahn    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19d2201f2fSdrahn 
20d2201f2fSdrahn #define SH64_ELF
21d2201f2fSdrahn 
22d2201f2fSdrahn #include "bfd.h"
23d2201f2fSdrahn #include "sysdep.h"
24d2201f2fSdrahn #include "elf-bfd.h"
25d2201f2fSdrahn #include "../opcodes/sh64-opc.h"
26d2201f2fSdrahn #include "elf32-sh64.h"
27d2201f2fSdrahn 
28d2201f2fSdrahn /* Add a suffix for datalabel indirection symbols.  It must not match any
29d2201f2fSdrahn    other symbols; user symbols with or without version or other
30d2201f2fSdrahn    decoration.  It must only be used internally and not emitted by any
31d2201f2fSdrahn    means.  */
32d2201f2fSdrahn #define DATALABEL_SUFFIX " DL"
33d2201f2fSdrahn 
34d2201f2fSdrahn /* Used to hold data for function called through bfd_map_over_sections.  */
35d2201f2fSdrahn struct sh64_find_section_vma_data
36d2201f2fSdrahn  {
37d2201f2fSdrahn    asection *section;
38d2201f2fSdrahn    bfd_vma addr;
39d2201f2fSdrahn  };
40d2201f2fSdrahn 
41d2201f2fSdrahn static bfd_boolean sh64_elf_new_section_hook
42*cf2f2c56Smiod   (bfd *, asection *);
43d2201f2fSdrahn static bfd_boolean sh64_elf_copy_private_data
44*cf2f2c56Smiod   (bfd *, bfd *);
45d2201f2fSdrahn static bfd_boolean sh64_elf_merge_private_data
46*cf2f2c56Smiod   (bfd *, bfd *);
47d2201f2fSdrahn static bfd_boolean sh64_elf_fake_sections
48*cf2f2c56Smiod   (bfd *, Elf_Internal_Shdr *, asection *);
49d2201f2fSdrahn static bfd_boolean sh64_elf_set_private_flags
50*cf2f2c56Smiod   (bfd *, flagword);
51d2201f2fSdrahn static bfd_boolean sh64_elf_set_mach_from_flags
52*cf2f2c56Smiod   (bfd *);
53d2201f2fSdrahn static bfd_boolean shmedia_prepare_reloc
54*cf2f2c56Smiod   (struct bfd_link_info *, bfd *, asection *, bfd_byte *,
55*cf2f2c56Smiod    const Elf_Internal_Rela *, bfd_vma *);
56d2201f2fSdrahn static int sh64_elf_get_symbol_type
57*cf2f2c56Smiod   (Elf_Internal_Sym *, int);
58d2201f2fSdrahn static bfd_boolean sh64_elf_add_symbol_hook
59*cf2f2c56Smiod   (bfd *, struct bfd_link_info *, Elf_Internal_Sym *, const char **,
60*cf2f2c56Smiod    flagword *, asection **, bfd_vma *);
61d2201f2fSdrahn static bfd_boolean sh64_elf_link_output_symbol_hook
62*cf2f2c56Smiod   (struct bfd_link_info *, const char *, Elf_Internal_Sym *, asection *,
63*cf2f2c56Smiod    struct elf_link_hash_entry *);
64d2201f2fSdrahn static bfd_boolean sh64_backend_section_from_shdr
65*cf2f2c56Smiod   (bfd *, Elf_Internal_Shdr *, const char *);
66d2201f2fSdrahn static void sh64_elf_final_write_processing
67*cf2f2c56Smiod   (bfd *, bfd_boolean);
68d2201f2fSdrahn static bfd_boolean sh64_bfd_elf_copy_private_section_data
69*cf2f2c56Smiod   (bfd *, asection *, bfd *, asection *);
70d2201f2fSdrahn static void sh64_find_section_for_address
71*cf2f2c56Smiod   (bfd *, asection *, void *);
72d2201f2fSdrahn 
73d2201f2fSdrahn /* Let elf32-sh.c handle the "bfd_" definitions, so we only have to
74d2201f2fSdrahn    intrude with an #ifndef around the function definition.  */
75d2201f2fSdrahn #define sh_elf_copy_private_data		sh64_elf_copy_private_data
76d2201f2fSdrahn #define sh_elf_merge_private_data		sh64_elf_merge_private_data
77d2201f2fSdrahn #define sh_elf_set_private_flags		sh64_elf_set_private_flags
78d2201f2fSdrahn /* Typo in elf32-sh.c (and unlinear name).  */
79d2201f2fSdrahn #define bfd_elf32_bfd_set_private_flags		sh64_elf_set_private_flags
80d2201f2fSdrahn #define sh_elf_set_mach_from_flags		sh64_elf_set_mach_from_flags
81d2201f2fSdrahn 
82d2201f2fSdrahn #define elf_backend_sign_extend_vma		1
83d2201f2fSdrahn #define elf_backend_fake_sections		sh64_elf_fake_sections
84d2201f2fSdrahn #define elf_backend_get_symbol_type		sh64_elf_get_symbol_type
85d2201f2fSdrahn #define elf_backend_add_symbol_hook		sh64_elf_add_symbol_hook
86d2201f2fSdrahn #define elf_backend_link_output_symbol_hook \
87d2201f2fSdrahn 	sh64_elf_link_output_symbol_hook
88*cf2f2c56Smiod #define elf_backend_merge_symbol_attribute	sh64_elf_merge_symbol_attribute
89d2201f2fSdrahn #define elf_backend_final_write_processing 	sh64_elf_final_write_processing
90d2201f2fSdrahn #define elf_backend_section_from_shdr		sh64_backend_section_from_shdr
91*cf2f2c56Smiod #define elf_backend_special_sections		sh64_elf_special_sections
92d2201f2fSdrahn 
93d2201f2fSdrahn #define bfd_elf32_new_section_hook		sh64_elf_new_section_hook
94d2201f2fSdrahn 
95d2201f2fSdrahn /* For objcopy, we need to set up sh64_elf_section_data (asection *) from
96d2201f2fSdrahn    incoming section flags.  This is otherwise done in sh64elf.em when
97d2201f2fSdrahn    linking or tc-sh64.c when assembling.  */
98d2201f2fSdrahn #define bfd_elf32_bfd_copy_private_section_data \
99d2201f2fSdrahn 	sh64_bfd_elf_copy_private_section_data
100d2201f2fSdrahn 
101d2201f2fSdrahn /* This COFF-only function (only compiled with COFF support, making
102d2201f2fSdrahn    ELF-only chains problematic) returns TRUE early for SH4, so let's just
103d2201f2fSdrahn    define it TRUE here.  */
104d2201f2fSdrahn #define _bfd_sh_align_load_span(a,b,c,d,e,f,g,h,i,j) TRUE
105d2201f2fSdrahn 
106d2201f2fSdrahn #define GOT_BIAS (-((long)-32768))
107d2201f2fSdrahn #define INCLUDE_SHMEDIA
108d2201f2fSdrahn #include "elf32-sh.c"
109d2201f2fSdrahn 
110d2201f2fSdrahn /* Tack some extra info on struct bfd_elf_section_data.  */
111d2201f2fSdrahn 
112d2201f2fSdrahn static bfd_boolean
sh64_elf_new_section_hook(bfd * abfd,asection * sec)113*cf2f2c56Smiod sh64_elf_new_section_hook (bfd *abfd, asection *sec)
114d2201f2fSdrahn {
115d2201f2fSdrahn   struct _sh64_elf_section_data *sdata;
116d2201f2fSdrahn   bfd_size_type amt = sizeof (*sdata);
117d2201f2fSdrahn 
118d2201f2fSdrahn   sdata = (struct _sh64_elf_section_data *) bfd_zalloc (abfd, amt);
119d2201f2fSdrahn   if (sdata == NULL)
120d2201f2fSdrahn     return FALSE;
121*cf2f2c56Smiod   sec->used_by_bfd = sdata;
122d2201f2fSdrahn 
123d2201f2fSdrahn   return _bfd_elf_new_section_hook (abfd, sec);
124d2201f2fSdrahn }
125d2201f2fSdrahn 
126d2201f2fSdrahn /* Set the SHF_SH5_ISA32 flag for ISA SHmedia code sections, and pass
127d2201f2fSdrahn    through SHT_SH5_CR_SORTED on a sorted .cranges section.  */
128d2201f2fSdrahn 
129d2201f2fSdrahn bfd_boolean
sh64_elf_fake_sections(bfd * output_bfd ATTRIBUTE_UNUSED,Elf_Internal_Shdr * elf_section_hdr,asection * asect)130*cf2f2c56Smiod sh64_elf_fake_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
131*cf2f2c56Smiod 			Elf_Internal_Shdr *elf_section_hdr,
132*cf2f2c56Smiod 			asection *asect)
133d2201f2fSdrahn {
134d2201f2fSdrahn   if (sh64_elf_section_data (asect)->sh64_info != NULL)
135d2201f2fSdrahn     elf_section_hdr->sh_flags
136d2201f2fSdrahn       |= sh64_elf_section_data (asect)->sh64_info->contents_flags;
137d2201f2fSdrahn 
138d2201f2fSdrahn   /* If this section has the SEC_SORT_ENTRIES flag set, it is a sorted
139d2201f2fSdrahn      .cranges section passing through objcopy.  */
140d2201f2fSdrahn   if ((bfd_get_section_flags (output_bfd, asect) & SEC_SORT_ENTRIES) != 0
141d2201f2fSdrahn       && strcmp (bfd_get_section_name (output_bfd, asect),
142d2201f2fSdrahn 		 SH64_CRANGES_SECTION_NAME) == 0)
143d2201f2fSdrahn     elf_section_hdr->sh_type = SHT_SH5_CR_SORTED;
144d2201f2fSdrahn 
145d2201f2fSdrahn   return TRUE;
146d2201f2fSdrahn }
147d2201f2fSdrahn 
148d2201f2fSdrahn static bfd_boolean
sh64_elf_set_mach_from_flags(bfd * abfd)149*cf2f2c56Smiod sh64_elf_set_mach_from_flags (bfd *abfd)
150d2201f2fSdrahn {
151d2201f2fSdrahn   flagword flags = elf_elfheader (abfd)->e_flags;
152d2201f2fSdrahn   asection *cranges;
153d2201f2fSdrahn 
154d2201f2fSdrahn   switch (flags & EF_SH_MACH_MASK)
155d2201f2fSdrahn     {
156d2201f2fSdrahn     case EF_SH5:
157d2201f2fSdrahn       /* These are fit to execute on SH5.  Just one but keep the switch
158d2201f2fSdrahn 	 construct to make additions easy.  */
159d2201f2fSdrahn       bfd_default_set_arch_mach (abfd, bfd_arch_sh, bfd_mach_sh5);
160d2201f2fSdrahn       break;
161d2201f2fSdrahn 
162d2201f2fSdrahn     default:
163d2201f2fSdrahn       bfd_set_error (bfd_error_wrong_format);
164d2201f2fSdrahn       return FALSE;
165d2201f2fSdrahn     }
166d2201f2fSdrahn 
167d2201f2fSdrahn   /* We also need to set SEC_DEBUGGING on an incoming .cranges section.
168d2201f2fSdrahn      We could have used elf_backend_section_flags if it had given us the
169d2201f2fSdrahn      section name; the bfd_section member in the header argument is not
170d2201f2fSdrahn      set at the point of the call.  FIXME: Find out whether that is by
171d2201f2fSdrahn      undocumented design or a bug.  */
172d2201f2fSdrahn   cranges = bfd_get_section_by_name (abfd, SH64_CRANGES_SECTION_NAME);
173d2201f2fSdrahn   if (cranges != NULL
174d2201f2fSdrahn       && ! bfd_set_section_flags (abfd, cranges,
175d2201f2fSdrahn 				  bfd_get_section_flags (abfd, cranges)
176d2201f2fSdrahn 				  | SEC_DEBUGGING))
177d2201f2fSdrahn     return FALSE;
178d2201f2fSdrahn 
179d2201f2fSdrahn   return TRUE;
180d2201f2fSdrahn }
181d2201f2fSdrahn 
182d2201f2fSdrahn static bfd_boolean
sh64_elf_copy_private_data(bfd * ibfd,bfd * obfd)183*cf2f2c56Smiod sh64_elf_copy_private_data (bfd * ibfd, bfd * obfd)
184d2201f2fSdrahn {
185d2201f2fSdrahn   if (   bfd_get_flavour (ibfd) != bfd_target_elf_flavour
186d2201f2fSdrahn       || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
187d2201f2fSdrahn     return TRUE;
188d2201f2fSdrahn 
189d2201f2fSdrahn   BFD_ASSERT (!elf_flags_init (obfd)
190d2201f2fSdrahn 	      || (elf_elfheader (obfd)->e_flags
191d2201f2fSdrahn 		  == elf_elfheader (ibfd)->e_flags));
192d2201f2fSdrahn 
193d2201f2fSdrahn   elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
194d2201f2fSdrahn   return TRUE;
195d2201f2fSdrahn }
196d2201f2fSdrahn 
197d2201f2fSdrahn static bfd_boolean
sh64_elf_merge_private_data(bfd * ibfd,bfd * obfd)198*cf2f2c56Smiod sh64_elf_merge_private_data (bfd *ibfd, bfd *obfd)
199d2201f2fSdrahn {
200d2201f2fSdrahn   flagword old_flags, new_flags;
201d2201f2fSdrahn 
202d2201f2fSdrahn   if (! _bfd_generic_verify_endian_match (ibfd, obfd))
203d2201f2fSdrahn     return FALSE;
204d2201f2fSdrahn 
205d2201f2fSdrahn   if (   bfd_get_flavour (ibfd) != bfd_target_elf_flavour
206d2201f2fSdrahn       || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
207d2201f2fSdrahn     return TRUE;
208d2201f2fSdrahn 
209d2201f2fSdrahn   if (bfd_get_arch_size (ibfd) != bfd_get_arch_size (obfd))
210d2201f2fSdrahn     {
211d2201f2fSdrahn       const char *msg;
212d2201f2fSdrahn 
213d2201f2fSdrahn       if (bfd_get_arch_size (ibfd) == 32
214d2201f2fSdrahn 	  && bfd_get_arch_size (obfd) == 64)
215d2201f2fSdrahn 	msg = _("%s: compiled as 32-bit object and %s is 64-bit");
216d2201f2fSdrahn       else if (bfd_get_arch_size (ibfd) == 64
217d2201f2fSdrahn 	       && bfd_get_arch_size (obfd) == 32)
218d2201f2fSdrahn 	msg = _("%s: compiled as 64-bit object and %s is 32-bit");
219d2201f2fSdrahn       else
220d2201f2fSdrahn 	msg = _("%s: object size does not match that of target %s");
221d2201f2fSdrahn 
222d2201f2fSdrahn       (*_bfd_error_handler) (msg, bfd_get_filename (ibfd),
223d2201f2fSdrahn 			     bfd_get_filename (obfd));
224d2201f2fSdrahn       bfd_set_error (bfd_error_wrong_format);
225d2201f2fSdrahn       return FALSE;
226d2201f2fSdrahn     }
227d2201f2fSdrahn 
228d2201f2fSdrahn   old_flags = elf_elfheader (obfd)->e_flags;
229d2201f2fSdrahn   new_flags = elf_elfheader (ibfd)->e_flags;
230d2201f2fSdrahn   if (! elf_flags_init (obfd))
231d2201f2fSdrahn     {
232d2201f2fSdrahn       /* This happens when ld starts out with a 'blank' output file.  */
233d2201f2fSdrahn       elf_flags_init (obfd) = TRUE;
234d2201f2fSdrahn       elf_elfheader (obfd)->e_flags = old_flags = new_flags;
235d2201f2fSdrahn     }
236d2201f2fSdrahn   /* We don't allow linking in non-SH64 code.  */
237d2201f2fSdrahn   else if ((new_flags & EF_SH_MACH_MASK) != EF_SH5)
238d2201f2fSdrahn     {
239d2201f2fSdrahn       (*_bfd_error_handler)
240d2201f2fSdrahn 	("%s: uses non-SH64 instructions while previous modules use SH64 instructions",
241d2201f2fSdrahn 	 bfd_get_filename (ibfd));
242d2201f2fSdrahn       bfd_set_error (bfd_error_bad_value);
243d2201f2fSdrahn       return FALSE;
244d2201f2fSdrahn     }
245d2201f2fSdrahn 
246d2201f2fSdrahn   /* I can't think of anything sane other than old_flags being EF_SH5 and
247d2201f2fSdrahn      that we need to preserve that.  */
248d2201f2fSdrahn   elf_elfheader (obfd)->e_flags = old_flags;
249d2201f2fSdrahn   return sh64_elf_set_mach_from_flags (obfd);
250d2201f2fSdrahn }
251d2201f2fSdrahn 
252d2201f2fSdrahn /* Handle a SH64-specific section when reading an object file.  This
253d2201f2fSdrahn    is called when elfcode.h finds a section with an unknown type.
254d2201f2fSdrahn 
255d2201f2fSdrahn    We only recognize SHT_SH5_CR_SORTED, on the .cranges section.  */
256d2201f2fSdrahn 
257d2201f2fSdrahn bfd_boolean
sh64_backend_section_from_shdr(bfd * abfd,Elf_Internal_Shdr * hdr,const char * name)258*cf2f2c56Smiod sh64_backend_section_from_shdr (bfd *abfd, Elf_Internal_Shdr *hdr,
259*cf2f2c56Smiod 				const char *name)
260d2201f2fSdrahn {
261d2201f2fSdrahn   flagword flags = 0;
262d2201f2fSdrahn 
263d2201f2fSdrahn   /* We do like MIPS with a bit switch for recognized types, and returning
264d2201f2fSdrahn      FALSE for a recognized section type with an unexpected name.  Right
265d2201f2fSdrahn      now we only have one recognized type, but that might change.  */
266d2201f2fSdrahn   switch (hdr->sh_type)
267d2201f2fSdrahn     {
268d2201f2fSdrahn     case SHT_SH5_CR_SORTED:
269d2201f2fSdrahn       if (strcmp (name, SH64_CRANGES_SECTION_NAME) != 0)
270d2201f2fSdrahn 	return FALSE;
271d2201f2fSdrahn 
272d2201f2fSdrahn       /* We set the SEC_SORT_ENTRIES flag so it can be passed on to
273d2201f2fSdrahn 	 sh64_elf_fake_sections, keeping SHT_SH5_CR_SORTED if this object
274d2201f2fSdrahn 	 passes through objcopy.  Perhaps it is brittle; the flag can
275d2201f2fSdrahn 	 suddenly be used by other BFD parts, but it seems not really used
276d2201f2fSdrahn 	 anywhere at the moment.  */
277d2201f2fSdrahn       flags = SEC_DEBUGGING | SEC_SORT_ENTRIES;
278d2201f2fSdrahn       break;
279d2201f2fSdrahn 
280d2201f2fSdrahn     default:
281d2201f2fSdrahn       return FALSE;
282d2201f2fSdrahn     }
283d2201f2fSdrahn 
284d2201f2fSdrahn   if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name))
285d2201f2fSdrahn     return FALSE;
286d2201f2fSdrahn 
287d2201f2fSdrahn   if (flags
288d2201f2fSdrahn       && ! bfd_set_section_flags (abfd, hdr->bfd_section,
289d2201f2fSdrahn 				  bfd_get_section_flags (abfd,
290d2201f2fSdrahn 							 hdr->bfd_section)
291d2201f2fSdrahn 				  | flags))
292d2201f2fSdrahn     return FALSE;
293d2201f2fSdrahn 
294d2201f2fSdrahn   return TRUE;
295d2201f2fSdrahn }
296d2201f2fSdrahn 
297d2201f2fSdrahn /* In contrast to sh64_backend_section_from_shdr, this is called for all
298d2201f2fSdrahn    sections, but only when copying sections, not when linking or
299d2201f2fSdrahn    assembling.  We need to set up the sh64_elf_section_data (asection *)
300d2201f2fSdrahn    structure for the SH64 ELF section flags to be copied correctly.  */
301d2201f2fSdrahn 
302d2201f2fSdrahn bfd_boolean
sh64_bfd_elf_copy_private_section_data(bfd * ibfd,asection * isec,bfd * obfd,asection * osec)303*cf2f2c56Smiod sh64_bfd_elf_copy_private_section_data (bfd *ibfd, asection *isec,
304*cf2f2c56Smiod 					bfd *obfd, asection *osec)
305d2201f2fSdrahn {
306d2201f2fSdrahn   struct sh64_section_data *sh64_sec_data;
307d2201f2fSdrahn 
308d2201f2fSdrahn   if (ibfd->xvec->flavour != bfd_target_elf_flavour
309d2201f2fSdrahn       || obfd->xvec->flavour != bfd_target_elf_flavour)
310d2201f2fSdrahn     return TRUE;
311d2201f2fSdrahn 
312d2201f2fSdrahn   if (! _bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec))
313d2201f2fSdrahn     return FALSE;
314d2201f2fSdrahn 
315d2201f2fSdrahn   sh64_sec_data = sh64_elf_section_data (isec)->sh64_info;
316d2201f2fSdrahn   if (sh64_sec_data == NULL)
317d2201f2fSdrahn     {
318d2201f2fSdrahn       sh64_sec_data = bfd_zmalloc (sizeof (struct sh64_section_data));
319d2201f2fSdrahn 
320d2201f2fSdrahn       if (sh64_sec_data == NULL)
321d2201f2fSdrahn 	return FALSE;
322d2201f2fSdrahn 
323d2201f2fSdrahn       sh64_sec_data->contents_flags
324d2201f2fSdrahn 	= (elf_section_data (isec)->this_hdr.sh_flags
325d2201f2fSdrahn 	   & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED));
326d2201f2fSdrahn 
327d2201f2fSdrahn       sh64_elf_section_data (osec)->sh64_info = sh64_sec_data;
328d2201f2fSdrahn     }
329d2201f2fSdrahn 
330d2201f2fSdrahn   return TRUE;
331d2201f2fSdrahn }
332d2201f2fSdrahn 
333d2201f2fSdrahn /* Function to keep SH64 specific file flags.  */
334d2201f2fSdrahn 
335d2201f2fSdrahn static bfd_boolean
sh64_elf_set_private_flags(bfd * abfd,flagword flags)336*cf2f2c56Smiod sh64_elf_set_private_flags (bfd *abfd, flagword flags)
337d2201f2fSdrahn {
338d2201f2fSdrahn   BFD_ASSERT (! elf_flags_init (abfd)
339d2201f2fSdrahn 	      || elf_elfheader (abfd)->e_flags == flags);
340d2201f2fSdrahn 
341d2201f2fSdrahn   elf_elfheader (abfd)->e_flags = flags;
342d2201f2fSdrahn   elf_flags_init (abfd) = TRUE;
343d2201f2fSdrahn   return sh64_elf_set_mach_from_flags (abfd);
344d2201f2fSdrahn }
345d2201f2fSdrahn 
346d2201f2fSdrahn /* Called when writing out an object file to decide the type of a symbol.  */
347d2201f2fSdrahn 
348d2201f2fSdrahn static int
sh64_elf_get_symbol_type(Elf_Internal_Sym * elf_sym,int type)349*cf2f2c56Smiod sh64_elf_get_symbol_type (Elf_Internal_Sym *elf_sym, int type)
350d2201f2fSdrahn {
351d2201f2fSdrahn   if (ELF_ST_TYPE (elf_sym->st_info) == STT_DATALABEL)
352d2201f2fSdrahn     return STT_DATALABEL;
353d2201f2fSdrahn 
354d2201f2fSdrahn   return type;
355d2201f2fSdrahn }
356d2201f2fSdrahn 
357d2201f2fSdrahn /* Hook called by the linker routine which adds symbols from an object
358d2201f2fSdrahn    file.  We must make indirect symbols for undefined symbols marked with
359d2201f2fSdrahn    STT_DATALABEL, so relocations passing them will pick up that attribute
360d2201f2fSdrahn    and neutralize STO_SH5_ISA32 found on the symbol definition.
361d2201f2fSdrahn 
362d2201f2fSdrahn    There is a problem, though: We want to fill in the hash-table entry for
363d2201f2fSdrahn    this symbol and signal to the caller that no further processing is
364d2201f2fSdrahn    needed.  But we don't have the index for this hash-table entry.  We
365d2201f2fSdrahn    rely here on that the current entry is the first hash-entry with NULL,
366d2201f2fSdrahn    which seems brittle.  Also, iterating over the hash-table to find that
367d2201f2fSdrahn    entry is a linear operation on the number of symbols in this input
368d2201f2fSdrahn    file, and this function should take constant time, so that's not good
369d2201f2fSdrahn    too.  Only comfort is that DataLabel references should only be found in
370d2201f2fSdrahn    hand-written assembly code and thus be rare.  FIXME: Talk maintainers
371d2201f2fSdrahn    into adding an option to elf_add_symbol_hook (preferably) for the index
372d2201f2fSdrahn    or the hash entry, alternatively adding the index to Elf_Internal_Sym
373d2201f2fSdrahn    (not so good).  */
374d2201f2fSdrahn 
375d2201f2fSdrahn static bfd_boolean
sh64_elf_add_symbol_hook(bfd * abfd,struct bfd_link_info * info,Elf_Internal_Sym * sym,const char ** namep,flagword * flagsp ATTRIBUTE_UNUSED,asection ** secp,bfd_vma * valp)376*cf2f2c56Smiod sh64_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
377*cf2f2c56Smiod 			  Elf_Internal_Sym *sym, const char **namep,
378*cf2f2c56Smiod 			  flagword *flagsp ATTRIBUTE_UNUSED,
379*cf2f2c56Smiod 			  asection **secp, bfd_vma *valp)
380d2201f2fSdrahn {
381d2201f2fSdrahn   /* We want to do this for relocatable as well as final linking.  */
382d2201f2fSdrahn   if (ELF_ST_TYPE (sym->st_info) == STT_DATALABEL
383*cf2f2c56Smiod       && is_elf_hash_table (info->hash))
384d2201f2fSdrahn     {
385d2201f2fSdrahn       struct elf_link_hash_entry *h;
386d2201f2fSdrahn 
387*cf2f2c56Smiod       /* For relocatable links, we register the DataLabel sym in its own
388d2201f2fSdrahn 	 right, and tweak the name when it's output.  Otherwise, we make
389d2201f2fSdrahn 	 an indirect symbol of it.  */
390d2201f2fSdrahn       flagword flags
391*cf2f2c56Smiod 	= info->relocatable || info->emitrelocations
392d2201f2fSdrahn 	? BSF_GLOBAL : BSF_GLOBAL | BSF_INDIRECT;
393d2201f2fSdrahn 
394d2201f2fSdrahn       char *dl_name
395d2201f2fSdrahn 	= bfd_malloc (strlen (*namep) + sizeof (DATALABEL_SUFFIX));
396d2201f2fSdrahn       struct elf_link_hash_entry ** sym_hash = elf_sym_hashes (abfd);
397d2201f2fSdrahn 
398d2201f2fSdrahn       BFD_ASSERT (sym_hash != NULL);
399d2201f2fSdrahn 
400d2201f2fSdrahn       /* Allocation may fail.  */
401d2201f2fSdrahn       if (dl_name == NULL)
402d2201f2fSdrahn 	return FALSE;
403d2201f2fSdrahn 
404d2201f2fSdrahn       strcpy (dl_name, *namep);
405d2201f2fSdrahn       strcat (dl_name, DATALABEL_SUFFIX);
406d2201f2fSdrahn 
407d2201f2fSdrahn       h = (struct elf_link_hash_entry *)
408d2201f2fSdrahn 	bfd_link_hash_lookup (info->hash, dl_name, FALSE, FALSE, FALSE);
409d2201f2fSdrahn 
410d2201f2fSdrahn       if (h == NULL)
411d2201f2fSdrahn 	{
412d2201f2fSdrahn 	  /* No previous datalabel symbol.  Make one.  */
413d2201f2fSdrahn 	  struct bfd_link_hash_entry *bh = NULL;
414*cf2f2c56Smiod 	  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
415d2201f2fSdrahn 
416d2201f2fSdrahn 	  if (! _bfd_generic_link_add_one_symbol (info, abfd, dl_name,
417d2201f2fSdrahn 						  flags, *secp, *valp,
418d2201f2fSdrahn 						  *namep, FALSE,
419d2201f2fSdrahn 						  bed->collect, &bh))
420d2201f2fSdrahn 	    {
421d2201f2fSdrahn 	      free (dl_name);
422d2201f2fSdrahn 	      return FALSE;
423d2201f2fSdrahn 	    }
424d2201f2fSdrahn 
425d2201f2fSdrahn 	  h = (struct elf_link_hash_entry *) bh;
426d2201f2fSdrahn 	  h->elf_link_hash_flags &=~ ELF_LINK_NON_ELF;
427d2201f2fSdrahn 	  h->type = STT_DATALABEL;
428d2201f2fSdrahn 	}
429d2201f2fSdrahn       else
430d2201f2fSdrahn 	/* If a new symbol was created, it holds the allocated name.
431d2201f2fSdrahn 	   Otherwise, we don't need it anymore and should deallocate it.  */
432d2201f2fSdrahn 	free (dl_name);
433d2201f2fSdrahn 
434d2201f2fSdrahn       if (h->type != STT_DATALABEL
435*cf2f2c56Smiod 	  || ((info->relocatable || info->emitrelocations)
436d2201f2fSdrahn 	      && h->root.type != bfd_link_hash_undefined)
437*cf2f2c56Smiod 	  || (! info->relocatable && !info->emitrelocations
438d2201f2fSdrahn 	      && h->root.type != bfd_link_hash_indirect))
439d2201f2fSdrahn 	{
440d2201f2fSdrahn 	  /* Make sure we don't get confused on invalid input.  */
441d2201f2fSdrahn 	  (*_bfd_error_handler)
442d2201f2fSdrahn 	    (_("%s: encountered datalabel symbol in input"),
443d2201f2fSdrahn 	     bfd_get_filename (abfd));
444d2201f2fSdrahn 	  bfd_set_error (bfd_error_bad_value);
445d2201f2fSdrahn 	  return FALSE;
446d2201f2fSdrahn 	}
447d2201f2fSdrahn 
448d2201f2fSdrahn       /* Now find the hash-table slot for this entry and fill it in.  */
449d2201f2fSdrahn       while (*sym_hash != NULL)
450d2201f2fSdrahn 	sym_hash++;
451d2201f2fSdrahn       *sym_hash = h;
452d2201f2fSdrahn 
453d2201f2fSdrahn       /* Signal to caller to skip this symbol - we've handled it.  */
454d2201f2fSdrahn       *namep = NULL;
455d2201f2fSdrahn     }
456d2201f2fSdrahn 
457d2201f2fSdrahn   return TRUE;
458d2201f2fSdrahn }
459d2201f2fSdrahn 
460d2201f2fSdrahn /* This hook function is called before the linker writes out a global
461d2201f2fSdrahn    symbol.  For relocatable links, DataLabel symbols will be present in
462d2201f2fSdrahn    linker output.  We cut off the special suffix on those symbols, so the
463d2201f2fSdrahn    right name appears in the output.
464d2201f2fSdrahn 
465d2201f2fSdrahn    When linking and emitting relocations, there can appear global symbols
466d2201f2fSdrahn    that are not referenced by relocs, but rather only implicitly through
467d2201f2fSdrahn    DataLabel references, a relation that is not visible to the linker.
468d2201f2fSdrahn    Since no stripping of global symbols in done when doing such linking,
469d2201f2fSdrahn    we don't need to look up and make sure to emit the main symbol for each
470d2201f2fSdrahn    DataLabel symbol.  */
471d2201f2fSdrahn 
472d2201f2fSdrahn bfd_boolean
sh64_elf_link_output_symbol_hook(struct bfd_link_info * info,const char * cname,Elf_Internal_Sym * sym,asection * input_sec ATTRIBUTE_UNUSED,struct elf_link_hash_entry * h ATTRIBUTE_UNUSED)473*cf2f2c56Smiod sh64_elf_link_output_symbol_hook (struct bfd_link_info *info,
474*cf2f2c56Smiod 				  const char *cname,
475*cf2f2c56Smiod 				  Elf_Internal_Sym *sym,
476*cf2f2c56Smiod 				  asection *input_sec ATTRIBUTE_UNUSED,
477*cf2f2c56Smiod 				  struct elf_link_hash_entry *h ATTRIBUTE_UNUSED)
478d2201f2fSdrahn {
479d2201f2fSdrahn   char *name = (char *) cname;
480d2201f2fSdrahn 
481*cf2f2c56Smiod   if (info->relocatable || info->emitrelocations)
482d2201f2fSdrahn     {
483d2201f2fSdrahn       if (ELF_ST_TYPE (sym->st_info) == STT_DATALABEL)
484d2201f2fSdrahn 	name[strlen (name) - strlen (DATALABEL_SUFFIX)] = 0;
485d2201f2fSdrahn     }
486d2201f2fSdrahn 
487d2201f2fSdrahn   return TRUE;
488d2201f2fSdrahn }
489d2201f2fSdrahn 
490d2201f2fSdrahn /* Check a SH64-specific reloc and put the value to relocate to into
491d2201f2fSdrahn    RELOCATION, ready to pass to _bfd_final_link_relocate.  Return FALSE if
492d2201f2fSdrahn    bad value, TRUE if ok.  */
493d2201f2fSdrahn 
494d2201f2fSdrahn static bfd_boolean
shmedia_prepare_reloc(struct bfd_link_info * info,bfd * abfd,asection * input_section,bfd_byte * contents,const Elf_Internal_Rela * rel,bfd_vma * relocation)495*cf2f2c56Smiod shmedia_prepare_reloc (struct bfd_link_info *info, bfd *abfd,
496*cf2f2c56Smiod 		       asection *input_section, bfd_byte *contents,
497*cf2f2c56Smiod 		       const Elf_Internal_Rela *rel, bfd_vma *relocation)
498d2201f2fSdrahn {
499d2201f2fSdrahn   bfd_vma disp, dropped;
500d2201f2fSdrahn 
501d2201f2fSdrahn   switch (ELF32_R_TYPE (rel->r_info))
502d2201f2fSdrahn     {
503d2201f2fSdrahn     case R_SH_PT_16:
504d2201f2fSdrahn       /* Check the lowest bit of the destination field.  If it is 1, we
505d2201f2fSdrahn 	 check the ISA type of the destination (i.e. the low bit of the
506d2201f2fSdrahn 	 "relocation" value, and emit an error if the instruction does not
507d2201f2fSdrahn 	 match).  If it is 0, we change a PTA to PTB.  There should never
508d2201f2fSdrahn 	 be a PTB that should change to a PTA; that indicates a toolchain
509d2201f2fSdrahn 	 error; a mismatch with GAS.  */
510d2201f2fSdrahn       {
511d2201f2fSdrahn 	char *msg = NULL;
512d2201f2fSdrahn 	bfd_vma insn = bfd_get_32 (abfd, contents + rel->r_offset);
513d2201f2fSdrahn 
514d2201f2fSdrahn 	if (insn & (1 << 10))
515d2201f2fSdrahn 	  {
516d2201f2fSdrahn 	    /* Check matching insn and ISA (address of target).  */
517d2201f2fSdrahn 	    if ((insn & SHMEDIA_PTB_BIT) != 0
518d2201f2fSdrahn 		&& ((*relocation + rel->r_addend) & 1) != 0)
519d2201f2fSdrahn 	      msg = _("PTB mismatch: a SHmedia address (bit 0 == 1)");
520d2201f2fSdrahn 	    else if ((insn & SHMEDIA_PTB_BIT) == 0
521d2201f2fSdrahn 		     && ((*relocation + rel->r_addend) & 1) == 0)
522d2201f2fSdrahn 	      msg = _("PTA mismatch: a SHcompact address (bit 0 == 0)");
523d2201f2fSdrahn 
524d2201f2fSdrahn 	    if (msg != NULL
525d2201f2fSdrahn 		&& ! ((*info->callbacks->reloc_dangerous)
526d2201f2fSdrahn 		      (info, msg, abfd, input_section,
527d2201f2fSdrahn 		       rel->r_offset)))
528d2201f2fSdrahn 	      return FALSE;
529d2201f2fSdrahn 	  }
530d2201f2fSdrahn 	else
531d2201f2fSdrahn 	  {
532d2201f2fSdrahn 	    /* We shouldn't get here with a PTB insn and a R_SH_PT_16.  It
533d2201f2fSdrahn 	       means GAS output does not match expectations; a PTA or PTB
534d2201f2fSdrahn 	       expressed as such (or a PT found at assembly to be PTB)
535d2201f2fSdrahn 	       would match the test above, and PT expansion with an
536d2201f2fSdrahn 	       unknown destination (or when relaxing) will get us here.  */
537d2201f2fSdrahn 	    if ((insn & SHMEDIA_PTB_BIT) != 0)
538d2201f2fSdrahn 	      {
539d2201f2fSdrahn 		(*_bfd_error_handler)
540d2201f2fSdrahn 		  (_("%s: GAS error: unexpected PTB insn with R_SH_PT_16"),
541d2201f2fSdrahn 		   bfd_get_filename (input_section->owner));
542d2201f2fSdrahn 		return FALSE;
543d2201f2fSdrahn 	      }
544d2201f2fSdrahn 
545d2201f2fSdrahn 	    /* Change the PTA to a PTB, if destination indicates so.  */
546d2201f2fSdrahn 	    if (((*relocation + rel->r_addend) & 1) == 0)
547d2201f2fSdrahn 	      bfd_put_32 (abfd, insn | SHMEDIA_PTB_BIT,
548d2201f2fSdrahn 			  contents + rel->r_offset);
549d2201f2fSdrahn 	  }
550d2201f2fSdrahn       }
551d2201f2fSdrahn 
552d2201f2fSdrahn     case R_SH_SHMEDIA_CODE:
553d2201f2fSdrahn     case R_SH_DIR5U:
554d2201f2fSdrahn     case R_SH_DIR6S:
555d2201f2fSdrahn     case R_SH_DIR6U:
556d2201f2fSdrahn     case R_SH_DIR10S:
557d2201f2fSdrahn     case R_SH_DIR10SW:
558d2201f2fSdrahn     case R_SH_DIR10SL:
559d2201f2fSdrahn     case R_SH_DIR10SQ:
560d2201f2fSdrahn     case R_SH_IMMS16:
561d2201f2fSdrahn     case R_SH_IMMU16:
562d2201f2fSdrahn     case R_SH_IMM_LOW16:
563d2201f2fSdrahn     case R_SH_IMM_LOW16_PCREL:
564d2201f2fSdrahn     case R_SH_IMM_MEDLOW16:
565d2201f2fSdrahn     case R_SH_IMM_MEDLOW16_PCREL:
566d2201f2fSdrahn     case R_SH_IMM_MEDHI16:
567d2201f2fSdrahn     case R_SH_IMM_MEDHI16_PCREL:
568d2201f2fSdrahn     case R_SH_IMM_HI16:
569d2201f2fSdrahn     case R_SH_IMM_HI16_PCREL:
570d2201f2fSdrahn     case R_SH_64:
571d2201f2fSdrahn     case R_SH_64_PCREL:
572d2201f2fSdrahn       break;
573d2201f2fSdrahn 
574d2201f2fSdrahn     default:
575d2201f2fSdrahn       return FALSE;
576d2201f2fSdrahn     }
577d2201f2fSdrahn 
578d2201f2fSdrahn   disp = (*relocation & 0xf);
579d2201f2fSdrahn   dropped = 0;
580d2201f2fSdrahn   switch (ELF32_R_TYPE (rel->r_info))
581d2201f2fSdrahn     {
582d2201f2fSdrahn     case R_SH_DIR10SW: dropped = disp & 1; break;
583d2201f2fSdrahn     case R_SH_DIR10SL: dropped = disp & 3; break;
584d2201f2fSdrahn     case R_SH_DIR10SQ: dropped = disp & 7; break;
585d2201f2fSdrahn     }
586d2201f2fSdrahn   if (dropped != 0)
587d2201f2fSdrahn     {
588d2201f2fSdrahn       (*_bfd_error_handler)
589d2201f2fSdrahn 	(_("%s: error: unaligned relocation type %d at %08x reloc %08x\n"),
590d2201f2fSdrahn 	 bfd_get_filename (input_section->owner), ELF32_R_TYPE (rel->r_info),
591d2201f2fSdrahn 	 (unsigned)rel->r_offset, (unsigned)relocation);
592d2201f2fSdrahn       return FALSE;
593d2201f2fSdrahn     }
594d2201f2fSdrahn 
595d2201f2fSdrahn   return TRUE;
596d2201f2fSdrahn }
597d2201f2fSdrahn 
598d2201f2fSdrahn /* Helper function to locate the section holding a certain address.  This
599d2201f2fSdrahn    is called via bfd_map_over_sections.  */
600d2201f2fSdrahn 
601d2201f2fSdrahn static void
sh64_find_section_for_address(bfd * abfd ATTRIBUTE_UNUSED,asection * section,void * data)602*cf2f2c56Smiod sh64_find_section_for_address (bfd *abfd ATTRIBUTE_UNUSED,
603*cf2f2c56Smiod 			       asection *section, void *data)
604d2201f2fSdrahn {
605d2201f2fSdrahn   bfd_vma vma;
606d2201f2fSdrahn   bfd_size_type size;
607d2201f2fSdrahn   struct sh64_find_section_vma_data *fsec_datap
608d2201f2fSdrahn     = (struct sh64_find_section_vma_data *) data;
609d2201f2fSdrahn 
610d2201f2fSdrahn   /* Return if already found.  */
611d2201f2fSdrahn   if (fsec_datap->section)
612d2201f2fSdrahn     return;
613d2201f2fSdrahn 
614d2201f2fSdrahn   /* If this section isn't part of the addressable contents, skip it.  */
615d2201f2fSdrahn   if ((bfd_get_section_flags (abfd, section) & SEC_ALLOC) == 0)
616d2201f2fSdrahn     return;
617d2201f2fSdrahn 
618d2201f2fSdrahn   vma = bfd_get_section_vma (abfd, section);
619d2201f2fSdrahn   if (fsec_datap->addr < vma)
620d2201f2fSdrahn     return;
621d2201f2fSdrahn 
622d2201f2fSdrahn   /* FIXME: section->reloc_done isn't set properly; a generic buglet
623d2201f2fSdrahn      preventing us from using bfd_get_section_size_after_reloc.  */
624d2201f2fSdrahn   size
625d2201f2fSdrahn     = section->_cooked_size ? section->_cooked_size : section->_raw_size;
626d2201f2fSdrahn 
627d2201f2fSdrahn   if (fsec_datap->addr >= vma + size)
628d2201f2fSdrahn     return;
629d2201f2fSdrahn 
630d2201f2fSdrahn   fsec_datap->section = section;
631d2201f2fSdrahn }
632d2201f2fSdrahn 
633d2201f2fSdrahn /* Make sure to write out the generated entries in the .cranges section
634d2201f2fSdrahn    when doing partial linking, and set bit 0 on the entry address if it
635d2201f2fSdrahn    points to SHmedia code and write sorted .cranges entries when writing
636d2201f2fSdrahn    executables (final linking and objcopy).  */
637d2201f2fSdrahn 
638d2201f2fSdrahn static void
sh64_elf_final_write_processing(bfd * abfd,bfd_boolean linker ATTRIBUTE_UNUSED)639*cf2f2c56Smiod sh64_elf_final_write_processing (bfd *abfd,
640*cf2f2c56Smiod 				 bfd_boolean linker ATTRIBUTE_UNUSED)
641d2201f2fSdrahn {
642d2201f2fSdrahn   bfd_vma ld_generated_cranges_size;
643d2201f2fSdrahn   asection *cranges
644d2201f2fSdrahn     = bfd_get_section_by_name (abfd, SH64_CRANGES_SECTION_NAME);
645d2201f2fSdrahn 
646d2201f2fSdrahn   /* If no new .cranges were added, the generic ELF linker parts will
647d2201f2fSdrahn      write it all out.  If not, we need to write them out when doing
648d2201f2fSdrahn      partial linking.  For a final link, we will sort them and write them
649d2201f2fSdrahn      all out further below.  */
650d2201f2fSdrahn   if (linker
651d2201f2fSdrahn       && cranges != NULL
652d2201f2fSdrahn       && elf_elfheader (abfd)->e_type != ET_EXEC
653d2201f2fSdrahn       && (ld_generated_cranges_size
654d2201f2fSdrahn 	  = sh64_elf_section_data (cranges)->sh64_info->cranges_growth) != 0)
655d2201f2fSdrahn     {
656d2201f2fSdrahn       bfd_vma incoming_cranges_size
657d2201f2fSdrahn 	= ((cranges->_cooked_size != 0
658d2201f2fSdrahn 	    ? cranges->_cooked_size : cranges->_raw_size)
659d2201f2fSdrahn 	   - ld_generated_cranges_size);
660d2201f2fSdrahn 
661d2201f2fSdrahn       if (! bfd_set_section_contents (abfd, cranges,
662d2201f2fSdrahn 				      cranges->contents
663d2201f2fSdrahn 				      + incoming_cranges_size,
664d2201f2fSdrahn 				      cranges->output_offset
665d2201f2fSdrahn 				      + incoming_cranges_size,
666d2201f2fSdrahn 				      ld_generated_cranges_size))
667d2201f2fSdrahn 	{
668d2201f2fSdrahn 	  bfd_set_error (bfd_error_file_truncated);
669d2201f2fSdrahn 	  (*_bfd_error_handler)
670d2201f2fSdrahn 	    (_("%s: could not write out added .cranges entries"),
671d2201f2fSdrahn 	     bfd_get_filename (abfd));
672d2201f2fSdrahn 	}
673d2201f2fSdrahn     }
674d2201f2fSdrahn 
675d2201f2fSdrahn   /* Only set entry address bit 0 and sort .cranges when linking to an
676d2201f2fSdrahn      executable; never with objcopy or strip.  */
677d2201f2fSdrahn   if (linker && elf_elfheader (abfd)->e_type == ET_EXEC)
678d2201f2fSdrahn     {
679d2201f2fSdrahn       struct sh64_find_section_vma_data fsec_data;
680d2201f2fSdrahn       sh64_elf_crange dummy;
681d2201f2fSdrahn 
682d2201f2fSdrahn       /* For a final link, set the low bit of the entry address to
683d2201f2fSdrahn 	 reflect whether or not it is a SHmedia address.
684d2201f2fSdrahn 	 FIXME: Perhaps we shouldn't do this if the entry address was
685d2201f2fSdrahn 	 supplied numerically, but we currently lack the infrastructure to
686d2201f2fSdrahn 	 recognize that: The entry symbol, and info whether it is numeric
687d2201f2fSdrahn 	 or a symbol name is kept private in the linker.  */
688d2201f2fSdrahn       fsec_data.addr = elf_elfheader (abfd)->e_entry;
689d2201f2fSdrahn       fsec_data.section = NULL;
690d2201f2fSdrahn 
691d2201f2fSdrahn       bfd_map_over_sections (abfd, sh64_find_section_for_address,
692*cf2f2c56Smiod 			     &fsec_data);
693d2201f2fSdrahn       if (fsec_data.section
694d2201f2fSdrahn 	  && (sh64_get_contents_type (fsec_data.section,
695d2201f2fSdrahn 				      elf_elfheader (abfd)->e_entry,
696d2201f2fSdrahn 				      &dummy) == CRT_SH5_ISA32))
697d2201f2fSdrahn 	elf_elfheader (abfd)->e_entry |= 1;
698d2201f2fSdrahn 
699d2201f2fSdrahn       /* If we have a .cranges section, sort the entries.  */
700d2201f2fSdrahn       if (cranges != NULL)
701d2201f2fSdrahn 	{
702d2201f2fSdrahn 	  bfd_size_type cranges_size
703d2201f2fSdrahn 	    = (cranges->_cooked_size != 0
704d2201f2fSdrahn 	       ? cranges->_cooked_size : cranges->_raw_size);
705d2201f2fSdrahn 
706d2201f2fSdrahn 	  /* We know we always have these in memory at this time.  */
707d2201f2fSdrahn 	  BFD_ASSERT (cranges->contents != NULL);
708d2201f2fSdrahn 
709d2201f2fSdrahn 	  /* The .cranges may already have been sorted in the process of
710d2201f2fSdrahn 	     finding out the ISA-type of the entry address.  If not, we do
711d2201f2fSdrahn 	     it here.  */
712d2201f2fSdrahn 	  if (elf_section_data (cranges)->this_hdr.sh_type
713d2201f2fSdrahn 	      != SHT_SH5_CR_SORTED)
714d2201f2fSdrahn 	    {
715d2201f2fSdrahn 	      qsort (cranges->contents, cranges_size / SH64_CRANGE_SIZE,
716d2201f2fSdrahn 		     SH64_CRANGE_SIZE,
717d2201f2fSdrahn 		     bfd_big_endian (cranges->owner)
718d2201f2fSdrahn 		     ? _bfd_sh64_crange_qsort_cmpb
719d2201f2fSdrahn 		     : _bfd_sh64_crange_qsort_cmpl);
720d2201f2fSdrahn 	      elf_section_data (cranges)->this_hdr.sh_type
721d2201f2fSdrahn 		= SHT_SH5_CR_SORTED;
722d2201f2fSdrahn 	    }
723d2201f2fSdrahn 
724d2201f2fSdrahn 	  /* We need to write it out in whole as sorted.  */
725d2201f2fSdrahn 	  if (! bfd_set_section_contents (abfd, cranges,
726d2201f2fSdrahn 					  cranges->contents,
727d2201f2fSdrahn 					  cranges->output_offset,
728d2201f2fSdrahn 					  cranges_size))
729d2201f2fSdrahn 	    {
730d2201f2fSdrahn 	      bfd_set_error (bfd_error_file_truncated);
731d2201f2fSdrahn 	      (*_bfd_error_handler)
732d2201f2fSdrahn 		(_("%s: could not write out sorted .cranges entries"),
733d2201f2fSdrahn 		 bfd_get_filename (abfd));
734d2201f2fSdrahn 	    }
735d2201f2fSdrahn 	}
736d2201f2fSdrahn     }
737d2201f2fSdrahn }
738d2201f2fSdrahn 
739*cf2f2c56Smiod /* Merge non visibility st_other attribute when the symbol comes from
740*cf2f2c56Smiod    a dynamic object.  */
741*cf2f2c56Smiod static void
sh64_elf_merge_symbol_attribute(struct elf_link_hash_entry * h,const Elf_Internal_Sym * isym,bfd_boolean definition,bfd_boolean dynamic)742*cf2f2c56Smiod sh64_elf_merge_symbol_attribute (struct elf_link_hash_entry *h,
743*cf2f2c56Smiod 				 const Elf_Internal_Sym *isym,
744*cf2f2c56Smiod 				 bfd_boolean definition,
745*cf2f2c56Smiod 				 bfd_boolean dynamic)
746*cf2f2c56Smiod {
747*cf2f2c56Smiod   if (isym->st_other != 0 && dynamic)
748*cf2f2c56Smiod     {
749*cf2f2c56Smiod       unsigned char other;
750*cf2f2c56Smiod 
751*cf2f2c56Smiod       /* Take the balance of OTHER from the definition.  */
752*cf2f2c56Smiod       other = (definition ? isym->st_other : h->other);
753*cf2f2c56Smiod       other &= ~ ELF_ST_VISIBILITY (-1);
754*cf2f2c56Smiod       h->other = other | ELF_ST_VISIBILITY (h->other);
755*cf2f2c56Smiod     }
756*cf2f2c56Smiod 
757*cf2f2c56Smiod   return;
758*cf2f2c56Smiod }
759*cf2f2c56Smiod 
760*cf2f2c56Smiod static struct bfd_elf_special_section const sh64_elf_special_sections[]=
761*cf2f2c56Smiod {
762*cf2f2c56Smiod   { ".cranges", 8, 0, SHT_PROGBITS, 0 },
763*cf2f2c56Smiod   { NULL,       0, 0, 0,            0 }
764*cf2f2c56Smiod };
765*cf2f2c56Smiod 
766d2201f2fSdrahn #undef	TARGET_BIG_SYM
767d2201f2fSdrahn #define	TARGET_BIG_SYM		bfd_elf32_sh64_vec
768d2201f2fSdrahn #undef	TARGET_BIG_NAME
769d2201f2fSdrahn #define	TARGET_BIG_NAME		"elf32-sh64"
770d2201f2fSdrahn #undef	TARGET_LITTLE_SYM
771d2201f2fSdrahn #define	TARGET_LITTLE_SYM	bfd_elf32_sh64l_vec
772d2201f2fSdrahn #undef	TARGET_LITTLE_NAME
773d2201f2fSdrahn #define	TARGET_LITTLE_NAME	"elf32-sh64l"
774d2201f2fSdrahn 
775d2201f2fSdrahn #include "elf32-target.h"
776d2201f2fSdrahn 
777d2201f2fSdrahn /* NetBSD support.  */
778d2201f2fSdrahn #undef	TARGET_BIG_SYM
779d2201f2fSdrahn #define	TARGET_BIG_SYM		bfd_elf32_sh64nbsd_vec
780d2201f2fSdrahn #undef	TARGET_BIG_NAME
781d2201f2fSdrahn #define	TARGET_BIG_NAME		"elf32-sh64-nbsd"
782d2201f2fSdrahn #undef	TARGET_LITTLE_SYM
783d2201f2fSdrahn #define	TARGET_LITTLE_SYM	bfd_elf32_sh64lnbsd_vec
784d2201f2fSdrahn #undef	TARGET_LITTLE_NAME
785d2201f2fSdrahn #define	TARGET_LITTLE_NAME	"elf32-sh64l-nbsd"
786d2201f2fSdrahn #undef	ELF_MAXPAGESIZE
787d2201f2fSdrahn #define	ELF_MAXPAGESIZE		0x10000
788d2201f2fSdrahn #undef	elf_symbol_leading_char
789d2201f2fSdrahn #define	elf_symbol_leading_char	0
790d2201f2fSdrahn #undef	elf32_bed
791d2201f2fSdrahn #define	elf32_bed		elf32_sh64_nbsd_bed
792d2201f2fSdrahn 
793d2201f2fSdrahn #include "elf32-target.h"
794d2201f2fSdrahn 
795d2201f2fSdrahn /* Linux support.  */
796d2201f2fSdrahn #undef	TARGET_BIG_SYM
797d2201f2fSdrahn #define	TARGET_BIG_SYM		bfd_elf32_sh64blin_vec
798d2201f2fSdrahn #undef	TARGET_BIG_NAME
799d2201f2fSdrahn #define	TARGET_BIG_NAME		"elf32-sh64big-linux"
800d2201f2fSdrahn #undef	TARGET_LITTLE_SYM
801d2201f2fSdrahn #define	TARGET_LITTLE_SYM	bfd_elf32_sh64lin_vec
802d2201f2fSdrahn #undef	TARGET_LITTLE_NAME
803d2201f2fSdrahn #define	TARGET_LITTLE_NAME	"elf32-sh64-linux"
804d2201f2fSdrahn #undef	elf32_bed
805d2201f2fSdrahn #define	elf32_bed		elf32_sh64_lin_bed
806d2201f2fSdrahn 
807d2201f2fSdrahn #include "elf32-target.h"
808d2201f2fSdrahn 
809