123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565 |
- # This shell script emits a C file. -*- C -*-
- # Copyright (C) 2000-2015 Free Software Foundation, Inc.
- #
- # This file is part of the GNU Binutils.
- #
- # 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 3 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., 51 Franklin Street - Fifth Floor, Boston,
- # MA 02110-1301, 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
- fragment <<EOF
- #include "libiberty.h"
- #include "libbfd.h"
- #include "elf-bfd.h"
- #include "elf/sh.h"
- #include "elf32-sh64.h"
- /* Check if we need a .cranges section and create it if it's not in any
- input file. It might seem better to always create it and if unneeded,
- discard it, but I don't find a simple way to discard it totally from
- the output.
- Putting it here instead of as a elf_backend_always_size_sections hook
- in elf32-sh64.c, means that we have access to linker command line
- options here, and we can access input sections in the order in which
- they will be linked. */
- static void
- sh64_elf_${EMULATION_NAME}_before_allocation (void)
- {
- asection *cranges;
- asection *osec;
- /* Call main function; we're just extending it. */
- gld${EMULATION_NAME}_before_allocation ();
- cranges = bfd_get_section_by_name (link_info.output_bfd,
- SH64_CRANGES_SECTION_NAME);
- if (cranges != NULL)
- {
- if (RELAXATION_ENABLED)
- {
- /* FIXME: Look through incoming sections with .cranges
- descriptors, build up some kind of descriptors that the
- relaxing function will pick up and adjust, or perhaps make it
- find and adjust an associated .cranges descriptor. We could
- also look through incoming relocs and kill the ones marking
- relaxation areas, but that wouldn't be TRT. */
- 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);
- }
- }
- DISABLE_RELAXATION;
- }
- /* We wouldn't need to do anything when there's already a .cranges
- section (and have a return here), except that we need to set the
- section flags right for output sections that *don't* need a
- .cranges section. */
- }
- if (RELAXATION_ENABLED)
- {
- 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);
- DISABLE_RELAXATION;
- goto done_scanning_shmedia_sections;
- }
- }
- }
- }
- }
- done_scanning_shmedia_sections:
- /* For each non-empty input section in each output section, check if it
- has the same SH64-specific flags. If some input section differs, we
- need a .cranges section. */
- for (osec = link_info.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 (link_info.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;
- /* Omit excluded or garbage-collected sections. */
- if (bfd_get_section_flags (link_info.output_bfd, osec) & SEC_EXCLUDE)
- continue;
- /* Make sure we have the target section data initialized. */
- 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;
- }
- /* First find an input section so we have flags to compare with; the
- flags in the output section are not valid. */
- {
- 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:
- /* Check that all input sections have the same contents-type flags
- as the first input section. */
- {
- 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 flags don't agree, we need a .cranges section.
- Create it here if it did not exist through input
- sections. */
- if (iflags_isa != oflags_isa)
- {
- if (cranges == NULL)
- {
- /* This section will be *appended* to
- sections, so the outer iteration will reach
- it in due time and set
- sh64_elf_section_data; no need to set it
- specifically here. */
- cranges
- = bfd_make_section_with_flags (link_info.output_bfd,
- SH64_CRANGES_SECTION_NAME,
- SEC_LINKER_CREATED
- | SEC_KEEP
- | SEC_HAS_CONTENTS
- | SEC_DEBUGGING);
- if (cranges == NULL)
- einfo
- (_("%P%E%F: Can't make .cranges section\n"));
- }
- /* We don't need to look at more input sections,
- and we know this section will have mixed
- contents. */
- goto break_2;
- }
- }
- }
- }
- }
- /* If we got here, then all input sections in this output section
- have the same contents flag. Put that where we expect to see
- contents flags. We don't need to do this for sections that will
- need additional, linker-generated .cranges entries. */
- sh64_sec_data->contents_flags = iflags_isa;
- break_2:
- ;
- }
- }
- /* Size up and extend the .cranges section, merging generated entries. */
- 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;
- gld${EMULATION_NAME}_after_allocation ();
- /* Needed, since we create link_orders here. */
- lang_clear_os_map ();
- cranges = bfd_get_section_by_name (link_info.output_bfd,
- SH64_CRANGES_SECTION_NAME);
- /* If there is no .cranges section, it is because it was seen earlier on
- that none was needed. Otherwise it must have been created then, or
- be present in input. */
- if (cranges == NULL)
- return;
- /* First, we set the ISA flags for each output section according to the
- first non-discarded section. For each input section in osec, we
- check if it has the same flags. If it does not, we set flags to mark
- a mixed section (and exit the loop early). */
- for (osec = link_info.output_bfd->sections;
- osec != NULL;
- osec = osec->next)
- {
- bfd_vma oflags_isa = 0;
- bfd_boolean need_check_cranges = FALSE;
- /* Omit excluded or garbage-collected sections. */
- if (bfd_get_section_flags (link_info.output_bfd, osec) & SEC_EXCLUDE)
- continue;
- /* First find an input section so we have flags to compare with; the
- flags in the output section are not valid. */
- {
- 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:
- /* Check that all input sections have the same contents-type flags
- as the first input section. */
- {
- 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 flags don't agree, set the target-specific data
- of the section to mark that this section needs to
- be have .cranges section entries added. Don't
- bother setting ELF section flags in output section;
- they will be cleared later and will have to be
- re-initialized before the linked file is written. */
- 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 there were no new ranges for this output section, we don't
- need to iterate over the input sections to check how many are
- needed. */
- if (! need_check_cranges)
- continue;
- /* If we found a section with differing contents type, we need more
- ranges to mark the sections that are not mixed (and already have
- .cranges descriptors). Calculate the maximum number of new
- entries here. We may merge some of them, so that number is not
- final; it can shrink. */
- {
- 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);
- /* Make sure we have .cranges in memory even if there were only
- assembler-generated .cranges. */
- 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 we don't need to grow the .cranges section beyond what was in the
- input sections, we have nothing more to do here. We then only got
- here because there was a .cranges section coming from input. Zero
- out the number of generated .cranges. */
- if (new_cranges == 0)
- {
- sh64_elf_section_data (cranges)->sh64_info->cranges_growth = 0;
- return;
- }
- crangesp = cranges->contents + cranges->size;
- /* Now pass over the sections again, and make reloc orders for the new
- .cranges entries. Constants are set as we go. */
- for (osec = link_info.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;
- /* Omit excluded or garbage-collected sections, and output sections
- which were not marked as needing further processing. */
- if ((bfd_get_section_flags (link_info.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)
- {
- /* Allow only sections that have (at least initially) a
- non-zero size, and are not excluded, and are not marked
- as containing mixed data, thus already having .cranges
- entries. */
- 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;
- /* Sections can be empty, like .text in a file that
- only contains other sections. Ranges shouldn't be
- emitted for them. This can presumably happen after
- relaxing and is not be caught at the "raw size"
- test above. */
- if (cr_size == 0)
- continue;
- /* See if this is a continuation of the previous range
- for the same output section. If so, just change
- the size of the last range and continue. */
- if (cr_type == last_cr_type
- && (continuation_vma
- == osec->vma + isec->output_offset))
- {
- last_cr_size += cr_size;
- bfd_put_32 (link_info.output_bfd, last_cr_size,
- crangesp - SH64_CRANGE_SIZE
- + SH64_CRANGE_CR_SIZE_OFFSET);
- continuation_vma += cr_size;
- continue;
- }
- /* If we emit relocatable contents, we need a
- relocation for the start address. */
- if (bfd_link_relocatable (&link_info)
- || link_info.emitrelocations)
- {
- /* FIXME: We could perhaps use lang_add_reloc and
- friends here, but I'm not really sure that
- would leave us free to do some optimizations
- later. */
- cr_addr_order
- = bfd_new_link_order (link_info.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;
- /* Since SH, unlike normal RELA-targets, uses a
- "partial inplace" REL-like relocation for this,
- we put the addend in the contents and specify 0
- for the reloc. */
- bfd_put_32 (link_info.output_bfd, isec->output_offset,
- crangesp + SH64_CRANGE_CR_ADDR_OFFSET);
- cr_addr_order->u.reloc.p->addend = 0;
- }
- else
- bfd_put_32 (link_info.output_bfd,
- osec->vma + isec->output_offset,
- crangesp + SH64_CRANGE_CR_ADDR_OFFSET);
- /* If we could make a reloc for cr_size we would do
- it, but we would have to have a symbol for the size
- of the _input_ section and there's no way to
- generate that. */
- bfd_put_32 (link_info.output_bfd, cr_size,
- crangesp + SH64_CRANGE_CR_SIZE_OFFSET);
- bfd_put_16 (link_info.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;
- }
- }
- }
- }
- }
- /* The .cranges section will have this size, no larger or smaller.
- Since relocs (if relocatable linking) will be emitted into the
- "extended" size, we must set the raw size to the total. We have to
- keep track of the number of new .cranges entries.
- Sorting before writing is done by sh64_elf_final_write_processing. */
- sh64_elf_section_data (cranges)->sh64_info->cranges_growth
- = crangesp - cranges->contents - cranges->size;
- cranges->size = crangesp - cranges->contents;
- cranges->rawsize = cranges->size;
- }
- EOF
|