1 /* SuperH SH64-specific support for 32-bit ELF
2 Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2007
3 Free Software Foundation, Inc.
5 This file is part of BFD, the Binary File Descriptor library.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20 MA 02110-1301, USA. */
29 #include "elf32-sh64.h"
30 #include "../opcodes/sh64-opc.h"
32 static bfd_boolean sh64_address_in_cranges
33 (asection
*cranges
, bfd_vma
, sh64_elf_crange
*);
35 /* Ordering functions of a crange, for the qsort and bsearch calls and for
36 different endianness. */
39 _bfd_sh64_crange_qsort_cmpb (const void *p1
, const void *p2
)
41 bfd_vma a1
= bfd_getb32 (p1
);
42 bfd_vma a2
= bfd_getb32 (p2
);
44 /* Preserve order if there's ambiguous contents. */
46 return (char *) p1
- (char *) p2
;
52 _bfd_sh64_crange_qsort_cmpl (const void *p1
, const void *p2
)
54 bfd_vma a1
= (bfd_vma
) bfd_getl32 (p1
);
55 bfd_vma a2
= (bfd_vma
) bfd_getl32 (p2
);
57 /* Preserve order if there's ambiguous contents. */
59 return (char *) p1
- (char *) p2
;
65 _bfd_sh64_crange_bsearch_cmpb (const void *p1
, const void *p2
)
67 bfd_vma a1
= *(bfd_vma
*) p1
;
68 bfd_vma a2
= (bfd_vma
) bfd_getb32 (p2
);
70 = (bfd_size_type
) bfd_getb32 (SH64_CRANGE_CR_SIZE_OFFSET
+ (char *) p2
);
80 _bfd_sh64_crange_bsearch_cmpl (const void *p1
, const void *p2
)
82 bfd_vma a1
= *(bfd_vma
*) p1
;
83 bfd_vma a2
= (bfd_vma
) bfd_getl32 (p2
);
85 = (bfd_size_type
) bfd_getl32 (SH64_CRANGE_CR_SIZE_OFFSET
+ (char *) p2
);
94 /* Check whether a specific address is specified within a .cranges
95 section. Return FALSE if not found, and TRUE if found, and the region
96 filled into RANGEP if non-NULL. */
99 sh64_address_in_cranges (asection
*cranges
, bfd_vma addr
,
100 sh64_elf_crange
*rangep
)
102 bfd_byte
*cranges_contents
;
103 bfd_byte
*found_rangep
;
104 bfd_size_type cranges_size
= cranges
->size
;
106 /* If the size is not a multiple of the cranges entry size, then
107 something is badly wrong. */
108 if ((cranges_size
% SH64_CRANGE_SIZE
) != 0)
111 /* If this section has relocations, then we can't do anything sane. */
112 if (bfd_get_section_flags (cranges
->owner
, cranges
) & SEC_RELOC
)
115 /* Has some kind soul (or previous call) left processed, sorted contents
117 if ((bfd_get_section_flags (cranges
->owner
, cranges
) & SEC_IN_MEMORY
)
118 && elf_section_data (cranges
)->this_hdr
.sh_type
== SHT_SH5_CR_SORTED
)
119 cranges_contents
= cranges
->contents
;
122 if (!bfd_malloc_and_get_section (cranges
->owner
, cranges
,
127 if (elf_section_data (cranges
)->this_hdr
.sh_type
128 != SHT_SH5_CR_SORTED
)
129 /* Nope. Lets sort it. */
130 qsort (cranges_contents
, cranges_size
/ SH64_CRANGE_SIZE
,
132 bfd_big_endian (cranges
->owner
)
133 ? _bfd_sh64_crange_qsort_cmpb
: _bfd_sh64_crange_qsort_cmpl
);
135 /* Let's keep it around. */
136 cranges
->contents
= cranges_contents
;
137 bfd_set_section_flags (cranges
->owner
, cranges
,
138 bfd_get_section_flags (cranges
->owner
, cranges
)
141 /* It's sorted now. */
142 elf_section_data (cranges
)->this_hdr
.sh_type
= SHT_SH5_CR_SORTED
;
145 /* Try and find a matching range. */
147 = bsearch (&addr
, cranges_contents
, cranges_size
/ SH64_CRANGE_SIZE
,
149 bfd_big_endian (cranges
->owner
)
150 ? _bfd_sh64_crange_bsearch_cmpb
151 : _bfd_sh64_crange_bsearch_cmpl
);
153 /* Fill in a few return values if we found a matching range. */
156 enum sh64_elf_cr_type cr_type
157 = bfd_get_16 (cranges
->owner
,
158 SH64_CRANGE_CR_TYPE_OFFSET
+ found_rangep
);
160 = bfd_get_32 (cranges
->owner
,
161 SH64_CRANGE_CR_ADDR_OFFSET
162 + (char *) found_rangep
);
163 bfd_size_type cr_size
164 = bfd_get_32 (cranges
->owner
,
165 SH64_CRANGE_CR_SIZE_OFFSET
166 + (char *) found_rangep
);
168 rangep
->cr_addr
= cr_addr
;
169 rangep
->cr_size
= cr_size
;
170 rangep
->cr_type
= cr_type
;
175 /* There is a .cranges section, but it does not have a descriptor
176 matching this address. */
180 if (cranges_contents
!= NULL
)
181 free (cranges_contents
);
185 /* Determine what ADDR points to in SEC, and fill in a range descriptor in
186 *RANGEP if it's non-NULL. */
188 enum sh64_elf_cr_type
189 sh64_get_contents_type (asection
*sec
, bfd_vma addr
, sh64_elf_crange
*rangep
)
193 /* Fill in the range with the boundaries of the section as a default. */
194 if (bfd_get_flavour (sec
->owner
) == bfd_target_elf_flavour
195 && elf_elfheader (sec
->owner
)->e_type
== ET_EXEC
)
197 rangep
->cr_addr
= bfd_get_section_vma (sec
->owner
, sec
);
198 rangep
->cr_size
= sec
->size
;
199 rangep
->cr_type
= CRT_NONE
;
204 /* If none of the pertinent bits are set, then it's a SHcompact (or at
205 least not SHmedia). */
206 if ((elf_section_data (sec
)->this_hdr
.sh_flags
207 & (SHF_SH5_ISA32
| SHF_SH5_ISA32_MIXED
)) == 0)
209 enum sh64_elf_cr_type cr_type
210 = ((bfd_get_section_flags (sec
->owner
, sec
) & SEC_CODE
) != 0
211 ? CRT_SH5_ISA16
: CRT_DATA
);
212 rangep
->cr_type
= cr_type
;
216 /* If only the SHF_SH5_ISA32 bit is set, then we have SHmedia. */
217 if ((elf_section_data (sec
)->this_hdr
.sh_flags
218 & (SHF_SH5_ISA32
| SHF_SH5_ISA32_MIXED
)) == SHF_SH5_ISA32
)
220 rangep
->cr_type
= CRT_SH5_ISA32
;
221 return CRT_SH5_ISA32
;
224 /* Otherwise, we have to look up the .cranges section. */
225 cranges
= bfd_get_section_by_name (sec
->owner
, SH64_CRANGES_SECTION_NAME
);
228 /* A mixed section but there's no .cranges section. This is probably
229 bad input; it does not comply to specs. */
232 /* If this call fails, we will still have CRT_NONE in rangep->cr_type
233 and that will be suitable to return. */
234 sh64_address_in_cranges (cranges
, addr
, rangep
);
236 return rangep
->cr_type
;
239 /* This is a simpler exported interface for the benefit of gdb et al. */
242 sh64_address_is_shmedia (asection
*sec
, bfd_vma addr
)
244 sh64_elf_crange dummy
;
245 return sh64_get_contents_type (sec
, addr
, &dummy
) == CRT_SH5_ISA32
;