diff options
author | Alexandre Oliva <aoliva@redhat.com> | 2002-02-08 05:33:27 +0000 |
---|---|---|
committer | Alexandre Oliva <aoliva@redhat.com> | 2002-02-08 05:33:27 +0000 |
commit | fbca6ad9f37cba55a02e4df8a925b638426ed87e (patch) | |
tree | 6c96ed916b3bbff5a35996d82dc76ebca72d86b3 /bfd/elf32-sh64.c | |
parent | 61e31d88f09f2e648d05bf547cb7ef7916db37dd (diff) | |
download | gdb-fbca6ad9f37cba55a02e4df8a925b638426ed87e.zip gdb-fbca6ad9f37cba55a02e4df8a925b638426ed87e.tar.gz gdb-fbca6ad9f37cba55a02e4df8a925b638426ed87e.tar.bz2 |
Contribute sh64-elf.
2002-01-23 Alexandre Oliva <aoliva@redhat.com>
* reloc.c (R_SH_GOTPLT32, R_SH_GOT_LOW16, R_SH_GOT_MEDLOW16,
R_SH_GOT_MEDHI16, R_SH_GOT_HI16, R_SH_GOTPLT_LOW16,
R_SH_GOTPLT_MEDLOW16, R_SH_GOTPLT_MEDHI16, R_SH_GOTPLT_HI16,
R_SH_PLT_LOW16, R_SH_PLT_MEDLOW16, R_SH_PLT_MEDHI16,
R_SH_PLT_HI16, R_SH_GOTOFF_LOW16, R_SH_GOTOFF_MEDLOW16,
R_SH_GOTOFF_MEDHI16, R_SH_GOTOFF_HI16, R_SH_GOTPC_LOW16,
R_SH_GOTPC_MEDLOW16, R_SH_GOTPC_MEDHI16, R_SH_GOTPC_HI16,
R_SH_GOT10BY4, R_SH_GOTPLT10BY4, R_SH_GOT10BY8, R_SH_GOTPLT10BY8,
R_SH_COPY64, R_SH_GLOB_DAT64, R_SH_JMP_SLOT64, R_SH_RELATIVE64):
New relocs.
* libbfd.h, bfd-in2.h: Rebuilt.
* elf32-sh.c (sh_elf_howto_table): Define new relocs.
(sh_reloc_map): Map them.
(PLT_ENTRY_SIZE, elf_sh_plt0_entry_be, elf_sh_plt0_entry_le,
elf_sh_plt_entry_be, elf_sh_plt_entry_le, elf_sh_pic_plt_entry_be,
elf_sh_pic_plt_entry_le, elf_sh_plt0_entry, elf_sh_plt_entry,
elf_sh_pic_plt_entry, elf_sh_sizeof_plt, elf_sh_plt_plt0_offset,
elf_sh_plt0_gotplt_offset, elf_sh_plt_temp_offset,
elf_sh_plt_symbol_offset, elf_sh_plt_reloc_offset,
movi_shori_putval) [INCLUDE_SHMEDIA]: New.
(elf_sh_link_hash_entry) [INCLUDE_SHMEDIA]: Add
datalabel_got_offset.
(sh_elf_link_hash_newfunc): Initialize it.
(sh_elf_relocate_section): Augment the scope of
seen_stt_datalabel. Introduce GOTPLT support. Extend GOTPC, PLT,
GOT and GOTOFF handling to new SHmedia relocation types. Support
GOT_BIAS.
(sh_elf_check_relocs): Likewise.
(sh_elf_finish_dynamic_symbol) [TARGET_SHMEDIA]: Set up values in
PLT entries using movi_shori_putval. Support GOT_BIAS.
(sh_elf_finish_dynamic_sections): Likewise.
* elf32-sh64.c (shmedia_prepare_reloc): Do not add addend to
relocation, it's now done by the caller.
(GOT_BIAS): New.
* elf64-sh64.c (GOT_BIAS, PLT_ENTRY_SIZE, elf_sh64_sizeof_plt,
elf_sh64_plt_plt0_offset, elf_sh64_plt0_gotplt_offset,
elf_sh64_plt_temp_offset, elf_sh64_plt_symbol_offset,
elf_sh64_plt_reloc_offset, ELF_DYNAMIC_INTERPRETER,
elf_sh64_pcrel_relocs_copied, elf_sh64_link_hash_entry,
elf_sh64_link_hash_table, sh64_elf64_link_hash_traverse,
sh64_elf64_hash_table): New.
(sh_elf64_howto_table): Introduce new relocs.
(sh_elf64_info_to_howto): Accept new PIC relocs.
(sh_elf64_relocate_section): Augment the scope of
seen_stt_datalabel. Support new PIC relocs.
(sh_elf64_check_relocs): Support new PIC relocs.
(elf_sh64_plt0_entry_be, elf_sh64_plt0_entry_le,
elf_sh64_plt_entry_be, elf_sh64_plt_entry_le,
elf_sh64_pic_plt_entry_be, elf_sh64_pic_plt_entry_le,
elf_sh64_plt0_entry, elf_sh64_plt_entry, elf_sh64_pic_plt_entry,
sh64_elf64_link_hash_newfunc, sh64_elf64_link_hash_table_create,
movi_shori_putval, movi_3shori_putval,
sh64_elf64_create_dynamic_sections,
sh64_elf64_adjust_dynamic_symbol, sh64_elf64_discard_copies,
sh64_elf64_size_dynamic_sections,
sh64_elf64_finish_dynamic_symbol,
sh64_elf64_finish_dynamic_sections): New.
(elf_backend_create_dynamic-sections,
bfd_elf64_bfd_link_hash_table_create,
elf_backend_adjust_dynamic_symbol,
elf_backend_size_dynamic_sections,
elf_backend_finish_dynamic_symbol,
elf_backend_finish_dynamic_sections, elf_backend_want_got_plt,
elf_backend_plt_readonly, elf_backend_want_plt_sym,
elf_backend_got_header_size, elf_backend_plt_header_size):
Define.
2001-05-16 Alexandre Oliva <aoliva@redhat.com>
* elf32-sh.c: Renumbered and renamed some SH5 relocations to
match official numbers and names; moved unmaching ones to the
range 0xf2-0xff.
* elf32-sh64.c, elf64-sh64.c: Likewise.
2001-03-12 DJ Delorie <dj@redhat.com>
* elf32-sh.c (sh_elf_relax_section): Don't relax SHmedia
sections.
2001-03-12 DJ Delorie <dj@redhat.com>
* elf32-sh64.c (shmedia_prepare_reloc): Validate relocs that must
be aligned.
* elf64-sh64.c (sh_elf64_relocate_section): Ditto.
2001-01-14 Hans-Peter Nilsson <hpn@cygnus.com>
* elf32-sh64.c (bfd_elf32_bfd_copy_private_section_data): Define.
(sh64_elf_fake_sections): Set type to SHT_SH5_CR_SORTED for a
.cranges section with SEC_SORT_ENTRIES set.
(sh64_backend_section_from_shdr): Set SEC_SORT_ENTRIES on an
incoming sorted .cranges section.
(sh64_bfd_elf_copy_private_section_data): New.
(sh64_elf_final_write_processing): Only sort .cranges and modify
start address if called by linker.
2001-01-08 Ben Elliston <bje@redhat.com>
* elf32-sh64.c (sh64_elf_final_write_processing): Activate
Hans-Peter Nilsson's set bit 0 patch from 2001-01-06.
* elf64-sh64.c (sh64_elf64_final_write_processing): Ditto.
2001-01-06 Hans-Peter Nilsson <hpn@cygnus.com>
* elf64-sh64.c (sh_elf64_howto_table): No open brace at start of
line. Add comments before all entries.
<R_SH_PT_16, R_SH_SHMEDIA_CODE>: Correct and clarify describing
comment.
(sh_elf64_reloc): Correct head comment.
(sh_elf64_relocate_section): Correct spacing.
<relocating for a local symbol>: Do not honour STO_SH5_ISA32;
instead call reloc_dangerous callback.
<case R_SH_SHMEDIA_CODE>: New case.
(sh_elf64_gc_mark_hook): Correct spacing.
(sh_elf64_check_relocs): Ditto.
* elf32-sh64.c (shmedia_prepare_reloc) <case R_SH_SHMEDIA_CODE>:
New case.
* elf32-sh.c: Correct #endif comments for #ifndef-wrapped
functions.
(sh_elf_howto_table) <R_SH_PT_16, R_SH_SHMEDIA_CODE>: Correct,
clarify describing comment. Add comments before all entries.
(sh_elf_relocate_section) <relocating for a local symbol>: Do not
honour STO_SH5_ISA32; instead call reloc_dangerous callback.
2001-01-06 Hans-Peter Nilsson <hpn@cygnus.com>
Sort .cranges section in final link. Prepare to set bit 0 on
entry address.
* elf32-sh64.c (struct sh64_find_section_vma_data): New.
(sh64_elf_link_output_symbol_hook): Fix typo in prototype.
(sh64_elf_set_mach_from_flags): Set SEC_DEBUGGING on incoming
.cranges section.
(sh64_backend_section_from_shdr): New, to recognize
SHT_SH5_CR_SORTED on incoming .cranges section.
(elf_backend_section_from_shdr): Define.
(sh64_elf_final_write_processing): Sort outgoing .cranges
section. (New, temporarily disabled:) Set bit 0 on entry address
according to ISA type.
(sh64_find_section_for_address): New.
(crange_qsort_cmpb, crange_qsort_cmpl, crange_bsearch_cmpb,
crange_bsearch_cmpl): Move here from opcodes/sh64-dis.c.
(sh64_address_in_cranges): Move here from opcodes/sh64-dis.c. Use
bfd_malloc, not xmalloc.
(sh64_get_contents_type): Move here from opcodes/sh64-dis.c. Make
global.
* elf32-sh64.c (sh64_elf64_final_write_processing): New, (but
temporarily disabled) setting bit 0 on entry address.
(elf_backend_final_write_processing): Define.
2001-01-05 Hans-Peter Nilsson <hpn@cygnus.com>
* elf32-sh.c (sh_elf_howto_table) <R_SH_PT_16>: Adjust fields to
be a proper relocation for PTA and PTB rather than a marker.
<R_SH_IMMU5, R_SH_IMMS6, R_SH_IMMU6, R_SH_IMMS10, R_SH_IMMS10BY2,
R_SH_IMMS10BY4, R_SH_IMMS10BY8, R_SH_IMMS16, R_SH_IMMU16,
R_SH_IMM_LOW16, R_SH_IMM_LOW16_PCREL, R_SH_IMM_MEDLOW16,
R_SH_IMM_MEDLOW16_PCREL, R_SH_IMM_MEDHI16, R_SH_IMM_MEDHI16_PCREL,
R_SH_IMM_HI16, R_SH_IMM_HI16_PCREL, R_SH_64, R_SH_64_PCREL>:
Zero src_mask.
* elf64-sh64.c: Ditto.
(sh_elf64_relocate_section) <case R_SH_PT_16>: New case.
* elf32-sh64.c: Include opcodes/sh64-opc.h
(shmedia_prepare_reloc): Take a bfd_link_info pointer as first
argument. Drop const qualifiers from "bfd *" and "bfd_byte *"
parameters. No unused parameters. Caller changed.
<case R_SH_PT_16>: New case.
* Makefile.am (elf32-sh64.lo): Add dependency on sh64-opc.h.
* Makefile.in: Regenerate.
2000-12-30 Hans-Peter Nilsson <hpn@cygnus.com>
* elf64-sh64.c (sh64_elf64_fake_sections): Set SHF_SH5_ISA32 for
all code sections.
(sh_elf64_set_mach_from_flags): Change from EF_SH64 to EF_SH5.
(sh64_elf_merge_private_data): Ditto.
* elf32-sh64.c (sh64_elf_fake_sections): Use sh64_elf_section_data
to access stored section flags.
(sh64_elf_final_write_processing): Return immediately unless
called by linker. Use sh64_elf_section_data (cranges) to get size
of linker-generated cranges entries.
(sh64_elf_copy_private_data): Add missing "return true".
(sh64_elf_set_mach_from_flags): Change from EF_SH64 to EF_SH5.
(sh_elf64_merge_private_data): Ditto.
2000-12-19 Hans-Peter Nilsson <hpn@cygnus.com>
* elf64-sh64.c (sh64_elf64_fake_sections): New, copy of
elf64-sh64.c:sh64_elf_fake_sections.
(elf_backend_fake_sections): Define as sh64_elf64_fake_sections.
2000-12-18 Hans-Peter Nilsson <hpn@cygnus.com>
* elf32-sh64.c (sh64_elf_copy_private_data_internal): Delete.
(sh64_elf_final_write_processing): New.
(elf_backend_final_write_processing): Define.
(sh64_elf_fake_sections): Get header flags from tdata field.
(sh64_elf_copy_private_data): Do not call
sh64_elf_copy_private_data_internal, just copy e_flags field.
(sh64_elf_merge_private_data): Do not call
sh64_elf_copy_private_data_internal.
2000-12-12 Hans-Peter Nilsson <hpn@cygnus.com>
Remove EF_SH64_ABI64, let ELF size make difference.
Remove SH64-specific BFD section flag.
* elf32-sh64.c (sh64_elf_fake_sections): Recognize section as
containing SHmedia through elf_section_data (asect)->tdata
non-zero, not using a BFD section flag.
(sh64_elf_set_mach_from_flags): Don't recognize EF_SH64_ABI64.
(sh64_elf_merge_private_data): Similar.
(elf_backend_section_flags): Don't define.
(sh64_elf_backend_section_flags): Delete.
* elf64-sh64.c (sh_elf64_set_mach_from_flags): Recognize EF_SH64,
not EF_SH64_ABI64.
(sh_elf64_merge_private_data): Similar.
* section.c (Section flags definitions): Don't define
SEC_SH_ISA_SHMEDIA.
(bfd-in2.h): Regenerate.
2000-12-09 Hans-Peter Nilsson <hpn@cygnus.com>
Make DataLabel references work with partial linking.
* elf32-sh64.c: Fix formatting.
(sh64_elf_link_output_symbol_hook): New.
(elf_backend_link_output_symbol_hook): Define to
sh64_elf_link_output_symbol_hook.
(sh64_elf_add_symbol_hook): Make DataLabel symbol just global
undefined if partial linking. Adjust sanity check.
* elf64-sh64.c (sh64_elf64_link_output_symbol_hook): New.
(elf_backend_link_output_symbol_hook): Define to
sh64_elf64_link_output_symbol_hook.
(sh64_elf64_add_symbol_hook): Make DataLabel symbol just global
undefined if partial linking. Adjust sanity check.
2000-12-07 Hans-Peter Nilsson <hpn@cygnus.com>
Implement semantics for inter-file DataLabel references.
* elf64-sh64.c (DATALABEL_SUFFIX): Define.
(sh64_elf64_add_symbol_hook): New.
(sh_elf64_relocate_section): If passing an indirect symbol with
st_type STT_DATALABEL on the way to a symbol with st_other
STO_SH5_ISA32, do not bitor 1 to the relocation.
(elf_backend_add_symbol_hook): Define to
sh64_elf64_add_symbol_hook.
* elf64-sh32.c: Tweak comments.
(DATALABEL_SUFFIX): Define.
(sh64_elf_add_symbol_hook): New.
(elf_backend_add_symbol_hook): Define to sh64_elf_add_symbol_hook.
* elf32-sh.c (sh_elf_relocate_section): If passing an indirect
symbol with st_type STT_DATALABEL on the way to a symbol with
st_other STO_SH5_ISA32, do not bitor 1 to the relocation.
2000-12-05 Hans-Peter Nilsson <hpn@cygnus.com>
Pass through STT_DATALABEL.
* elf32-sh64.c (sh64_elf_get_symbol_type): New.
(elf_backend_get_symbol_type): Define.
* elf64-sh64.c (sh64_elf64_get_symbol_type): New.
(elf_backend_get_symbol_type): Define.
2000-11-30 Hans-Peter Nilsson <hpn@cygnus.com>
* elf32-sh64.c: Tweak comments.
(sh64_elf_copy_private_data_internal): Add prototype.
(bfd_elf32_bfd_set_private_flags): Define.
(sh64_elf_copy_private_data_internal): Compare machine name, not
textual BFD target name, to check whether to copy section flag
SHF_SH5_ISA32.
(sh64_elf_merge_private_data): Validize bfd_get_arch_size.
Tweak section-contents-type-mismatch message.
(shmedia_prepare_reloc): Add ATTRIBUTE_UNUSED markers.
Validize reloc-types.
* elf64-sh64.c: New file.
* targets.c (bfd_elf64_sh64_vec, bfd_elf64_sh64l_vec): Declare.
* Makefile.am (BFD64_BACKENDS): Add elf64-sh64.lo.
(BFD64_BACKENDS_CFILES): Add elf64-sh64.c.
Regenerate dependencies.
* Makefile.in: Regenerate.
* config.bfd (sh64-*-elf*): Add bfd_elf64_sh64_vec and
bfd_elf64_sh64l_vec.
* configure.in: Handle bfd_elf64_sh64_vec and
bfd_elf64_sh64l_vec.
* configure: Regenerate.
* po/POTFILES.in: Regenerate.
* po/bfd.pot: Regenerate.
2000-11-29 Hans-Peter Nilsson <hpn@cygnus.com>
* elf32-sh64.c (sh64_elf_set_mach_from_flags): Do not recognize
anything else but EF_SH64 and EF_SH64_ABI64.
(sh64_elf_merge_private_data): Emit error for anything else but
EF_SH64 and EF_SH64_ABI64.
* config.bfd: Remove bfd_elf32_shblin_vec and bfd_elf32_shlin_vec
from targ_selvecs.
* configure.in: Add cofflink.lo to bfd_elf32_sh64_vec and
bfd_elf32_sh64l_vec as a temporary measure.
* configure: Regenerate.
2000-11-27 Hans-Peter Nilsson <hpn@cygnus.com>
* cpu-sh.c (arch_info_struct): Include sh5 item
unconditionalized.
* config.bfd (sh64-*-elf*): Do not set targ_cflags.
Add targ_selvecs bfd_elf32_sh_vec, bfd_elf32_shl_vec,
bfd_elf32_shblin_vec and bfd_elf32_shlin_vec.
* elf32-sh64.c: Tweak comments.
(sh64_elf_set_mach_from_flags): Recognize all machine flags that
are proper subsets of SH64 as bfd_mach_sh5. Add EF_SH64_ABI64.
(sh64_elf_copy_private_data_internal): Wrap long line.
(sh64_elf_merge_private_data): Rewrite to allow objects from
SH64 subsets to be linked together.
(INCLUDE_SHMEDIA): Define.
* elf32-sh.c (sh_elf_relocate_section) <local symbol>:
Parenthesize plus-expression inside or-expression.
<global symbol>: Ditto.
(sh_elf_set_mach_from_flags): Remove code refusing
deleted EF_SH64_32BIT_ABI flag.
2000-11-26 Hans-Peter Nilsson <hpn@cygnus.com>
* elf32-sh.c (sh_elf_howto_table) <R_SH_IMM_LOW16_PCREL,
R_SH_IMM_MEDLOW16_PCREL, R_SH_IMM_MEDHI16_PCREL,
R_SH_IMM_HI16_PCREL, R_SH_64_PCREL>: Set pcrel_offset to true.
(sh_elf_relocate_section) <local symbol>: Or 1 in
calculation of relocation if sym->st_other & STO_SH5_ISA32.
<global symbol>: Ditto if h->other & STO_SH5_ISA32.
* elf32-sh64.c (shmedia_prepare_reloc): Add rel->r_addend to
relocation.
2000-11-24 Hans-Peter Nilsson <hpn@cygnus.com>
* Makefile.am (BFD32_BACKENDS): Add elf32-sh64.lo.
(BFD32_BACKENDS_CFILES): Add elf32-sh64.c.
Regenerate dependencies.
* Makefile.in: Regenerate.
* archures.c: Add bfd_mach_sh5.
* config.bfd: Map targ_cpu sh* to bfd_sh_arch.
Handle sh64-*-elf*. Set targ_cflags to -DINCLUDE_SHMEDIA.
* configure.in: Handle bfd_elf32_sh64_vec and bfd_elf32_sh64l_vec.
* configure: Regenerate.
* reloc.c (BFD_RELOC_SH_SHMEDIA_CODE, BFD_RELOC_SH_IMMU5,
BFD_RELOC_SH_IMMS6, BFD_RELOC_SH_IMMS6BY32, BFD_RELOC_SH_IMMU6,
BFD_RELOC_SH_IMMS10, BFD_RELOC_SH_IMMS10BY2,
BFD_RELOC_SH_IMMS10BY4, BFD_RELOC_SH_IMMS10BY8,
BFD_RELOC_SH_IMMS16, BFD_RELOC_SH_IMMU16, BFD_RELOC_SH_IMM_LOW16,
BFD_RELOC_SH_IMM_LOW16_PCREL, BFD_RELOC_SH_IMM_MEDLOW16,
BFD_RELOC_SH_IMM_MEDLOW16_PCREL, BFD_RELOC_SH_IMM_MEDHI16,
BFD_RELOC_SH_IMM_MEDHI16_PCREL, BFD_RELOC_SH_IMM_HI16,
BFD_RELOC_SH_IMM_HI16_PCREL, BFD_RELOC_SH_PT_16): New relocations.
* cpu-sh.c [INCLUDE_SHMEDIA] (arch_info_struct): Define and link
in item for SH5.
* elf32-sh.c [INCLUDE_SHMEDIA] (sh_elf_howto_table): Add howto items
for SHmedia relocs.
[INCLUDE_SHMEDIA] (sh_rel): Add mappings for SHmedia relocs.
[INCLUDE_SHMEDIA] (sh_elf_relocate_section) [default]: Call
shmedia_prepare_reloc, goto final_link_relocate if it returns
non-zero, else fail as before.
(sh_elf_set_mach_from_flags): Provide function only if not defined
as macro. Do not recognize objects with EF_SH64_32BIT_ABI set.
(sh_elf_set_private_flags): Provide function only if not defined
as a macro.
(sh_elf_copy_private_data): Similar.
(sh_elf_merge_private_data): Similar.
* section.c (SEC_SH_ISA_SHMEDIA): New.
* targets.c (bfd_elf32_sh64_vec, bfd_elf32_sh64l_vec): Declare.
* elf32-sh64.c: New file.
* libbfd.h: Regenerate.
* bfd-in2.h: Regenerate.
* po/POTFILES.in: Regenerate.
* po/bfd.pot: Regenerate.
* bfd-in2.h: Regenerate.
* libbfd.h: Regenerate.
Diffstat (limited to 'bfd/elf32-sh64.c')
-rw-r--r-- | bfd/elf32-sh64.c | 983 |
1 files changed, 983 insertions, 0 deletions
diff --git a/bfd/elf32-sh64.c b/bfd/elf32-sh64.c new file mode 100644 index 0000000..561c7af --- /dev/null +++ b/bfd/elf32-sh64.c @@ -0,0 +1,983 @@ +/* Hitachi SH64-specific support for 32-bit ELF + Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define SH64_ELF + +#include "bfd.h" +#include "sysdep.h" +#include "elf-bfd.h" +#include "../opcodes/sh64-opc.h" + +/* Add a suffix for datalabel indirection symbols. It must not match any + other symbols; user symbols with or without version or other + decoration. It must only be used internally and not emitted by any + means. */ +#define DATALABEL_SUFFIX " DL" + +/* Used to hold data for function called through bfd_map_over_sections. */ +struct sh64_find_section_vma_data + { + asection *section; + bfd_vma addr; + }; + +static boolean sh64_elf_copy_private_data PARAMS ((bfd *, bfd *)); +static boolean sh64_elf_merge_private_data PARAMS ((bfd *, bfd *)); +static boolean sh64_elf_fake_sections PARAMS ((bfd *, Elf_Internal_Shdr *, + asection *)); +static boolean sh64_elf_set_private_flags PARAMS ((bfd *, flagword)); +static boolean sh64_elf_set_mach_from_flags PARAMS ((bfd *)); +static boolean shmedia_prepare_reloc + PARAMS ((struct bfd_link_info *, bfd *, asection *, + bfd_byte *, const Elf_Internal_Rela *, bfd_vma *)); +static int sh64_elf_get_symbol_type PARAMS ((Elf_Internal_Sym *, int)); +static boolean sh64_elf_add_symbol_hook + PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Sym *, + const char **, flagword *, asection **, bfd_vma *)); +static boolean sh64_elf_link_output_symbol_hook + PARAMS ((bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *, + asection *)); +static boolean sh64_backend_section_from_shdr + PARAMS ((bfd *, Elf_Internal_Shdr *, char *)); +static void sh64_elf_final_write_processing PARAMS ((bfd *, boolean)); +static boolean sh64_bfd_elf_copy_private_section_data + PARAMS ((bfd *, asection *, bfd *, asection *)); + +/* Let elf32-sh.c handle the "bfd_" definitions, so we only have to + intrude with an #ifndef around the function definition. */ +#define sh_elf_copy_private_data sh64_elf_copy_private_data +#define sh_elf_merge_private_data sh64_elf_merge_private_data +#define sh_elf_set_private_flags sh64_elf_set_private_flags +/* Typo in elf32-sh.c (and unlinear name). */ +#define bfd_elf32_bfd_set_private_flags sh64_elf_set_private_flags +#define sh_elf_set_mach_from_flags sh64_elf_set_mach_from_flags + +#define elf_backend_sign_extend_vma 1 +#define elf_backend_fake_sections sh64_elf_fake_sections +#define elf_backend_get_symbol_type sh64_elf_get_symbol_type +#define elf_backend_add_symbol_hook sh64_elf_add_symbol_hook +#define elf_backend_link_output_symbol_hook \ + sh64_elf_link_output_symbol_hook +#define elf_backend_final_write_processing sh64_elf_final_write_processing +#define elf_backend_section_from_shdr sh64_backend_section_from_shdr + +/* For objcopy, we need to set up sh64_elf_section_data (asection *) from + incoming section flags. This is otherwise done in sh64elf.em when + linking or tc-sh64.c when assembling. */ +#define bfd_elf32_bfd_copy_private_section_data \ + sh64_bfd_elf_copy_private_section_data + +/* This COFF-only function (only compiled with COFF support, making + ELF-only chains problematic) returns true early for SH4, so let's just + define it true here. */ +#define _bfd_sh_align_load_span(a,b,c,d,e,f,g,h,i,j) true + +#ifndef ELF_ARCH +#define TARGET_BIG_SYM bfd_elf32_sh64_vec +#define TARGET_BIG_NAME "elf32-sh64" +#define TARGET_LITTLE_SYM bfd_elf32_sh64l_vec +#define TARGET_LITTLE_NAME "elf32-sh64l" +#define ELF_ARCH bfd_arch_sh +#define ELF_MACHINE_CODE EM_SH +#define ELF_MAXPAGESIZE 128 + +#define elf_symbol_leading_char '_' +#endif /* ELF_ARCH */ + +#define GOT_BIAS (-((long)-32768)) +#define INCLUDE_SHMEDIA +#include "elf32-sh.c" + +/* The type sh64_elf_crange is defined in elf/sh.h which is included in + elf32-sh.c, hence these prototypes located after including it. */ +static int crange_qsort_cmpb PARAMS ((const void *, const void *)); +static int crange_qsort_cmpl PARAMS ((const void *, const void *)); +static int crange_bsearch_cmpb PARAMS ((const void *, const void *)); +static int crange_bsearch_cmpl PARAMS ((const void *, const void *)); +static boolean sh64_address_in_cranges + PARAMS ((asection *cranges, bfd_vma, sh64_elf_crange *)); + +/* Set the SHF_SH5_ISA32 flag for ISA SHmedia code sections, and pass + through SHT_SH5_CR_SORTED on a sorted .cranges section. */ + +boolean +sh64_elf_fake_sections (output_bfd, elf_section_hdr, asect) + bfd *output_bfd ATTRIBUTE_UNUSED; + Elf_Internal_Shdr *elf_section_hdr; + asection *asect; +{ + if (sh64_elf_section_data (asect) != NULL) + elf_section_hdr->sh_flags + |= sh64_elf_section_data (asect)->contents_flags; + + /* If this section has the SEC_SORT_ENTRIES flag set, it is a sorted + .cranges section passing through objcopy. */ + if ((bfd_get_section_flags (output_bfd, asect) & SEC_SORT_ENTRIES) != 0 + && strcmp (bfd_get_section_name (output_bfd, asect), + SH64_CRANGES_SECTION_NAME) == 0) + elf_section_hdr->sh_type = SHT_SH5_CR_SORTED; + + return true; +} + +static boolean +sh64_elf_set_mach_from_flags (abfd) + bfd *abfd; +{ + flagword flags = elf_elfheader (abfd)->e_flags; + asection *cranges; + + switch (flags & EF_SH_MACH_MASK) + { + case EF_SH5: + /* These are fit to execute on SH5. Just one but keep the switch + construct to make additions easy. */ + bfd_default_set_arch_mach (abfd, bfd_arch_sh, bfd_mach_sh5); + break; + + default: + bfd_set_error (bfd_error_wrong_format); + return false; + } + + /* We also need to set SEC_DEBUGGING on an incoming .cranges section. + We could have used elf_backend_section_flags if it had given us the + section name; the bfd_section member in the header argument is not + set at the point of the call. FIXME: Find out whether that is by + undocumented design or a bug. */ + cranges = bfd_get_section_by_name (abfd, SH64_CRANGES_SECTION_NAME); + if (cranges != NULL + && ! bfd_set_section_flags (abfd, cranges, + bfd_get_section_flags (abfd, cranges) + | SEC_DEBUGGING)) + return false; + + return true; +} + +static boolean +sh64_elf_copy_private_data (ibfd, obfd) + bfd * ibfd; + bfd * obfd; +{ + if ( bfd_get_flavour (ibfd) != bfd_target_elf_flavour + || bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return true; + + BFD_ASSERT (!elf_flags_init (obfd) + || (elf_elfheader (obfd)->e_flags + == elf_elfheader (ibfd)->e_flags)); + + elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; + return true; +} + +static boolean +sh64_elf_merge_private_data (ibfd, obfd) + bfd *ibfd; + bfd *obfd; +{ + flagword old_flags, new_flags; + + if (_bfd_generic_verify_endian_match (ibfd, obfd) == false) + return false; + + if ( bfd_get_flavour (ibfd) != bfd_target_elf_flavour + || bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return true; + + if (bfd_get_arch_size (ibfd) != bfd_get_arch_size (obfd)) + { + const char *msg; + + if (bfd_get_arch_size (ibfd) == 32 + && bfd_get_arch_size (obfd) == 64) + msg = _("%s: compiled as 32-bit object and %s is 64-bit"); + else if (bfd_get_arch_size (ibfd) == 64 + && bfd_get_arch_size (obfd) == 32) + msg = _("%s: compiled as 64-bit object and %s is 32-bit"); + else + msg = _("%s: object size does not match that of target %s"); + + (*_bfd_error_handler) (msg, bfd_get_filename (ibfd), + bfd_get_filename (obfd)); + bfd_set_error (bfd_error_wrong_format); + return false; + } + + old_flags = elf_elfheader (obfd)->e_flags; + new_flags = elf_elfheader (ibfd)->e_flags; + if (! elf_flags_init (obfd)) + { + /* This happens when ld starts out with a 'blank' output file. */ + elf_flags_init (obfd) = true; + elf_elfheader (obfd)->e_flags = old_flags = new_flags; + } + /* We don't allow linking in non-SH64 code. */ + else if ((new_flags & EF_SH_MACH_MASK) != EF_SH5) + { + (*_bfd_error_handler) + ("%s: uses non-SH64 instructions while previous modules use SH64 instructions", + bfd_get_filename (ibfd)); + bfd_set_error (bfd_error_bad_value); + return false; + } + + /* I can't think of anything sane other than old_flags being EF_SH5 and + that we need to preserve that. */ + elf_elfheader (obfd)->e_flags = old_flags; + return sh64_elf_set_mach_from_flags (obfd); +} + +/* Handle a SH64-specific section when reading an object file. This + is called when elfcode.h finds a section with an unknown type. + + We only recognize SHT_SH5_CR_SORTED, on the .cranges section. */ + +boolean +sh64_backend_section_from_shdr (abfd, hdr, name) + bfd *abfd; + Elf_Internal_Shdr *hdr; + char *name; +{ + flagword flags = 0; + + /* We do like MIPS with a bit switch for recognized types, and returning + false for a recognized section type with an unexpected name. Right + now we only have one recognized type, but that might change. */ + switch (hdr->sh_type) + { + case SHT_SH5_CR_SORTED: + if (strcmp (name, SH64_CRANGES_SECTION_NAME) != 0) + return false; + + /* We set the SEC_SORT_ENTRIES flag so it can be passed on to + sh64_elf_fake_sections, keeping SHT_SH5_CR_SORTED if this object + passes through objcopy. Perhaps it is brittle; the flag can + suddenly be used by other BFD parts, but it seems not really used + anywhere at the moment. */ + flags = SEC_DEBUGGING | SEC_SORT_ENTRIES; + break; + + default: + return false; + } + + if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name)) + return false; + + if (flags + && ! bfd_set_section_flags (abfd, hdr->bfd_section, + bfd_get_section_flags (abfd, + hdr->bfd_section) + | flags)) + return false; + + return true; +} + +/* In contrast to sh64_backend_section_from_shdr, this is called for all + sections, but only when copying sections, not when linking or + assembling. We need to set up the sh64_elf_section_data (asection *) + structure for the SH64 ELF section flags to be copied correctly. */ + +boolean +sh64_bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec) + bfd *ibfd; + asection *isec; + bfd *obfd; + asection *osec; +{ + struct sh64_section_data *sh64_sec_data; + + if (ibfd->xvec->flavour != bfd_target_elf_flavour + || obfd->xvec->flavour != bfd_target_elf_flavour) + return true; + + if (! _bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec)) + return false; + + sh64_sec_data = sh64_elf_section_data (isec); + if (sh64_sec_data == NULL) + { + sh64_sec_data = bfd_zmalloc (sizeof (struct sh64_section_data)); + + if (sh64_sec_data == NULL) + return false; + + sh64_sec_data->contents_flags + = (elf_section_data (isec)->this_hdr.sh_flags + & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)); + + sh64_elf_section_data (osec) = sh64_sec_data; + } + + return true; +} + +/* Function to keep SH64 specific file flags. */ + +static boolean +sh64_elf_set_private_flags (abfd, flags) + bfd * abfd; + flagword flags; +{ + BFD_ASSERT (! elf_flags_init (abfd) + || elf_elfheader (abfd)->e_flags == flags); + + elf_elfheader (abfd)->e_flags = flags; + elf_flags_init (abfd) = true; + return sh64_elf_set_mach_from_flags (abfd); +} + +/* Called when writing out an object file to decide the type of a symbol. */ + +static int +sh64_elf_get_symbol_type (elf_sym, type) + Elf_Internal_Sym * elf_sym; + int type; +{ + if (ELF_ST_TYPE (elf_sym->st_info) == STT_DATALABEL) + return STT_DATALABEL; + + return type; +} + +/* Hook called by the linker routine which adds symbols from an object + file. We must make indirect symbols for undefined symbols marked with + STT_DATALABEL, so relocations passing them will pick up that attribute + and neutralize STO_SH5_ISA32 found on the symbol definition. + + There is a problem, though: We want to fill in the hash-table entry for + this symbol and signal to the caller that no further processing is + needed. But we don't have the index for this hash-table entry. We + rely here on that the current entry is the first hash-entry with NULL, + which seems brittle. Also, iterating over the hash-table to find that + entry is a linear operation on the number of symbols in this input + file, and this function should take constant time, so that's not good + too. Only comfort is that DataLabel references should only be found in + hand-written assembly code and thus be rare. FIXME: Talk maintainers + into adding an option to elf_add_symbol_hook (preferably) for the index + or the hash entry, alternatively adding the index to Elf_Internal_Sym + (not so good). */ + +static boolean +sh64_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp) + bfd *abfd; + struct bfd_link_info *info; + const Elf_Internal_Sym *sym; + const char **namep; + flagword *flagsp ATTRIBUTE_UNUSED; + asection **secp; + bfd_vma *valp; +{ + /* We want to do this for relocatable as well as final linking. */ + if (ELF_ST_TYPE (sym->st_info) == STT_DATALABEL) + { + struct elf_link_hash_entry *h; + + /* For relocateable links, we register the DataLabel sym in its own + right, and tweak the name when it's output. Otherwise, we make + an indirect symbol of it. */ + flagword flags + = info->relocateable || info->emitrelocations + ? BSF_GLOBAL : BSF_GLOBAL | BSF_INDIRECT; + + char *dl_name + = bfd_malloc (strlen (*namep) + sizeof (DATALABEL_SUFFIX)); + struct elf_link_hash_entry ** sym_hash = elf_sym_hashes (abfd); + + BFD_ASSERT (sym_hash != NULL); + + /* Allocation may fail. */ + if (dl_name == NULL) + return false; + + strcpy (dl_name, *namep); + strcat (dl_name, DATALABEL_SUFFIX); + + h = (struct elf_link_hash_entry *) + bfd_link_hash_lookup (info->hash, dl_name, false, false, false); + + if (h == NULL) + { + /* No previous datalabel symbol. Make one. */ + if (! _bfd_generic_link_add_one_symbol (info, abfd, dl_name, + flags, *secp, *valp, + *namep, false, + get_elf_backend_data (abfd)->collect, + (struct bfd_link_hash_entry **) &h)) + { + free (dl_name); + return false; + } + + h->elf_link_hash_flags &=~ ELF_LINK_NON_ELF; + h->type = STT_DATALABEL; + } + else + /* If a new symbol was created, it holds the allocated name. + Otherwise, we don't need it anymore and should deallocate it. */ + free (dl_name); + + if (h->type != STT_DATALABEL + || ((info->relocateable || info->emitrelocations) + && h->root.type != bfd_link_hash_undefined) + || (! info->relocateable && !info->emitrelocations + && h->root.type != bfd_link_hash_indirect)) + { + /* Make sure we don't get confused on invalid input. */ + (*_bfd_error_handler) + (_("%s: encountered datalabel symbol in input"), + bfd_get_filename (abfd)); + bfd_set_error (bfd_error_bad_value); + return false; + } + + /* Now find the hash-table slot for this entry and fill it in. */ + while (*sym_hash != NULL) + sym_hash++; + *sym_hash = h; + + /* Signal to caller to skip this symbol - we've handled it. */ + *namep = NULL; + } + + return true; +} + +/* This hook function is called before the linker writes out a global + symbol. For relocatable links, DataLabel symbols will be present in + linker output. We cut off the special suffix on those symbols, so the + right name appears in the output. + + When linking and emitting relocations, there can appear global symbols + that are not referenced by relocs, but rather only implicitly through + DataLabel references, a relation that is not visible to the linker. + Since no stripping of global symbols in done when doing such linking, + we don't need to look up and make sure to emit the main symbol for each + DataLabel symbol. */ + +boolean +sh64_elf_link_output_symbol_hook (abfd, info, cname, sym, input_sec) + bfd *abfd ATTRIBUTE_UNUSED; + struct bfd_link_info *info; + const char *cname; + Elf_Internal_Sym *sym; + asection *input_sec ATTRIBUTE_UNUSED; +{ + char *name = (char *) cname; + + if (info->relocateable || info->emitrelocations) + { + if (ELF_ST_TYPE (sym->st_info) == STT_DATALABEL) + name[strlen (name) - strlen (DATALABEL_SUFFIX)] = 0; + } + + return true; +} + +/* Check a SH64-specific reloc and put the value to relocate to into + RELOCATION, ready to pass to _bfd_final_link_relocate. Return FALSE if + bad value, TRUE if ok. */ + +static boolean +shmedia_prepare_reloc (info, abfd, input_section, + contents, rel, relocation) + struct bfd_link_info *info; + bfd *abfd; + asection *input_section; + bfd_byte *contents; + const Elf_Internal_Rela *rel; + bfd_vma *relocation; +{ + bfd_vma disp, dropped; + + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_SH_PT_16: + /* Check the lowest bit of the destination field. If it is 1, we + check the ISA type of the destination (i.e. the low bit of the + "relocation" value, and emit an error if the instruction does not + match). If it is 0, we change a PTA to PTB. There should never + be a PTB that should change to a PTA; that indicates a toolchain + error; a mismatch with GAS. */ + { + char *msg = NULL; + bfd_vma insn = bfd_get_32 (abfd, contents + rel->r_offset); + + if (insn & (1 << 10)) + { + /* Check matching insn and ISA (address of target). */ + if ((insn & SHMEDIA_PTB_BIT) != 0 + && ((*relocation + rel->r_addend) & 1) != 0) + msg = _("PTB mismatch: a SHmedia address (bit 0 == 1)"); + else if ((insn & SHMEDIA_PTB_BIT) == 0 + && ((*relocation + rel->r_addend) & 1) == 0) + msg = _("PTA mismatch: a SHcompact address (bit 0 == 0)"); + + if (msg != NULL + && ! ((*info->callbacks->reloc_dangerous) + (info, msg, abfd, input_section, + rel->r_offset))) + return false; + } + else + { + /* We shouldn't get here with a PTB insn and a R_SH_PT_16. It + means GAS output does not match expectations; a PTA or PTB + expressed as such (or a PT found at assembly to be PTB) + would match the test above, and PT expansion with an + unknown destination (or when relaxing) will get us here. */ + if ((insn & SHMEDIA_PTB_BIT) != 0) + { + (*_bfd_error_handler) + (_("%s: GAS error: unexpected PTB insn with R_SH_PT_16"), + bfd_get_filename (input_section->owner)); + return false; + } + + /* Change the PTA to a PTB, if destination indicates so. */ + if (((*relocation + rel->r_addend) & 1) == 0) + bfd_put_32 (abfd, insn | SHMEDIA_PTB_BIT, + contents + rel->r_offset); + } + } + + case R_SH_SHMEDIA_CODE: + case R_SH_DIR5U: + case R_SH_DIR6S: + case R_SH_DIR6U: + case R_SH_DIR10S: + case R_SH_DIR10SW: + case R_SH_DIR10SL: + case R_SH_DIR10SQ: + case R_SH_IMMS16: + case R_SH_IMMU16: + case R_SH_IMM_LOW16: + case R_SH_IMM_LOW16_PCREL: + case R_SH_IMM_MEDLOW16: + case R_SH_IMM_MEDLOW16_PCREL: + case R_SH_IMM_MEDHI16: + case R_SH_IMM_MEDHI16_PCREL: + case R_SH_IMM_HI16: + case R_SH_IMM_HI16_PCREL: + case R_SH_64: + case R_SH_64_PCREL: + break; + + default: + return false; + } + + disp = (*relocation & 0xf); + dropped = 0; + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_SH_DIR10SW: dropped = disp & 1; break; + case R_SH_DIR10SL: dropped = disp & 3; break; + case R_SH_DIR10SQ: dropped = disp & 7; break; + } + if (dropped != 0) + { + (*_bfd_error_handler) + (_("%s: error: unaligned relocation type %d at %08x reloc %08x\n"), + bfd_get_filename (input_section->owner), ELF32_R_TYPE (rel->r_info), + (unsigned)rel->r_offset, (unsigned)relocation); + return false; + } + + return true; +} + +/* Helper function to locate the section holding a certain address. This + is called via bfd_map_over_sections. */ + +static void +sh64_find_section_for_address (abfd, section, data) + bfd *abfd ATTRIBUTE_UNUSED; + asection *section; + PTR data; +{ + bfd_vma vma; + bfd_size_type size; + struct sh64_find_section_vma_data *fsec_datap + = (struct sh64_find_section_vma_data *) data; + + /* Return if already found. */ + if (fsec_datap->section) + return; + + /* If this section isn't part of the addressable contents, skip it. */ + if ((bfd_get_section_flags (abfd, section) & SEC_ALLOC) == 0) + return; + + vma = bfd_get_section_vma (abfd, section); + if (fsec_datap->addr < vma) + return; + + /* FIXME: section->reloc_done isn't set properly; a generic buglet + preventing us from using bfd_get_section_size_after_reloc. */ + size + = section->_cooked_size ? section->_cooked_size : section->_raw_size; + + if (fsec_datap->addr >= vma + size) + return; + + fsec_datap->section = section; +} + +/* Make sure to write out the generated entries in the .cranges section + when doing partial linking, and set bit 0 on the entry address if it + points to SHmedia code and write sorted .cranges entries when writing + executables (final linking and objcopy). */ + +static void +sh64_elf_final_write_processing (abfd, linker) + bfd * abfd; + boolean linker ATTRIBUTE_UNUSED; +{ + bfd_vma ld_generated_cranges_size; + asection *cranges + = bfd_get_section_by_name (abfd, SH64_CRANGES_SECTION_NAME); + + /* If no new .cranges were added, the generic ELF linker parts will + write it all out. If not, we need to write them out when doing + partial linking. For a final link, we will sort them and write them + all out further below. */ + if (linker + && cranges != NULL + && elf_elfheader (abfd)->e_type != ET_EXEC + && (ld_generated_cranges_size + = sh64_elf_section_data (cranges)->cranges_growth) != 0) + { + bfd_vma incoming_cranges_size + = ((cranges->_cooked_size != 0 + ? cranges->_cooked_size : cranges->_raw_size) + - ld_generated_cranges_size); + + if (! bfd_set_section_contents (abfd, cranges, + cranges->contents + + incoming_cranges_size, + cranges->output_offset + + incoming_cranges_size, + ld_generated_cranges_size)) + { + bfd_set_error (bfd_error_file_truncated); + (*_bfd_error_handler) + (_("%s: could not write out added .cranges entries"), + bfd_get_filename (abfd)); + } + } + + /* Only set entry address bit 0 and sort .cranges when linking to an + executable; never with objcopy or strip. */ + if (linker && elf_elfheader (abfd)->e_type == ET_EXEC) + { + struct sh64_find_section_vma_data fsec_data; + sh64_elf_crange dummy; + + /* For a final link, set the low bit of the entry address to + reflect whether or not it is a SHmedia address. + FIXME: Perhaps we shouldn't do this if the entry address was + supplied numerically, but we currently lack the infrastructure to + recognize that: The entry symbol, and info whether it is numeric + or a symbol name is kept private in the linker. */ + fsec_data.addr = elf_elfheader (abfd)->e_entry; + fsec_data.section = NULL; + + bfd_map_over_sections (abfd, sh64_find_section_for_address, + (PTR) &fsec_data); + if (fsec_data.section + && (sh64_get_contents_type (fsec_data.section, + elf_elfheader (abfd)->e_entry, + &dummy) == CRT_SH5_ISA32)) + elf_elfheader (abfd)->e_entry |= 1; + + /* If we have a .cranges section, sort the entries. */ + if (cranges != NULL) + { + bfd_size_type cranges_size + = (cranges->_cooked_size != 0 + ? cranges->_cooked_size : cranges->_raw_size); + + /* We know we always have these in memory at this time. */ + BFD_ASSERT (cranges->contents != NULL); + + /* The .cranges may already have been sorted in the process of + finding out the ISA-type of the entry address. If not, we do + it here. */ + if (elf_section_data (cranges)->this_hdr.sh_type + != SHT_SH5_CR_SORTED) + { + qsort (cranges->contents, cranges_size / SH64_CRANGE_SIZE, + SH64_CRANGE_SIZE, + bfd_big_endian (cranges->owner) + ? crange_qsort_cmpb : crange_qsort_cmpl); + elf_section_data (cranges)->this_hdr.sh_type + = SHT_SH5_CR_SORTED; + } + + /* We need to write it out in whole as sorted. */ + if (! bfd_set_section_contents (abfd, cranges, + cranges->contents, + cranges->output_offset, + cranges_size)) + { + bfd_set_error (bfd_error_file_truncated); + (*_bfd_error_handler) + (_("%s: could not write out sorted .cranges entries"), + bfd_get_filename (abfd)); + } + } + } +} + +/* Ordering functions of a crange, for the qsort and bsearch calls and for + different endianness. */ + +static int +crange_qsort_cmpb (p1, p2) + const PTR p1; + const PTR p2; +{ + bfd_vma a1 = bfd_getb32 (p1); + bfd_vma a2 = bfd_getb32 (p2); + + /* Preserve order if there's ambiguous contents. */ + if (a1 == a2) + return (char *) p1 - (char *) p2; + + return a1 - a2; +} + +static int +crange_qsort_cmpl (p1, p2) + const PTR p1; + const PTR p2; +{ + bfd_vma a1 = (bfd_vma) bfd_getl32 (p1); + bfd_vma a2 = (bfd_vma) bfd_getl32 (p2); + + /* Preserve order if there's ambiguous contents. */ + if (a1 == a2) + return (char *) p1 - (char *) p2; + + return a1 - a2; +} + +static int +crange_bsearch_cmpb (p1, p2) + const PTR p1; + const PTR p2; +{ + bfd_vma a1 = *(bfd_vma *) p1; + bfd_vma a2 = (bfd_vma) bfd_getb32 (p2); + bfd_size_type size + = (bfd_size_type) bfd_getb32 (SH64_CRANGE_CR_SIZE_OFFSET + (char *) p2); + + if (a1 >= a2 + size) + return 1; + if (a1 < a2) + return -1; + return 0; +} + +static int +crange_bsearch_cmpl (p1, p2) + const PTR p1; + const PTR p2; +{ + bfd_vma a1 = *(bfd_vma *) p1; + bfd_vma a2 = (bfd_vma) bfd_getl32 (p2); + bfd_size_type size + = (bfd_size_type) bfd_getl32 (SH64_CRANGE_CR_SIZE_OFFSET + (char *) p2); + + if (a1 >= a2 + size) + return 1; + if (a1 < a2) + return -1; + return 0; +} + +/* Check whether a specific address is specified within a .cranges + section. Return FALSE if not found, and TRUE if found, and the region + filled into RANGEP if non-NULL. */ + +static boolean +sh64_address_in_cranges (cranges, addr, rangep) + asection *cranges; + bfd_vma addr; + sh64_elf_crange *rangep; +{ + bfd_byte *cranges_contents; + bfd_byte *found_rangep; + bfd_size_type cranges_size = bfd_section_size (cranges->owner, cranges); + + /* If the size is not a multiple of the cranges entry size, then + something is badly wrong. */ + if ((cranges_size % SH64_CRANGE_SIZE) != 0) + return false; + + /* If this section has relocations, then we can't do anything sane. */ + if (bfd_get_section_flags (cranges->owner, cranges) & SEC_RELOC) + return false; + + /* Has some kind soul (or previous call) left processed, sorted contents + for us? */ + if ((bfd_get_section_flags (cranges->owner, cranges) & SEC_IN_MEMORY) + && elf_section_data (cranges)->this_hdr.sh_type == SHT_SH5_CR_SORTED) + cranges_contents = cranges->contents; + else + { + cranges_contents + = bfd_malloc (cranges->_cooked_size == 0 + ? cranges->_cooked_size : cranges->_raw_size); + if (cranges_contents == NULL) + return false; + + if (! bfd_get_section_contents (cranges->owner, cranges, + cranges_contents, (file_ptr) 0, + cranges_size)) + goto error_return; + + /* Is it sorted? */ + if (elf_section_data (cranges)->this_hdr.sh_type + != SHT_SH5_CR_SORTED) + /* Nope. Lets sort it. */ + qsort (cranges_contents, cranges_size / SH64_CRANGE_SIZE, + SH64_CRANGE_SIZE, + bfd_big_endian (cranges->owner) + ? crange_qsort_cmpb : crange_qsort_cmpl); + + /* Let's keep it around. */ + cranges->contents = cranges_contents; + bfd_set_section_flags (cranges->owner, cranges, + bfd_get_section_flags (cranges->owner, cranges) + | SEC_IN_MEMORY); + + /* It's sorted now. */ + elf_section_data (cranges)->this_hdr.sh_type = SHT_SH5_CR_SORTED; + } + + /* Try and find a matching range. */ + found_rangep + = bsearch (&addr, cranges_contents, cranges_size / SH64_CRANGE_SIZE, + SH64_CRANGE_SIZE, + bfd_big_endian (cranges->owner) + ? crange_bsearch_cmpb : crange_bsearch_cmpl); + + /* Fill in a few return values if we found a matching range. */ + if (found_rangep) + { + enum sh64_elf_cr_type cr_type + = bfd_get_16 (cranges->owner, + SH64_CRANGE_CR_TYPE_OFFSET + found_rangep); + bfd_vma cr_addr + = bfd_get_32 (cranges->owner, + SH64_CRANGE_CR_ADDR_OFFSET + + (char *) found_rangep); + bfd_size_type cr_size + = bfd_get_32 (cranges->owner, + SH64_CRANGE_CR_SIZE_OFFSET + + (char *) found_rangep); + + rangep->cr_addr = cr_addr; + rangep->cr_size = cr_size; + rangep->cr_type = cr_type; + + return true; + } + + /* There is a .cranges section, but it does not have a descriptor + matching this address. */ + return false; + +error_return: + free (cranges_contents); + return false; +} + +/* Determine what ADDR points to in SEC, and fill in a range descriptor in + *RANGEP if it's non-NULL. */ + +enum sh64_elf_cr_type +sh64_get_contents_type (sec, addr, rangep) + asection *sec; + bfd_vma addr; + sh64_elf_crange *rangep; +{ + asection *cranges; + + /* Fill in the range with the boundaries of the section as a default. */ + if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour + && elf_elfheader (sec->owner)->e_type == ET_EXEC) + { + rangep->cr_addr = bfd_get_section_vma (sec->owner, sec); + rangep->cr_size = bfd_section_size (sec->owner, sec); + rangep->cr_type = CRT_NONE; + } + else + return false; + + /* If none of the pertinent bits are set, then it's a SHcompact (or at + least not SHmedia). */ + if ((elf_section_data (sec)->this_hdr.sh_flags + & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)) == 0) + { + enum sh64_elf_cr_type cr_type + = ((bfd_get_section_flags (sec->owner, sec) & SEC_CODE) != 0 + ? CRT_SH5_ISA16 : CRT_DATA); + rangep->cr_type = cr_type; + return cr_type; + } + + /* If only the SHF_SH5_ISA32 bit is set, then we have SHmedia. */ + if ((elf_section_data (sec)->this_hdr.sh_flags + & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)) == SHF_SH5_ISA32) + { + rangep->cr_type = CRT_SH5_ISA32; + return CRT_SH5_ISA32; + } + + /* Otherwise, we have to look up the .cranges section. */ + cranges = bfd_get_section_by_name (sec->owner, SH64_CRANGES_SECTION_NAME); + + if (cranges == NULL) + /* A mixed section but there's no .cranges section. This is probably + bad input; it does not comply to specs. */ + return CRT_NONE; + + /* If this call fails, we will still have CRT_NONE in rangep->cr_type + and that will be suitable to return. */ + sh64_address_in_cranges (cranges, addr, rangep); + + return rangep->cr_type; +} + +/* This is a simpler exported interface for the benefit of gdb et al. */ + +boolean +sh64_address_is_shmedia (sec, addr) + asection *sec; + bfd_vma addr; +{ + sh64_elf_crange dummy; + return sh64_get_contents_type (sec, addr, &dummy) == CRT_SH5_ISA32; +} |