Back to index

cell-binutils  2.17cvs20070401
elf32-sh64-com.c
Go to the documentation of this file.
00001 /* SuperH SH64-specific support for 32-bit ELF
00002    Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
00003 
00004    This file is part of BFD, the Binary File Descriptor library.
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010 
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015 
00016    You should have received a copy of the GNU General Public License
00017    along with this program; if not, write to the Free Software
00018    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00019 
00020 #define SH64_ELF
00021 
00022 #include "bfd.h"
00023 #include "sysdep.h"
00024 #include "libbfd.h"
00025 #include "elf-bfd.h"
00026 #include "elf/sh.h"
00027 #include "elf32-sh64.h"
00028 #include "../opcodes/sh64-opc.h"
00029 
00030 static bfd_boolean sh64_address_in_cranges
00031   (asection *cranges, bfd_vma, sh64_elf_crange *);
00032 
00033 /* Ordering functions of a crange, for the qsort and bsearch calls and for
00034    different endianness.  */
00035 
00036 int
00037 _bfd_sh64_crange_qsort_cmpb (const void *p1, const void *p2)
00038 {
00039   bfd_vma a1 = bfd_getb32 (p1);
00040   bfd_vma a2 = bfd_getb32 (p2);
00041 
00042   /* Preserve order if there's ambiguous contents.  */
00043   if (a1 == a2)
00044     return (char *) p1 - (char *) p2;
00045 
00046   return a1 - a2;
00047 }
00048 
00049 int
00050 _bfd_sh64_crange_qsort_cmpl (const void *p1, const void *p2)
00051 {
00052   bfd_vma a1 = (bfd_vma) bfd_getl32 (p1);
00053   bfd_vma a2 = (bfd_vma) bfd_getl32 (p2);
00054 
00055   /* Preserve order if there's ambiguous contents.  */
00056   if (a1 == a2)
00057     return (char *) p1 - (char *) p2;
00058 
00059   return a1 - a2;
00060 }
00061 
00062 int
00063 _bfd_sh64_crange_bsearch_cmpb (const void *p1, const void *p2)
00064 {
00065   bfd_vma a1 = *(bfd_vma *) p1;
00066   bfd_vma a2 = (bfd_vma) bfd_getb32 (p2);
00067   bfd_size_type size
00068     = (bfd_size_type) bfd_getb32 (SH64_CRANGE_CR_SIZE_OFFSET + (char *) p2);
00069 
00070   if (a1 >= a2 + size)
00071     return 1;
00072   if (a1 < a2)
00073     return -1;
00074   return 0;
00075 }
00076 
00077 int
00078 _bfd_sh64_crange_bsearch_cmpl (const void *p1, const void *p2)
00079 {
00080   bfd_vma a1 = *(bfd_vma *) p1;
00081   bfd_vma a2 = (bfd_vma) bfd_getl32 (p2);
00082   bfd_size_type size
00083     = (bfd_size_type) bfd_getl32 (SH64_CRANGE_CR_SIZE_OFFSET + (char *) p2);
00084 
00085   if (a1 >= a2 + size)
00086     return 1;
00087   if (a1 < a2)
00088     return -1;
00089   return 0;
00090 }
00091 
00092 /* Check whether a specific address is specified within a .cranges
00093    section.  Return FALSE if not found, and TRUE if found, and the region
00094    filled into RANGEP if non-NULL.  */
00095 
00096 static bfd_boolean
00097 sh64_address_in_cranges (asection *cranges, bfd_vma addr,
00098                       sh64_elf_crange *rangep)
00099 {
00100   bfd_byte *cranges_contents;
00101   bfd_byte *found_rangep;
00102   bfd_size_type cranges_size = cranges->size;
00103 
00104   /* If the size is not a multiple of the cranges entry size, then
00105      something is badly wrong.  */
00106   if ((cranges_size % SH64_CRANGE_SIZE) != 0)
00107     return FALSE;
00108 
00109   /* If this section has relocations, then we can't do anything sane.  */
00110   if (bfd_get_section_flags (cranges->owner, cranges) & SEC_RELOC)
00111     return FALSE;
00112 
00113   /* Has some kind soul (or previous call) left processed, sorted contents
00114      for us?  */
00115   if ((bfd_get_section_flags (cranges->owner, cranges) & SEC_IN_MEMORY)
00116       && elf_section_data (cranges)->this_hdr.sh_type == SHT_SH5_CR_SORTED)
00117     cranges_contents = cranges->contents;
00118   else
00119     {
00120       if (!bfd_malloc_and_get_section (cranges->owner, cranges,
00121                                    &cranges_contents))
00122        goto error_return;
00123 
00124       /* Is it sorted?  */
00125       if (elf_section_data (cranges)->this_hdr.sh_type
00126          != SHT_SH5_CR_SORTED)
00127        /* Nope.  Lets sort it.  */
00128        qsort (cranges_contents, cranges_size / SH64_CRANGE_SIZE,
00129               SH64_CRANGE_SIZE,
00130               bfd_big_endian (cranges->owner)
00131               ? _bfd_sh64_crange_qsort_cmpb : _bfd_sh64_crange_qsort_cmpl);
00132 
00133       /* Let's keep it around.  */
00134       cranges->contents = cranges_contents;
00135       bfd_set_section_flags (cranges->owner, cranges,
00136                           bfd_get_section_flags (cranges->owner, cranges)
00137                           | SEC_IN_MEMORY);
00138 
00139       /* It's sorted now.  */
00140       elf_section_data (cranges)->this_hdr.sh_type = SHT_SH5_CR_SORTED;
00141     }
00142 
00143   /* Try and find a matching range.  */
00144   found_rangep
00145     = bsearch (&addr, cranges_contents, cranges_size / SH64_CRANGE_SIZE,
00146               SH64_CRANGE_SIZE,
00147               bfd_big_endian (cranges->owner)
00148               ? _bfd_sh64_crange_bsearch_cmpb
00149               : _bfd_sh64_crange_bsearch_cmpl);
00150 
00151   /* Fill in a few return values if we found a matching range.  */
00152   if (found_rangep)
00153     {
00154       enum sh64_elf_cr_type cr_type
00155        = bfd_get_16 (cranges->owner,
00156                     SH64_CRANGE_CR_TYPE_OFFSET + found_rangep);
00157       bfd_vma cr_addr
00158        = bfd_get_32 (cranges->owner,
00159                     SH64_CRANGE_CR_ADDR_OFFSET
00160                     + (char *) found_rangep);
00161       bfd_size_type cr_size
00162        = bfd_get_32 (cranges->owner,
00163                     SH64_CRANGE_CR_SIZE_OFFSET
00164                     + (char *) found_rangep);
00165 
00166       rangep->cr_addr = cr_addr;
00167       rangep->cr_size = cr_size;
00168       rangep->cr_type = cr_type;
00169 
00170       return TRUE;
00171     }
00172 
00173   /* There is a .cranges section, but it does not have a descriptor
00174      matching this address.  */
00175   return FALSE;
00176 
00177 error_return:
00178   if (cranges_contents != NULL)
00179     free (cranges_contents);
00180   return FALSE;
00181 }
00182 
00183 /* Determine what ADDR points to in SEC, and fill in a range descriptor in
00184    *RANGEP if it's non-NULL.  */
00185 
00186 enum sh64_elf_cr_type
00187 sh64_get_contents_type (asection *sec, bfd_vma addr, sh64_elf_crange *rangep)
00188 {
00189   asection *cranges;
00190 
00191   /* Fill in the range with the boundaries of the section as a default.  */
00192   if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour
00193       && elf_elfheader (sec->owner)->e_type == ET_EXEC)
00194     {
00195       rangep->cr_addr = bfd_get_section_vma (sec->owner, sec);
00196       rangep->cr_size = sec->size;
00197       rangep->cr_type = CRT_NONE;
00198     }
00199   else
00200     return FALSE;
00201 
00202   /* If none of the pertinent bits are set, then it's a SHcompact (or at
00203      least not SHmedia).  */
00204   if ((elf_section_data (sec)->this_hdr.sh_flags
00205        & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)) == 0)
00206     {
00207       enum sh64_elf_cr_type cr_type
00208        = ((bfd_get_section_flags (sec->owner, sec) & SEC_CODE) != 0
00209           ? CRT_SH5_ISA16 : CRT_DATA);
00210       rangep->cr_type = cr_type;
00211       return cr_type;
00212     }
00213 
00214   /* If only the SHF_SH5_ISA32 bit is set, then we have SHmedia.  */
00215   if ((elf_section_data (sec)->this_hdr.sh_flags
00216        & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)) == SHF_SH5_ISA32)
00217     {
00218       rangep->cr_type = CRT_SH5_ISA32;
00219       return CRT_SH5_ISA32;
00220     }
00221 
00222   /* Otherwise, we have to look up the .cranges section.  */
00223   cranges = bfd_get_section_by_name (sec->owner, SH64_CRANGES_SECTION_NAME);
00224 
00225   if (cranges == NULL)
00226     /* A mixed section but there's no .cranges section.  This is probably
00227        bad input; it does not comply to specs.  */
00228     return CRT_NONE;
00229 
00230   /* If this call fails, we will still have CRT_NONE in rangep->cr_type
00231      and that will be suitable to return.  */
00232   sh64_address_in_cranges (cranges, addr, rangep);
00233 
00234   return rangep->cr_type;
00235 }
00236 
00237 /* This is a simpler exported interface for the benefit of gdb et al.  */
00238 
00239 bfd_boolean
00240 sh64_address_is_shmedia (asection *sec, bfd_vma addr)
00241 {
00242   sh64_elf_crange dummy;
00243   return sh64_get_contents_type (sec, addr, &dummy) == CRT_SH5_ISA32;
00244 }