xref: /netbsd-src/external/gpl3/binutils/dist/ld/emultempl/avrelf.em (revision 63d4abf06d37aace2f9e41a494102a64fe3abddb)
1# This shell script emits a C file. -*- C -*-
2#   Copyright 2006, 2007, 2008
3#   Free Software Foundation, Inc.
4#
5# This file is part of the GNU Binutils.
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 3 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20# MA 02110-1301, USA.
21
22
23# This file is sourced from elf32.em, and defines extra avr-elf specific
24# routines.  It is used to generate the trampolines for the avr6 family
25# of devices where one needs to address the issue that it is not possible
26# to reach the whole program memory by using 16 bit pointers.
27
28fragment <<EOF
29
30#include "elf32-avr.h"
31#include "ldctor.h"
32
33/* The fake file and it's corresponding section meant to hold
34   the linker stubs if needed.  */
35
36static lang_input_statement_type *stub_file;
37static asection *avr_stub_section;
38
39/* Variables set by the command-line parameters and transfered
40   to the bfd without use of global shared variables.  */
41
42static bfd_boolean avr_no_stubs = FALSE;
43static bfd_boolean avr_debug_relax = FALSE;
44static bfd_boolean avr_debug_stubs = FALSE;
45static bfd_boolean avr_replace_call_ret_sequences = TRUE;
46static bfd_vma avr_pc_wrap_around = 0x10000000;
47
48/* Transfers information to the bfd frontend.  */
49
50static void
51avr_elf_set_global_bfd_parameters (void)
52{
53  elf32_avr_setup_params (& link_info,
54                          stub_file->the_bfd,
55                          avr_stub_section,
56                          avr_no_stubs,
57                          avr_debug_stubs,
58                          avr_debug_relax,
59                          avr_pc_wrap_around,
60                          avr_replace_call_ret_sequences);
61}
62
63
64/* Makes a conservative estimate of the trampoline section size that could
65   be corrected later on.  */
66
67static void
68avr_elf_${EMULATION_NAME}_before_allocation (void)
69{
70  int ret;
71
72  gld${EMULATION_NAME}_before_allocation ();
73
74  /* We only need stubs for the avr6 family.  */
75  if (strcmp ("${EMULATION_NAME}","avr6"))
76    avr_no_stubs = TRUE;
77
78  avr_elf_set_global_bfd_parameters ();
79
80  /* If generating a relocatable output file, then
81     we don't  have to generate the trampolines.  */
82  if (link_info.relocatable)
83    avr_no_stubs = TRUE;
84
85  if (avr_no_stubs)
86    return;
87
88  ret = elf32_avr_setup_section_lists (link_info.output_bfd, &link_info);
89
90  if (ret < 0)
91    einfo ("%X%P: can not setup the input section list: %E\n");
92
93  if (ret <= 0)
94    return;
95
96  /* Call into the BFD backend to do the real "stub"-work.  */
97  if (! elf32_avr_size_stubs (link_info.output_bfd, &link_info, TRUE))
98    einfo ("%X%P: can not size stub section: %E\n");
99}
100
101/* This is called before the input files are opened.  We create a new
102   fake input file to hold the stub section and generate the section itself.  */
103
104static void
105avr_elf_create_output_section_statements (void)
106{
107  flagword flags;
108
109  stub_file = lang_add_input_file ("linker stubs",
110                                   lang_input_file_is_fake_enum,
111                                   NULL);
112
113  stub_file->the_bfd = bfd_create ("linker stubs", link_info.output_bfd);
114  if (stub_file->the_bfd == NULL
115      || !bfd_set_arch_mach (stub_file->the_bfd,
116                             bfd_get_arch (link_info.output_bfd),
117                             bfd_get_mach (link_info.output_bfd)))
118    {
119      einfo ("%X%P: can not create stub BFD %E\n");
120      return;
121    }
122
123  /* Now we add the stub section.  */
124
125  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
126           | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP);
127  avr_stub_section = bfd_make_section_anyway_with_flags (stub_file->the_bfd,
128							 ".trampolines",
129							 flags);
130  if (avr_stub_section == NULL)
131    goto err_ret;
132
133  avr_stub_section->alignment_power = 1;
134
135  ldlang_add_file (stub_file);
136
137  return;
138
139  err_ret:
140   einfo ("%X%P: can not make stub section: %E\n");
141   return;
142}
143
144/* Re-calculates the size of the stubs so that we won't waste space.  */
145
146static void
147avr_elf_finish (void)
148{
149  if (!avr_no_stubs)
150    {
151      /* Now build the linker stubs.  */
152      if (stub_file->the_bfd->sections != NULL)
153       {
154         /* Call again the trampoline analyzer to initialize the trampoline
155            stubs with the correct symbol addresses.  Since there could have
156            been relaxation, the symbol addresses that were found during
157            first call may no longer be correct.  */
158         if (!elf32_avr_size_stubs (link_info.output_bfd, &link_info, FALSE))
159           {
160             einfo ("%X%P: can not size stub section: %E\n");
161             return;
162           }
163
164         if (!elf32_avr_build_stubs (&link_info))
165           einfo ("%X%P: can not build stubs: %E\n");
166       }
167    }
168
169  gld${EMULATION_NAME}_finish ();
170}
171
172
173EOF
174
175
176PARSE_AND_LIST_PROLOGUE='
177
178#define OPTION_NO_CALL_RET_REPLACEMENT 301
179#define OPTION_PMEM_WRAP_AROUND        302
180#define OPTION_NO_STUBS                303
181#define OPTION_DEBUG_STUBS             304
182#define OPTION_DEBUG_RELAX             305
183'
184
185PARSE_AND_LIST_LONGOPTS='
186  { "no-call-ret-replacement", no_argument,
187     NULL, OPTION_NO_CALL_RET_REPLACEMENT},
188  { "pmem-wrap-around", required_argument,
189    NULL, OPTION_PMEM_WRAP_AROUND},
190  { "no-stubs", no_argument,
191    NULL, OPTION_NO_STUBS},
192  { "debug-stubs", no_argument,
193    NULL, OPTION_DEBUG_STUBS},
194  { "debug-relax", no_argument,
195    NULL, OPTION_DEBUG_RELAX},
196'
197
198PARSE_AND_LIST_OPTIONS='
199  fprintf (file, _("  --pmem-wrap-around=<val>    "
200		   "Make the linker relaxation machine assume that a\n"
201		   "                              "
202		   "  program counter wrap-around occures at address\n"
203		   "                              "
204		   "  <val>.  Supported values: 8k, 16k, 32k and 64k.\n"));
205  fprintf (file, _("  --no-call-ret-replacement   "
206		   "The relaxation machine normally will\n"
207		   "                              "
208		   "  substitute two immediately following call/ret\n"
209		   "                              "
210		   "  instructions by a single jump instruction.\n"
211		   "                              "
212		   "  This option disables this optimization.\n"));
213  fprintf (file, _("  --no-stubs                  "
214		   "If the linker detects to attempt to access\n"
215		   "                              "
216		   "  an instruction beyond 128k by a reloc that\n"
217		   "                              "
218		   "  is limited to 128k max, it inserts a jump\n"
219		   "                              "
220		   "  stub. You can de-active this with this switch.\n"));
221  fprintf (file, _("  --debug-stubs               "
222		   "Used for debugging avr-ld.\n"));
223  fprintf (file, _("  --debug-relax               "
224		   "Used for debugging avr-ld.\n"));
225'
226
227PARSE_AND_LIST_ARGS_CASES='
228
229    case OPTION_PMEM_WRAP_AROUND:
230      {
231        /* This variable is defined in the bfd library.  */
232        if ((!strcmp (optarg,"32k"))      || (!strcmp (optarg,"32K")))
233          avr_pc_wrap_around = 32768;
234        else if ((!strcmp (optarg,"8k")) || (!strcmp (optarg,"8K")))
235          avr_pc_wrap_around = 8192;
236        else if ((!strcmp (optarg,"16k")) || (!strcmp (optarg,"16K")))
237          avr_pc_wrap_around = 16384;
238        else if ((!strcmp (optarg,"64k")) || (!strcmp (optarg,"64K")))
239          avr_pc_wrap_around = 0x10000;
240        else
241          return FALSE;
242      }
243      break;
244
245    case OPTION_DEBUG_STUBS:
246      avr_debug_stubs = TRUE;
247      break;
248
249    case OPTION_DEBUG_RELAX:
250      avr_debug_relax = TRUE;
251      break;
252
253    case OPTION_NO_STUBS:
254      avr_no_stubs = TRUE;
255      break;
256
257    case OPTION_NO_CALL_RET_REPLACEMENT:
258      {
259        /* This variable is defined in the bfd library.  */
260        avr_replace_call_ret_sequences = FALSE;
261      }
262      break;
263'
264
265#
266# Put these extra avr-elf routines in ld_${EMULATION_NAME}_emulation
267#
268LDEMUL_BEFORE_ALLOCATION=avr_elf_${EMULATION_NAME}_before_allocation
269LDEMUL_FINISH=avr_elf_finish
270LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=avr_elf_create_output_section_statements
271