daily update
[binutils.git] / bfd / elf32-sh64-com.c
blob107e50490bbd79c30711cffb86cde8403c292d99
1 /* Hitachi SH64-specific support for 32-bit ELF
2 Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
4 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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. */
20 #define SH64_ELF
22 #include "bfd.h"
23 #include "sysdep.h"
24 #include "libbfd.h"
25 #include "elf-bfd.h"
26 #include "elf/sh.h"
27 #include "elf32-sh64.h"
28 #include "../opcodes/sh64-opc.h"
30 static bfd_boolean sh64_address_in_cranges
31 PARAMS ((asection *cranges, bfd_vma, sh64_elf_crange *));
33 /* Ordering functions of a crange, for the qsort and bsearch calls and for
34 different endianness. */
36 int
37 _bfd_sh64_crange_qsort_cmpb (p1, p2)
38 const PTR p1;
39 const PTR p2;
41 bfd_vma a1 = bfd_getb32 (p1);
42 bfd_vma a2 = bfd_getb32 (p2);
44 /* Preserve order if there's ambiguous contents. */
45 if (a1 == a2)
46 return (char *) p1 - (char *) p2;
48 return a1 - a2;
51 int
52 _bfd_sh64_crange_qsort_cmpl (p1, p2)
53 const PTR p1;
54 const PTR p2;
56 bfd_vma a1 = (bfd_vma) bfd_getl32 (p1);
57 bfd_vma a2 = (bfd_vma) bfd_getl32 (p2);
59 /* Preserve order if there's ambiguous contents. */
60 if (a1 == a2)
61 return (char *) p1 - (char *) p2;
63 return a1 - a2;
66 int
67 _bfd_sh64_crange_bsearch_cmpb (p1, p2)
68 const PTR p1;
69 const PTR p2;
71 bfd_vma a1 = *(bfd_vma *) p1;
72 bfd_vma a2 = (bfd_vma) bfd_getb32 (p2);
73 bfd_size_type size
74 = (bfd_size_type) bfd_getb32 (SH64_CRANGE_CR_SIZE_OFFSET + (char *) p2);
76 if (a1 >= a2 + size)
77 return 1;
78 if (a1 < a2)
79 return -1;
80 return 0;
83 int
84 _bfd_sh64_crange_bsearch_cmpl (p1, p2)
85 const PTR p1;
86 const PTR p2;
88 bfd_vma a1 = *(bfd_vma *) p1;
89 bfd_vma a2 = (bfd_vma) bfd_getl32 (p2);
90 bfd_size_type size
91 = (bfd_size_type) bfd_getl32 (SH64_CRANGE_CR_SIZE_OFFSET + (char *) p2);
93 if (a1 >= a2 + size)
94 return 1;
95 if (a1 < a2)
96 return -1;
97 return 0;
100 /* Check whether a specific address is specified within a .cranges
101 section. Return FALSE if not found, and TRUE if found, and the region
102 filled into RANGEP if non-NULL. */
104 static bfd_boolean
105 sh64_address_in_cranges (cranges, addr, rangep)
106 asection *cranges;
107 bfd_vma addr;
108 sh64_elf_crange *rangep;
110 bfd_byte *cranges_contents;
111 bfd_byte *found_rangep;
112 bfd_size_type cranges_size = bfd_section_size (cranges->owner, cranges);
114 /* If the size is not a multiple of the cranges entry size, then
115 something is badly wrong. */
116 if ((cranges_size % SH64_CRANGE_SIZE) != 0)
117 return FALSE;
119 /* If this section has relocations, then we can't do anything sane. */
120 if (bfd_get_section_flags (cranges->owner, cranges) & SEC_RELOC)
121 return FALSE;
123 /* Has some kind soul (or previous call) left processed, sorted contents
124 for us? */
125 if ((bfd_get_section_flags (cranges->owner, cranges) & SEC_IN_MEMORY)
126 && elf_section_data (cranges)->this_hdr.sh_type == SHT_SH5_CR_SORTED)
127 cranges_contents = cranges->contents;
128 else
130 cranges_contents
131 = bfd_malloc (cranges->_cooked_size != 0
132 ? cranges->_cooked_size : cranges->_raw_size);
133 if (cranges_contents == NULL)
134 return FALSE;
136 if (! bfd_get_section_contents (cranges->owner, cranges,
137 cranges_contents, (file_ptr) 0,
138 cranges_size))
139 goto error_return;
141 /* Is it sorted? */
142 if (elf_section_data (cranges)->this_hdr.sh_type
143 != SHT_SH5_CR_SORTED)
144 /* Nope. Lets sort it. */
145 qsort (cranges_contents, cranges_size / SH64_CRANGE_SIZE,
146 SH64_CRANGE_SIZE,
147 bfd_big_endian (cranges->owner)
148 ? _bfd_sh64_crange_qsort_cmpb : _bfd_sh64_crange_qsort_cmpl);
150 /* Let's keep it around. */
151 cranges->contents = cranges_contents;
152 bfd_set_section_flags (cranges->owner, cranges,
153 bfd_get_section_flags (cranges->owner, cranges)
154 | SEC_IN_MEMORY);
156 /* It's sorted now. */
157 elf_section_data (cranges)->this_hdr.sh_type = SHT_SH5_CR_SORTED;
160 /* Try and find a matching range. */
161 found_rangep
162 = bsearch (&addr, cranges_contents, cranges_size / SH64_CRANGE_SIZE,
163 SH64_CRANGE_SIZE,
164 bfd_big_endian (cranges->owner)
165 ? _bfd_sh64_crange_bsearch_cmpb
166 : _bfd_sh64_crange_bsearch_cmpl);
168 /* Fill in a few return values if we found a matching range. */
169 if (found_rangep)
171 enum sh64_elf_cr_type cr_type
172 = bfd_get_16 (cranges->owner,
173 SH64_CRANGE_CR_TYPE_OFFSET + found_rangep);
174 bfd_vma cr_addr
175 = bfd_get_32 (cranges->owner,
176 SH64_CRANGE_CR_ADDR_OFFSET
177 + (char *) found_rangep);
178 bfd_size_type cr_size
179 = bfd_get_32 (cranges->owner,
180 SH64_CRANGE_CR_SIZE_OFFSET
181 + (char *) found_rangep);
183 rangep->cr_addr = cr_addr;
184 rangep->cr_size = cr_size;
185 rangep->cr_type = cr_type;
187 return TRUE;
190 /* There is a .cranges section, but it does not have a descriptor
191 matching this address. */
192 return FALSE;
194 error_return:
195 free (cranges_contents);
196 return FALSE;
199 /* Determine what ADDR points to in SEC, and fill in a range descriptor in
200 *RANGEP if it's non-NULL. */
202 enum sh64_elf_cr_type
203 sh64_get_contents_type (sec, addr, rangep)
204 asection *sec;
205 bfd_vma addr;
206 sh64_elf_crange *rangep;
208 asection *cranges;
210 /* Fill in the range with the boundaries of the section as a default. */
211 if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour
212 && elf_elfheader (sec->owner)->e_type == ET_EXEC)
214 rangep->cr_addr = bfd_get_section_vma (sec->owner, sec);
215 rangep->cr_size = bfd_section_size (sec->owner, sec);
216 rangep->cr_type = CRT_NONE;
218 else
219 return FALSE;
221 /* If none of the pertinent bits are set, then it's a SHcompact (or at
222 least not SHmedia). */
223 if ((elf_section_data (sec)->this_hdr.sh_flags
224 & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)) == 0)
226 enum sh64_elf_cr_type cr_type
227 = ((bfd_get_section_flags (sec->owner, sec) & SEC_CODE) != 0
228 ? CRT_SH5_ISA16 : CRT_DATA);
229 rangep->cr_type = cr_type;
230 return cr_type;
233 /* If only the SHF_SH5_ISA32 bit is set, then we have SHmedia. */
234 if ((elf_section_data (sec)->this_hdr.sh_flags
235 & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)) == SHF_SH5_ISA32)
237 rangep->cr_type = CRT_SH5_ISA32;
238 return CRT_SH5_ISA32;
241 /* Otherwise, we have to look up the .cranges section. */
242 cranges = bfd_get_section_by_name (sec->owner, SH64_CRANGES_SECTION_NAME);
244 if (cranges == NULL)
245 /* A mixed section but there's no .cranges section. This is probably
246 bad input; it does not comply to specs. */
247 return CRT_NONE;
249 /* If this call fails, we will still have CRT_NONE in rangep->cr_type
250 and that will be suitable to return. */
251 sh64_address_in_cranges (cranges, addr, rangep);
253 return rangep->cr_type;
256 /* This is a simpler exported interface for the benefit of gdb et al. */
258 bfd_boolean
259 sh64_address_is_shmedia (sec, addr)
260 asection *sec;
261 bfd_vma addr;
263 sh64_elf_crange dummy;
264 return sh64_get_contents_type (sec, addr, &dummy) == CRT_SH5_ISA32;