1 /* SuperH SH64-specific support for 32-bit ELF 2 Copyright (C) 2000-2014 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 3 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., 51 Franklin Street - Fifth Floor, Boston, 19 MA 02110-1301, USA. */ 20 21 #define SH64_ELF 22 23 #include "sysdep.h" 24 #include "bfd.h" 25 #include "libbfd.h" 26 #include "elf-bfd.h" 27 #include "elf/sh.h" 28 #include "elf32-sh64.h" 29 #include "../opcodes/sh64-opc.h" 30 31 static bfd_boolean sh64_address_in_cranges 32 (asection *cranges, bfd_vma, sh64_elf_crange *); 33 34 /* Ordering functions of a crange, for the qsort and bsearch calls and for 35 different endianness. */ 36 37 int 38 _bfd_sh64_crange_qsort_cmpb (const void *p1, const void *p2) 39 { 40 bfd_vma a1 = bfd_getb32 (p1); 41 bfd_vma a2 = bfd_getb32 (p2); 42 43 /* Preserve order if there's ambiguous contents. */ 44 if (a1 == a2) 45 return (char *) p1 - (char *) p2; 46 47 return a1 - a2; 48 } 49 50 int 51 _bfd_sh64_crange_qsort_cmpl (const void *p1, const void *p2) 52 { 53 bfd_vma a1 = (bfd_vma) bfd_getl32 (p1); 54 bfd_vma a2 = (bfd_vma) bfd_getl32 (p2); 55 56 /* Preserve order if there's ambiguous contents. */ 57 if (a1 == a2) 58 return (char *) p1 - (char *) p2; 59 60 return a1 - a2; 61 } 62 63 int 64 _bfd_sh64_crange_bsearch_cmpb (const void *p1, const void *p2) 65 { 66 bfd_vma a1 = *(bfd_vma *) p1; 67 bfd_vma a2 = (bfd_vma) bfd_getb32 (p2); 68 bfd_size_type size 69 = (bfd_size_type) bfd_getb32 (SH64_CRANGE_CR_SIZE_OFFSET + (char *) p2); 70 71 if (a1 >= a2 + size) 72 return 1; 73 if (a1 < a2) 74 return -1; 75 return 0; 76 } 77 78 int 79 _bfd_sh64_crange_bsearch_cmpl (const void *p1, const void *p2) 80 { 81 bfd_vma a1 = *(bfd_vma *) p1; 82 bfd_vma a2 = (bfd_vma) bfd_getl32 (p2); 83 bfd_size_type size 84 = (bfd_size_type) bfd_getl32 (SH64_CRANGE_CR_SIZE_OFFSET + (char *) p2); 85 86 if (a1 >= a2 + size) 87 return 1; 88 if (a1 < a2) 89 return -1; 90 return 0; 91 } 92 93 /* Check whether a specific address is specified within a .cranges 94 section. Return FALSE if not found, and TRUE if found, and the region 95 filled into RANGEP if non-NULL. */ 96 97 static bfd_boolean 98 sh64_address_in_cranges (asection *cranges, bfd_vma addr, 99 sh64_elf_crange *rangep) 100 { 101 bfd_byte *cranges_contents; 102 bfd_byte *found_rangep; 103 bfd_size_type cranges_size = cranges->size; 104 105 /* If the size is not a multiple of the cranges entry size, then 106 something is badly wrong. */ 107 if ((cranges_size % SH64_CRANGE_SIZE) != 0) 108 return FALSE; 109 110 /* If this section has relocations, then we can't do anything sane. */ 111 if (bfd_get_section_flags (cranges->owner, cranges) & SEC_RELOC) 112 return FALSE; 113 114 /* Has some kind soul (or previous call) left processed, sorted contents 115 for us? */ 116 if ((bfd_get_section_flags (cranges->owner, cranges) & SEC_IN_MEMORY) 117 && elf_section_data (cranges)->this_hdr.sh_type == SHT_SH5_CR_SORTED) 118 cranges_contents = cranges->contents; 119 else 120 { 121 if (!bfd_malloc_and_get_section (cranges->owner, cranges, 122 &cranges_contents)) 123 goto error_return; 124 125 /* Is it sorted? */ 126 if (elf_section_data (cranges)->this_hdr.sh_type 127 != SHT_SH5_CR_SORTED) 128 /* Nope. Lets sort it. */ 129 qsort (cranges_contents, cranges_size / SH64_CRANGE_SIZE, 130 SH64_CRANGE_SIZE, 131 bfd_big_endian (cranges->owner) 132 ? _bfd_sh64_crange_qsort_cmpb : _bfd_sh64_crange_qsort_cmpl); 133 134 /* Let's keep it around. */ 135 cranges->contents = cranges_contents; 136 bfd_set_section_flags (cranges->owner, cranges, 137 bfd_get_section_flags (cranges->owner, cranges) 138 | SEC_IN_MEMORY); 139 140 /* It's sorted now. */ 141 elf_section_data (cranges)->this_hdr.sh_type = SHT_SH5_CR_SORTED; 142 } 143 144 /* Try and find a matching range. */ 145 found_rangep 146 = bsearch (&addr, cranges_contents, cranges_size / SH64_CRANGE_SIZE, 147 SH64_CRANGE_SIZE, 148 bfd_big_endian (cranges->owner) 149 ? _bfd_sh64_crange_bsearch_cmpb 150 : _bfd_sh64_crange_bsearch_cmpl); 151 152 /* Fill in a few return values if we found a matching range. */ 153 if (found_rangep) 154 { 155 enum sh64_elf_cr_type cr_type 156 = bfd_get_16 (cranges->owner, 157 SH64_CRANGE_CR_TYPE_OFFSET + found_rangep); 158 bfd_vma cr_addr 159 = bfd_get_32 (cranges->owner, 160 SH64_CRANGE_CR_ADDR_OFFSET 161 + (char *) found_rangep); 162 bfd_size_type cr_size 163 = bfd_get_32 (cranges->owner, 164 SH64_CRANGE_CR_SIZE_OFFSET 165 + (char *) found_rangep); 166 167 rangep->cr_addr = cr_addr; 168 rangep->cr_size = cr_size; 169 rangep->cr_type = cr_type; 170 171 return TRUE; 172 } 173 174 /* There is a .cranges section, but it does not have a descriptor 175 matching this address. */ 176 return FALSE; 177 178 error_return: 179 if (cranges_contents != NULL) 180 free (cranges_contents); 181 return FALSE; 182 } 183 184 /* Determine what ADDR points to in SEC, and fill in a range descriptor in 185 *RANGEP if it's non-NULL. */ 186 187 enum sh64_elf_cr_type 188 sh64_get_contents_type (asection *sec, bfd_vma addr, sh64_elf_crange *rangep) 189 { 190 asection *cranges; 191 192 /* Fill in the range with the boundaries of the section as a default. */ 193 if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour 194 && elf_elfheader (sec->owner)->e_type == ET_EXEC) 195 { 196 rangep->cr_addr = bfd_get_section_vma (sec->owner, sec); 197 rangep->cr_size = sec->size; 198 rangep->cr_type = CRT_NONE; 199 } 200 else 201 return FALSE; 202 203 /* If none of the pertinent bits are set, then it's a SHcompact (or at 204 least not SHmedia). */ 205 if ((elf_section_data (sec)->this_hdr.sh_flags 206 & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)) == 0) 207 { 208 enum sh64_elf_cr_type cr_type 209 = ((bfd_get_section_flags (sec->owner, sec) & SEC_CODE) != 0 210 ? CRT_SH5_ISA16 : CRT_DATA); 211 rangep->cr_type = cr_type; 212 return cr_type; 213 } 214 215 /* If only the SHF_SH5_ISA32 bit is set, then we have SHmedia. */ 216 if ((elf_section_data (sec)->this_hdr.sh_flags 217 & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)) == SHF_SH5_ISA32) 218 { 219 rangep->cr_type = CRT_SH5_ISA32; 220 return CRT_SH5_ISA32; 221 } 222 223 /* Otherwise, we have to look up the .cranges section. */ 224 cranges = bfd_get_section_by_name (sec->owner, SH64_CRANGES_SECTION_NAME); 225 226 if (cranges == NULL) 227 /* A mixed section but there's no .cranges section. This is probably 228 bad input; it does not comply to specs. */ 229 return CRT_NONE; 230 231 /* If this call fails, we will still have CRT_NONE in rangep->cr_type 232 and that will be suitable to return. */ 233 sh64_address_in_cranges (cranges, addr, rangep); 234 235 return rangep->cr_type; 236 } 237 238 /* This is a simpler exported interface for the benefit of gdb et al. */ 239 240 bfd_boolean 241 sh64_address_is_shmedia (asection *sec, bfd_vma addr) 242 { 243 sh64_elf_crange dummy; 244 return sh64_get_contents_type (sec, addr, &dummy) == CRT_SH5_ISA32; 245 } 246