1# This shell script emits a C file. -*- C -*-
2#   Copyright (C) 2011-2016 Free Software Foundation, Inc.
3#
4# This file is part of the GNU Binutils.
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19# MA 02110-1301, USA.
20#
21
22# This file is sourced from elf32.em, and defines extra C6X DSBT specific
23# features.
24#
25fragment <<EOF
26#include "ldctor.h"
27#include "elf32-tic6x.h"
28
29static struct elf32_tic6x_params params =
30{
31  0, 64
32};
33
34static int merge_exidx_entries = -1;
35
36static int
37is_tic6x_target (void)
38{
39  extern const bfd_target tic6x_elf32_le_vec;
40  extern const bfd_target tic6x_elf32_be_vec;
41  extern const bfd_target tic6x_elf32_linux_le_vec;
42  extern const bfd_target tic6x_elf32_linux_be_vec;
43  extern const bfd_target tic6x_elf32_c6000_le_vec;
44  extern const bfd_target tic6x_elf32_c6000_be_vec;
45
46  return (link_info.output_bfd->xvec == &tic6x_elf32_le_vec
47	  || link_info.output_bfd->xvec == &tic6x_elf32_be_vec
48	  || link_info.output_bfd->xvec == &tic6x_elf32_linux_le_vec
49	  || link_info.output_bfd->xvec == &tic6x_elf32_linux_be_vec
50	  || link_info.output_bfd->xvec == &tic6x_elf32_c6000_le_vec
51	  || link_info.output_bfd->xvec == &tic6x_elf32_c6000_be_vec);
52}
53
54/* Pass params to backend.  */
55
56static void
57tic6x_after_open (void)
58{
59  if (is_tic6x_target ())
60    {
61      if (params.dsbt_index >= params.dsbt_size)
62	{
63	  einfo (_("%P%F: invalid --dsbt-index %d, outside DSBT size.\n"),
64		 params.dsbt_index);
65	}
66      elf32_tic6x_setup (&link_info, &params);
67    }
68
69  gld${EMULATION_NAME}_after_open ();
70}
71
72static int
73compare_output_sec_vma (const void *a, const void *b)
74{
75  asection *asec = *(asection **) a, *bsec = *(asection **) b;
76  asection *aout = asec->output_section, *bout = bsec->output_section;
77  bfd_vma avma, bvma;
78
79  /* If there's no output section for some reason, compare equal.  */
80  if (!aout || !bout)
81    return 0;
82
83  avma = aout->vma + asec->output_offset;
84  bvma = bout->vma + bsec->output_offset;
85
86  if (avma > bvma)
87    return 1;
88  else if (avma < bvma)
89    return -1;
90
91  return 0;
92}
93
94static void
95gld${EMULATION_NAME}_after_allocation (void)
96{
97  int layout_changed = 0;
98  int ret;
99
100  if (!bfd_link_relocatable (&link_info))
101    {
102      /* Build a sorted list of input text sections, then use that to process
103	 the unwind table index.  */
104      unsigned int list_size = 10;
105      asection **sec_list = (asection **)
106          xmalloc (list_size * sizeof (asection *));
107      unsigned int sec_count = 0;
108
109      LANG_FOR_EACH_INPUT_STATEMENT (is)
110	{
111	  bfd *abfd = is->the_bfd;
112	  asection *sec;
113
114	  if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
115	    continue;
116
117	  for (sec = abfd->sections; sec != NULL; sec = sec->next)
118	    {
119	      asection *out_sec = sec->output_section;
120
121	      if (out_sec
122		  && elf_section_data (sec)
123		  && elf_section_type (sec) == SHT_PROGBITS
124		  && (elf_section_flags (sec) & SHF_EXECINSTR) != 0
125		  && (sec->flags & SEC_EXCLUDE) == 0
126		  && sec->sec_info_type != SEC_INFO_TYPE_JUST_SYMS
127		  && out_sec != bfd_abs_section_ptr)
128		{
129		  if (sec_count == list_size)
130		    {
131		      list_size *= 2;
132		      sec_list = (asection **)
133                          xrealloc (sec_list, list_size * sizeof (asection *));
134		    }
135
136		  sec_list[sec_count++] = sec;
137		}
138	    }
139	}
140
141      qsort (sec_list, sec_count, sizeof (asection *), &compare_output_sec_vma);
142
143      if (elf32_tic6x_fix_exidx_coverage (sec_list, sec_count, &link_info,
144					   merge_exidx_entries))
145	layout_changed = 1;
146
147      free (sec_list);
148    }
149
150  /* bfd_elf32_discard_info just plays with debugging sections,
151     ie. doesn't affect any code, so we can delay resizing the
152     sections.  */
153  ret = bfd_elf_discard_info (link_info.output_bfd, & link_info);
154  if (ret < 0)
155    {
156      einfo ("%X%P: .eh_frame/.stab edit: %E\n");
157      return;
158    }
159  else if (ret > 0)
160    layout_changed = 1;
161
162  gld${EMULATION_NAME}_map_segments (layout_changed);
163}
164EOF
165
166# This code gets inserted into the generic elf32.sc linker script
167# and allows us to define our own command line switches.
168PARSE_AND_LIST_PROLOGUE='
169#define OPTION_DSBT_INDEX		300
170#define OPTION_DSBT_SIZE		301
171#define OPTION_NO_MERGE_EXIDX_ENTRIES   302
172'
173
174PARSE_AND_LIST_LONGOPTS='
175  {"dsbt-index", required_argument, NULL, OPTION_DSBT_INDEX},
176  {"dsbt-size", required_argument, NULL, OPTION_DSBT_SIZE},
177  { "no-merge-exidx-entries", no_argument, NULL, OPTION_NO_MERGE_EXIDX_ENTRIES },
178'
179
180PARSE_AND_LIST_OPTIONS='
181  fprintf (file, _("  --dsbt-index <index>\n"));
182  fprintf (file, _("\t\t\tUse this as the DSBT index for the output object\n"));
183  fprintf (file, _("  --dsbt-size <index>\n"));
184  fprintf (file, _("\t\t\tUse this as the number of entries in the DSBT table\n"));
185  fprintf (file, _("  --no-merge-exidx-entries    Disable merging exidx entries\n"));
186'
187
188PARSE_AND_LIST_ARGS_CASES='
189    case OPTION_DSBT_INDEX:
190      {
191	char *end;
192	params.dsbt_index = strtol (optarg, &end, 0);
193	if (*end == 0
194	    && params.dsbt_index >= 0 && params.dsbt_index < 0x7fff)
195	  break;
196	einfo (_("%P%F: invalid --dsbt-index %s\n"), optarg);
197      }
198      break;
199    case OPTION_DSBT_SIZE:
200      {
201	char *end;
202	params.dsbt_size = strtol (optarg, &end, 0);
203	if (*end == 0
204	    && params.dsbt_size >= 0 && params.dsbt_size < 0x7fff)
205	  break;
206	einfo (_("%P%F: invalid --dsbt-size %s\n"), optarg);
207      }
208      break;
209   case OPTION_NO_MERGE_EXIDX_ENTRIES:
210      merge_exidx_entries = 0;
211'
212
213LDEMUL_AFTER_OPEN=tic6x_after_open
214LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation
215