# This shell script emits a C file. -*- C -*-
# Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
#
# This file is part of GLD, the Gnu Linker.
#
# 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.
#
# This file is sourced from elf32.em, and defines extra sh64
# specific routines.
#
LDEMUL_AFTER_ALLOCATION=sh64_elf_${EMULATION_NAME}_after_allocation
LDEMUL_BEFORE_ALLOCATION=sh64_elf_${EMULATION_NAME}_before_allocation
cat >>e${EMULATION_NAME}.c <<EOF
#include "libiberty.h"
#include "libbfd.h"
#include "elf-bfd.h"
#include "elf/sh.h"
#include "elf32-sh64.h"
static void
sh64_elf_${EMULATION_NAME}_before_allocation (void)
{
asection *cranges;
asection *osec;
gld${EMULATION_NAME}_before_allocation ();
cranges = bfd_get_section_by_name (output_bfd, SH64_CRANGES_SECTION_NAME);
if (cranges != NULL)
{
if (command_line.relax)
{
einfo
(_("%P: Sorry, turning off relaxing: .cranges section in input.\n"));
einfo (_(" A .cranges section is present in:\n"));
{
LANG_FOR_EACH_INPUT_STATEMENT (f)
{
asection *input_cranges
= bfd_get_section_by_name (f->the_bfd,
SH64_CRANGES_SECTION_NAME);
if (input_cranges != NULL)
einfo (" %I\n", f);
}
}
command_line.relax = FALSE;
}
}
if (command_line.relax)
{
LANG_FOR_EACH_INPUT_STATEMENT (f)
{
if (bfd_get_flavour (f->the_bfd) == bfd_target_elf_flavour)
{
asection *isec;
for (isec = f->the_bfd->sections;
isec != NULL;
isec = isec->next)
{
if (elf_section_data (isec)->this_hdr.sh_flags
& (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED))
{
einfo (_("%P: Sorry, turning off relaxing: SHmedia sections present.\n"));
einfo (" %I\n", f);
command_line.relax = FALSE;
goto done_scanning_shmedia_sections;
}
}
}
}
}
done_scanning_shmedia_sections:
for (osec = output_bfd->sections;
osec != NULL;
osec = osec->next)
{
struct sh64_section_data *sh64_sec_data;
bfd_vma oflags_isa = 0;
bfd_vma iflags_isa = 0;
if (bfd_get_flavour (output_bfd) != bfd_target_elf_flavour)
einfo (_("%FError: non-ELF output formats are not supported by this target's linker.\n"));
sh64_sec_data = sh64_elf_section_data (osec)->sh64_info;
if (bfd_get_section_flags (output_bfd, osec) & SEC_EXCLUDE)
continue;
if (sh64_sec_data == NULL)
{
sh64_sec_data = xcalloc (1, sizeof (struct sh64_section_data));
sh64_elf_section_data (osec)->sh64_info = sh64_sec_data;
}
{
LANG_FOR_EACH_INPUT_STATEMENT (f)
{
asection *isec;
for (isec = f->the_bfd->sections;
isec != NULL;
isec = isec->next)
{
if (isec->output_section == osec
&& isec->size != 0
&& (bfd_get_section_flags (isec->owner, isec)
& SEC_EXCLUDE) == 0)
{
oflags_isa
= (elf_section_data (isec)->this_hdr.sh_flags
& (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED));
goto break_1;
}
}
}
}
break_1:
{
LANG_FOR_EACH_INPUT_STATEMENT (f)
{
asection *isec;
for (isec = f->the_bfd->sections;
isec != NULL;
isec = isec->next)
{
if (isec->output_section == osec
&& isec->size != 0
&& (bfd_get_section_flags (isec->owner, isec)
& SEC_EXCLUDE) == 0)
{
iflags_isa
= (elf_section_data (isec)->this_hdr.sh_flags
& (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED));
if (iflags_isa != oflags_isa)
{
if (cranges == NULL)
{
cranges
= bfd_make_section (output_bfd,
SH64_CRANGES_SECTION_NAME);
if (cranges == NULL
|| !bfd_set_section_flags (output_bfd,
cranges,
SEC_LINKER_CREATED
| SEC_KEEP
| SEC_HAS_CONTENTS
| SEC_DEBUGGING))
einfo
(_("%P%E%F: Can't make .cranges section\n"));
}
goto break_2;
}
}
}
}
}
sh64_sec_data->contents_flags = iflags_isa;
break_2:
;
}
}
static void
sh64_elf_${EMULATION_NAME}_after_allocation (void)
{
bfd_vma new_cranges = 0;
bfd_vma cranges_growth = 0;
asection *osec;
bfd_byte *crangesp;
asection *cranges
= bfd_get_section_by_name (output_bfd, SH64_CRANGES_SECTION_NAME);
after_allocation_default ();
if (cranges == NULL)
return;
for (osec = output_bfd->sections;
osec != NULL;
osec = osec->next)
{
bfd_vma oflags_isa = 0;
bfd_boolean need_check_cranges = FALSE;
if (bfd_get_section_flags (output_bfd, osec) & SEC_EXCLUDE)
continue;
{
LANG_FOR_EACH_INPUT_STATEMENT (f)
{
asection *isec;
for (isec = f->the_bfd->sections;
isec != NULL;
isec = isec->next)
{
if (isec->output_section == osec
&& isec->size != 0
&& (bfd_get_section_flags (isec->owner, isec)
& SEC_EXCLUDE) == 0)
{
oflags_isa
= (elf_section_data (isec)->this_hdr.sh_flags
& (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED));
goto break_1;
}
}
}
}
break_1:
{
LANG_FOR_EACH_INPUT_STATEMENT (f)
{
asection *isec;
for (isec = f->the_bfd->sections;
isec != NULL;
isec = isec->next)
{
if (isec->output_section == osec
&& isec->size != 0
&& (bfd_get_section_flags (isec->owner, isec)
& SEC_EXCLUDE) == 0)
{
bfd_vma iflags_isa
= (elf_section_data (isec)->this_hdr.sh_flags
& (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED));
if (iflags_isa != oflags_isa)
{
oflags_isa = SHF_SH5_ISA32_MIXED;
BFD_ASSERT (sh64_elf_section_data (osec)->sh64_info);
sh64_elf_section_data (osec)->sh64_info->contents_flags
= SHF_SH5_ISA32_MIXED;
need_check_cranges = TRUE;
goto break_2;
}
}
}
}
}
break_2:
if (! need_check_cranges)
continue;
{
LANG_FOR_EACH_INPUT_STATEMENT (f)
{
asection *isec;
for (isec = f->the_bfd->sections;
isec != NULL;
isec = isec->next)
{
if (isec->output_section == osec
&& isec->size != 0
&& (bfd_get_section_flags (isec->owner, isec)
& SEC_EXCLUDE) == 0
&& ((elf_section_data (isec)->this_hdr.sh_flags
& (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED))
!= SHF_SH5_ISA32_MIXED))
new_cranges++;
}
}
}
}
if (cranges->contents != NULL)
free (cranges->contents);
BFD_ASSERT (sh64_elf_section_data (cranges)->sh64_info != NULL);
cranges_growth = new_cranges * SH64_CRANGE_SIZE;
cranges->contents = xcalloc (cranges->size + cranges_growth, 1);
bfd_set_section_flags (cranges->owner, cranges,
bfd_get_section_flags (cranges->owner, cranges)
| SEC_IN_MEMORY);
if (new_cranges == 0)
{
sh64_elf_section_data (cranges)->sh64_info->cranges_growth = 0;
return;
}
crangesp = cranges->contents + cranges->size;
for (osec = output_bfd->sections;
osec != NULL;
osec = osec->next)
{
struct bfd_link_order *cr_addr_order = NULL;
enum sh64_elf_cr_type last_cr_type = CRT_NONE;
bfd_vma last_cr_size = 0;
bfd_vma continuation_vma = 0;
if ((bfd_get_section_flags (output_bfd, osec) & SEC_EXCLUDE) != 0
|| (sh64_elf_section_data (osec)->sh64_info->contents_flags
!= SHF_SH5_ISA32_MIXED))
continue;
{
LANG_FOR_EACH_INPUT_STATEMENT (f)
{
asection *isec;
for (isec = f->the_bfd->sections;
isec != NULL;
isec = isec->next)
{
if (isec->output_section == osec
&& isec->size != 0
&& (bfd_get_section_flags (isec->owner, isec)
& SEC_EXCLUDE) == 0
&& ((elf_section_data (isec)->this_hdr.sh_flags
& (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED))
!= SHF_SH5_ISA32_MIXED))
{
enum sh64_elf_cr_type cr_type;
bfd_vma cr_size;
bfd_vma isa_flags
= (elf_section_data (isec)->this_hdr.sh_flags
& (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED));
if (isa_flags == SHF_SH5_ISA32)
cr_type = CRT_SH5_ISA32;
else if ((bfd_get_section_flags (isec->owner, isec)
& SEC_CODE) == 0)
cr_type = CRT_DATA;
else
cr_type = CRT_SH5_ISA16;
cr_size = isec->size;
if (cr_size == 0)
continue;
if (cr_type == last_cr_type
&& (continuation_vma
== osec->vma + isec->output_offset))
{
last_cr_size += cr_size;
bfd_put_32 (output_bfd, last_cr_size,
crangesp - SH64_CRANGE_SIZE
+ SH64_CRANGE_CR_SIZE_OFFSET);
continuation_vma += cr_size;
continue;
}
if (link_info.relocatable || link_info.emitrelocations)
{
cr_addr_order
= bfd_new_link_order (output_bfd, cranges);
if (cr_addr_order == NULL)
{
einfo (_("%P%F: bfd_new_link_order failed\n"));
return;
}
cr_addr_order->type = bfd_section_reloc_link_order;
cr_addr_order->offset
= (cranges->output_offset
+ crangesp + SH64_CRANGE_CR_ADDR_OFFSET
- cranges->contents);
cr_addr_order->size = 4;
cr_addr_order->u.reloc.p
= xmalloc (sizeof (struct bfd_link_order_reloc));
cr_addr_order->u.reloc.p->reloc = BFD_RELOC_32;
cr_addr_order->u.reloc.p->u.section = osec;
bfd_put_32 (output_bfd, isec->output_offset,
crangesp + SH64_CRANGE_CR_ADDR_OFFSET);
cr_addr_order->u.reloc.p->addend = 0;
elf_section_data(cranges)->rel_count++;
}
else
bfd_put_32 (output_bfd,
osec->vma + isec->output_offset,
crangesp + SH64_CRANGE_CR_ADDR_OFFSET);
bfd_put_32 (output_bfd, cr_size,
crangesp + SH64_CRANGE_CR_SIZE_OFFSET);
bfd_put_16 (output_bfd, cr_type,
crangesp + SH64_CRANGE_CR_TYPE_OFFSET);
last_cr_type = cr_type;
last_cr_size = cr_size;
continuation_vma
= osec->vma + isec->output_offset + cr_size;
crangesp += SH64_CRANGE_SIZE;
}
}
}
}
}
sh64_elf_section_data (cranges)->sh64_info->cranges_growth
= crangesp - cranges->contents - cranges->size;
cranges->size = crangesp - cranges->contents;
}