Home | History | Annotate | Line # | Download | only in emultempl
      1      1.1  christos # This shell script emits a C file. -*- C -*-
      2  1.1.1.4  christos #   Copyright (C) 2013-2025 Free Software Foundation, Inc.
      3      1.1  christos #
      4      1.1  christos # This file is part of GNU Binutils.
      5      1.1  christos #
      6      1.1  christos # This program is free software; you can redistribute it and/or modify
      7      1.1  christos # it under the terms of the GNU General Public License as published by
      8      1.1  christos # the Free Software Foundation; either version 3 of the License, or
      9      1.1  christos # (at your option) any later version.
     10      1.1  christos #
     11      1.1  christos # This program is distributed in the hope that it will be useful,
     12      1.1  christos # but WITHOUT ANY WARRANTY; without even the implied warranty of
     13      1.1  christos # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14      1.1  christos # GNU General Public License for more details.
     15      1.1  christos #
     16      1.1  christos # You should have received a copy of the GNU General Public License
     17      1.1  christos # along with this program; if not, write to the Free Software
     18      1.1  christos # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     19      1.1  christos # MA 02110-1301, USA.
     20      1.1  christos 
     21      1.1  christos # This file is sourced from elf.em, and defines extra C-SKY ELF
     22      1.1  christos # specific routines.
     23      1.1  christos #
     24      1.1  christos fragment <<EOF
     25      1.1  christos 
     26      1.1  christos #include "ldctor.h"
     27      1.1  christos #include "elf/csky.h"
     28      1.1  christos #include "elf32-csky.h"
     29      1.1  christos 
     30      1.1  christos /* To use branch stub or not.  */
     31  1.1.1.2  christos extern bool use_branch_stub;
     32      1.1  christos 
     33      1.1  christos /* Fake input file for stubs.  */
     34      1.1  christos static lang_input_statement_type *stub_file;
     35      1.1  christos 
     36      1.1  christos /* Whether we need to call gldcsky_layout_sections_again.  */
     37      1.1  christos static int need_laying_out = 0;
     38      1.1  christos 
     39      1.1  christos /* Maximum size of a group of input sections that can be handled by
     40      1.1  christos    one stub section.  A value of +/-1 indicates the bfd back-end
     41      1.1  christos    should use a suitable default size.  */
     42      1.1  christos static bfd_signed_vma group_size = 1;
     43      1.1  christos 
     44      1.1  christos struct hook_stub_info
     45      1.1  christos {
     46      1.1  christos   lang_statement_list_type add;
     47      1.1  christos   asection *input_section;
     48      1.1  christos };
     49      1.1  christos 
     50      1.1  christos /* Traverse the linker tree to find the spot where the stub goes.  */
     51  1.1.1.2  christos static bool
     52      1.1  christos hook_in_stub (struct hook_stub_info *info, lang_statement_union_type **lp)
     53      1.1  christos {
     54      1.1  christos   lang_statement_union_type *l;
     55  1.1.1.2  christos   bool ret;
     56      1.1  christos 
     57      1.1  christos   for (l = *lp; l != NULL; lp = &l->header.next, l = *lp)
     58      1.1  christos     switch (l->header.type)
     59      1.1  christos       {
     60      1.1  christos       case lang_constructors_statement_enum:
     61      1.1  christos 	ret = hook_in_stub (info, &constructor_list.head);
     62      1.1  christos 	if (ret)
     63      1.1  christos 	  return ret;
     64      1.1  christos 	break;
     65      1.1  christos 
     66      1.1  christos       case lang_output_section_statement_enum:
     67      1.1  christos 	ret = hook_in_stub (info,
     68      1.1  christos 			    &l->output_section_statement.children.head);
     69      1.1  christos 	if (ret)
     70      1.1  christos 	  return ret;
     71      1.1  christos 	break;
     72      1.1  christos 
     73      1.1  christos       case lang_wild_statement_enum:
     74      1.1  christos 	ret = hook_in_stub (info, &l->wild_statement.children.head);
     75      1.1  christos 	if (ret)
     76      1.1  christos 	  return ret;
     77      1.1  christos 	break;
     78      1.1  christos 
     79      1.1  christos       case lang_group_statement_enum:
     80      1.1  christos 	ret = hook_in_stub (info, &l->group_statement.children.head);
     81      1.1  christos 	if (ret)
     82      1.1  christos 	  return ret;
     83      1.1  christos 	break;
     84      1.1  christos 
     85      1.1  christos       case lang_input_section_enum:
     86      1.1  christos 	if (l->input_section.section == info->input_section)
     87      1.1  christos 	  {
     88      1.1  christos 	    /* We've found our section.  Insert the stub immediately
     89      1.1  christos 	       after its associated input section.  */
     90      1.1  christos 	    *(info->add.tail) = l->header.next;
     91      1.1  christos 	    l->header.next = info->add.head;
     92  1.1.1.2  christos 	    return true;
     93      1.1  christos 	  }
     94      1.1  christos 	break;
     95      1.1  christos 
     96      1.1  christos       case lang_data_statement_enum:
     97      1.1  christos       case lang_reloc_statement_enum:
     98      1.1  christos       case lang_object_symbols_statement_enum:
     99      1.1  christos       case lang_output_statement_enum:
    100      1.1  christos       case lang_target_statement_enum:
    101      1.1  christos       case lang_input_statement_enum:
    102      1.1  christos       case lang_assignment_statement_enum:
    103      1.1  christos       case lang_padding_statement_enum:
    104      1.1  christos       case lang_address_statement_enum:
    105      1.1  christos       case lang_fill_statement_enum:
    106      1.1  christos 	break;
    107      1.1  christos 
    108      1.1  christos       default:
    109      1.1  christos 	FAIL ();
    110      1.1  christos 	break;
    111      1.1  christos       }
    112      1.1  christos 
    113  1.1.1.2  christos   return false;
    114      1.1  christos }
    115      1.1  christos EOF
    116      1.1  christos 
    117      1.1  christos case ${target} in
    118      1.1  christos     csky-*-linux-*)
    119      1.1  christos fragment <<EOF
    120      1.1  christos 
    121      1.1  christos static void
    122      1.1  christos csky_elf_before_parse (void)
    123      1.1  christos {
    124  1.1.1.2  christos   use_branch_stub = false;
    125      1.1  christos   gld${EMULATION_NAME}_before_parse ();
    126      1.1  christos }
    127      1.1  christos EOF
    128      1.1  christos     ;;
    129      1.1  christos esac
    130      1.1  christos 
    131      1.1  christos fragment <<EOF
    132      1.1  christos 
    133      1.1  christos /* This is a convenient point to tell BFD about target specific flags.
    134      1.1  christos    After the output has been created, but before inputs are read.  */
    135      1.1  christos static void
    136      1.1  christos csky_elf_create_output_section_statements (void)
    137      1.1  christos {
    138      1.1  christos   if (!(bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour
    139      1.1  christos 	&& elf_object_id (link_info.output_bfd) == CSKY_ELF_DATA))
    140  1.1.1.2  christos     use_branch_stub = false;
    141      1.1  christos 
    142      1.1  christos   /* If don't use branch stub, just do not emit stub_file.  */
    143      1.1  christos   if (!use_branch_stub)
    144      1.1  christos     return;
    145      1.1  christos 
    146      1.1  christos   stub_file = lang_add_input_file ("linker stubs",
    147      1.1  christos 				   lang_input_file_is_fake_enum, NULL);
    148      1.1  christos   stub_file->the_bfd = bfd_create ("linker stubs", link_info.output_bfd);
    149      1.1  christos   if (stub_file->the_bfd == NULL
    150      1.1  christos       || !bfd_set_arch_mach (stub_file->the_bfd,
    151      1.1  christos 	  bfd_get_arch (link_info.output_bfd),
    152      1.1  christos 	  bfd_get_mach (link_info.output_bfd)))
    153      1.1  christos     {
    154  1.1.1.4  christos       fatal (_("%P: can not create BFD: %E\n"));
    155      1.1  christos       return;
    156      1.1  christos     }
    157      1.1  christos 
    158      1.1  christos   stub_file->the_bfd->flags |= BFD_LINKER_CREATED;
    159      1.1  christos   ldlang_add_file (stub_file);
    160      1.1  christos }
    161      1.1  christos 
    162      1.1  christos /* Call-back for elf32_csky_size_stubs.  */
    163      1.1  christos 
    164      1.1  christos /* Create a new stub section, and arrange for it to be linked
    165      1.1  christos    immediately after INPUT_SECTION.  */
    166      1.1  christos static asection *
    167      1.1  christos elf32_csky_add_stub_section (const char *stub_sec_name,
    168      1.1  christos 			     asection *input_section)
    169      1.1  christos {
    170      1.1  christos   asection *stub_sec;
    171      1.1  christos   flagword flags;
    172      1.1  christos   asection *output_section;
    173      1.1  christos   const char *secname;
    174      1.1  christos   lang_output_section_statement_type *os;
    175      1.1  christos   struct hook_stub_info info;
    176      1.1  christos 
    177      1.1  christos   flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
    178      1.1  christos 	   | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP);
    179      1.1  christos   stub_sec = bfd_make_section_anyway_with_flags (stub_file->the_bfd,
    180      1.1  christos 						 stub_sec_name, flags);
    181      1.1  christos   if (stub_sec == NULL)
    182      1.1  christos     goto err_ret;
    183      1.1  christos 
    184      1.1  christos   bfd_set_section_alignment (stub_sec, 3);
    185      1.1  christos 
    186      1.1  christos   output_section = input_section->output_section;
    187      1.1  christos   secname = bfd_section_name (output_section);
    188      1.1  christos   os = lang_output_section_find (secname);
    189      1.1  christos 
    190      1.1  christos   info.input_section = input_section;
    191      1.1  christos   lang_list_init (&info.add);
    192  1.1.1.2  christos   lang_add_section (&info.add, stub_sec, NULL, NULL, os);
    193      1.1  christos 
    194      1.1  christos   if (info.add.head == NULL)
    195      1.1  christos     goto err_ret;
    196      1.1  christos 
    197      1.1  christos   if (hook_in_stub (&info, &os->children.head))
    198      1.1  christos     return stub_sec;
    199      1.1  christos 
    200  1.1.1.2  christos  err_ret:
    201      1.1  christos   einfo (_("%X%P: can not make stub section: %E\n"));
    202      1.1  christos   return NULL;
    203      1.1  christos }
    204      1.1  christos 
    205      1.1  christos /* Another call-back for elf_csky_size_stubs.  */
    206      1.1  christos static void
    207      1.1  christos gldcsky_layout_sections_again (void)
    208      1.1  christos {
    209      1.1  christos   /* If we have changed sizes of the stub sections, then we need
    210      1.1  christos      to recalculate all the section offsets.  This may mean we need to
    211      1.1  christos      add even more stubs.  */
    212  1.1.1.2  christos   ldelf_map_segments (true);
    213      1.1  christos   need_laying_out = -1;
    214      1.1  christos }
    215      1.1  christos 
    216      1.1  christos static void
    217      1.1  christos build_section_lists (lang_statement_union_type *statement)
    218      1.1  christos {
    219      1.1  christos   if (statement->header.type == lang_input_section_enum)
    220      1.1  christos     {
    221      1.1  christos       asection *i = statement->input_section.section;
    222      1.1  christos 
    223      1.1  christos       if (i->sec_info_type != SEC_INFO_TYPE_JUST_SYMS
    224      1.1  christos 	  && (i->flags & SEC_EXCLUDE) == 0
    225      1.1  christos 	  && i->output_section != NULL
    226      1.1  christos 	  && i->output_section->owner == link_info.output_bfd)
    227      1.1  christos 	elf32_csky_next_input_section (&link_info, i);
    228      1.1  christos     }
    229      1.1  christos }
    230      1.1  christos 
    231      1.1  christos static void
    232      1.1  christos gld${EMULATION_NAME}_after_allocation (void)
    233      1.1  christos {
    234      1.1  christos   /* bfd_elf32_discard_info just plays with debugging sections,
    235      1.1  christos      ie. doesn't affect any code, so we can delay resizing the
    236      1.1  christos      sections.  It's likely we'll resize everything in the process of
    237      1.1  christos      adding stubs.  */
    238      1.1  christos   if (bfd_elf_discard_info (link_info.output_bfd, &link_info))
    239      1.1  christos     need_laying_out = 1;
    240      1.1  christos 
    241      1.1  christos   /* If generating a relocatable output file, then we don't
    242      1.1  christos      have to examine the relocs.  */
    243      1.1  christos 
    244      1.1  christos   if (stub_file != NULL && !bfd_link_relocatable (&link_info))
    245      1.1  christos     {
    246      1.1  christos       int ret = elf32_csky_setup_section_lists (link_info.output_bfd,
    247      1.1  christos 						&link_info);
    248      1.1  christos 
    249      1.1  christos       if (ret < 0)
    250      1.1  christos 	{
    251      1.1  christos 	  einfo (_("%X%P: could not compute sections lists for stub generation: %E\n"));
    252      1.1  christos 	  return;
    253      1.1  christos 	}
    254      1.1  christos       else if (ret != 0)
    255      1.1  christos 	{
    256      1.1  christos 	  lang_for_each_statement (build_section_lists);
    257      1.1  christos 
    258      1.1  christos 	  /* Call into the BFD backend to do the real work.  */
    259      1.1  christos 	  if (! elf32_csky_size_stubs (link_info.output_bfd,
    260      1.1  christos 				       stub_file->the_bfd,
    261      1.1  christos 				       &link_info,
    262      1.1  christos 				       group_size,
    263      1.1  christos 				       &elf32_csky_add_stub_section,
    264      1.1  christos 				       &gldcsky_layout_sections_again))
    265      1.1  christos 	  {
    266      1.1  christos 	    einfo (_("%X%P: cannot size stub section: %E\n"));
    267      1.1  christos 	    return;
    268      1.1  christos 	  }
    269      1.1  christos 	}
    270      1.1  christos     }
    271      1.1  christos 
    272      1.1  christos   if (need_laying_out != -1)
    273      1.1  christos     ldelf_map_segments (need_laying_out);
    274      1.1  christos }
    275      1.1  christos 
    276      1.1  christos static void
    277      1.1  christos gld${EMULATION_NAME}_finish (void)
    278      1.1  christos {
    279      1.1  christos   if (stub_file != NULL
    280      1.1  christos       && !bfd_link_relocatable (&link_info)
    281      1.1  christos       && stub_file->the_bfd->sections != NULL
    282      1.1  christos       && !elf32_csky_build_stubs (&link_info))
    283      1.1  christos     einfo (_("%X%P: cannot build stubs: %E\n"));
    284      1.1  christos   finish_default ();
    285      1.1  christos }
    286      1.1  christos 
    287      1.1  christos EOF
    288      1.1  christos 
    289      1.1  christos # This code gets inserted into the generic elf32.sc linker script
    290      1.1  christos # and allows us to define our own command line switches.
    291      1.1  christos PARSE_AND_LIST_LONGOPTS='
    292      1.1  christos   {"branch-stub",	no_argument,       NULL, OPTION_BRANCH_STUB},
    293      1.1  christos   {"no-branch-stub",	no_argument,       NULL, OPTION_NO_BRANCH_STUB},
    294      1.1  christos   {"stub-group-size",	required_argument, NULL, OPTION_STUBGROUP_SIZE},
    295      1.1  christos '
    296      1.1  christos PARSE_AND_LIST_OPTIONS='
    297  1.1.1.2  christos   fprintf (file, _("  --[no-]branch-stub          "
    298  1.1.1.2  christos 		   "Disable/enable use of stubs to expand branch\n"
    299  1.1.1.2  christos 		   "                              "
    300  1.1.1.2  christos 		   "  instructions that cannot reach the target.\n"));
    301  1.1.1.2  christos   fprintf (file, _("  --stub-group-size=N         "
    302  1.1.1.2  christos 		   "Maximum size of a group of input sections\n"
    303  1.1.1.2  christos 		   "                              "
    304  1.1.1.2  christos 		   "  handled by one stub section.\n"));
    305      1.1  christos '
    306      1.1  christos 
    307      1.1  christos PARSE_AND_LIST_ARGS_CASES='
    308      1.1  christos   case OPTION_BRANCH_STUB:
    309  1.1.1.2  christos     use_branch_stub = true;
    310      1.1  christos     break;
    311      1.1  christos   case OPTION_NO_BRANCH_STUB:
    312  1.1.1.2  christos     use_branch_stub = false;
    313      1.1  christos     break;
    314      1.1  christos 
    315      1.1  christos   case OPTION_STUBGROUP_SIZE:
    316      1.1  christos     {
    317      1.1  christos       const char *end;
    318      1.1  christos 
    319      1.1  christos       group_size = bfd_scan_vma (optarg, &end, 0);
    320      1.1  christos       if (*end)
    321  1.1.1.4  christos 	fatal (_("%P: invalid number `%s'\''\n"), optarg);
    322      1.1  christos     }
    323      1.1  christos     break;
    324      1.1  christos '
    325      1.1  christos 
    326      1.1  christos case ${target} in
    327      1.1  christos     csky-*-linux-*) LDEMUL_BEFORE_PARSE=csky_elf_before_parse ;;
    328      1.1  christos esac
    329      1.1  christos LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation
    330      1.1  christos LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=csky_elf_create_output_section_statements
    331      1.1  christos LDEMUL_FINISH=gld${EMULATION_NAME}_finish
    332