1214571Sdim# This shell script emits a C file. -*- C -*-
2214571Sdim#   Copyright 2006
3214571Sdim#   Free Software Foundation, Inc.
4214571Sdim#
5214571Sdim# This file is part of GLD, the Gnu Linker.
6214571Sdim#
7214571Sdim# This program is free software; you can redistribute it and/or modify
8214571Sdim# it under the terms of the GNU General Public License as published by
9214571Sdim# the Free Software Foundation; either version 2 of the License, or
10214571Sdim# (at your option) any later version.
11214571Sdim#
12214571Sdim# This program is distributed in the hope that it will be useful,
13214571Sdim# but WITHOUT ANY WARRANTY; without even the implied warranty of
14214571Sdim# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15214571Sdim# GNU General Public License for more details.
16214571Sdim#
17214571Sdim# You should have received a copy of the GNU General Public License
18214571Sdim# along with this program; if not, write to the Free Software
19214571Sdim# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 
20214571Sdim# MA 02110-1301 USA.
21214571Sdim
22214571Sdim# This file is sourced from elf32.em, and defines extra avr-elf
23214571Sdim# specific routines.  It is used to generate the trampolines for the avr6
24214571Sdim# family devices where one needs to address the issue that it is not possible
25214571Sdim# to reach the whole program memory by using 16 bit pointers.
26214571Sdim
27214571Sdimcat >>e${EMULATION_NAME}.c <<EOF
28214571Sdim
29214571Sdim#include "elf32-avr.h"
30214571Sdim#include "ldctor.h"
31214571Sdim
32214571Sdim/* The fake file and it's corresponding section meant to hold 
33214571Sdim   the linker stubs if needed.  */
34214571Sdim
35214571Sdimstatic lang_input_statement_type *stub_file;
36214571Sdimstatic asection *avr_stub_section;
37214571Sdim
38214571Sdim/* Variables set by the command-line parameters and transfered
39214571Sdim   to the bfd without use of global shared variables.  */
40214571Sdim
41214571Sdimstatic bfd_boolean avr_no_stubs = FALSE;
42214571Sdimstatic bfd_boolean avr_debug_relax = FALSE;
43214571Sdimstatic bfd_boolean avr_debug_stubs = FALSE;
44214571Sdimstatic bfd_boolean avr_replace_call_ret_sequences = TRUE;
45214571Sdimstatic bfd_vma avr_pc_wrap_around = 0x10000000;
46214571Sdim
47214571Sdim/* Transfers information to the bfd frontend.  */
48214571Sdim
49214571Sdimstatic void
50214571Sdimavr_elf_set_global_bfd_parameters (void)
51214571Sdim{
52214571Sdim  elf32_avr_setup_params (& link_info,
53214571Sdim                          stub_file->the_bfd,
54214571Sdim                          avr_stub_section,
55214571Sdim                          avr_no_stubs,
56214571Sdim                          avr_debug_stubs,
57214571Sdim                          avr_debug_relax,
58214571Sdim                          avr_pc_wrap_around,
59214571Sdim                          avr_replace_call_ret_sequences);
60214571Sdim}
61214571Sdim
62214571Sdim
63214571Sdim/* Makes a conservative estimate of the trampoline section size that could
64214571Sdim   be corrected later on.  */
65214571Sdim
66214571Sdimstatic void
67214571Sdimavr_elf_${EMULATION_NAME}_before_allocation (void)
68214571Sdim{
69214571Sdim  int ret;
70214571Sdim
71214571Sdim  gld${EMULATION_NAME}_before_allocation ();
72214571Sdim
73214571Sdim  /* We only need stubs for the avr6 family.  */
74214571Sdim  if (strcmp ("${EMULATION_NAME}","avr6"))
75214571Sdim    avr_no_stubs = TRUE;
76214571Sdim
77214571Sdim  avr_elf_set_global_bfd_parameters ();
78214571Sdim
79214571Sdim  /* If generating a relocatable output file, then
80214571Sdim     we don't  have to generate the trampolines.  */
81214571Sdim  if (link_info.relocatable)
82214571Sdim    avr_no_stubs = TRUE;
83214571Sdim
84214571Sdim  if (avr_no_stubs)
85214571Sdim    return;
86214571Sdim
87214571Sdim  ret = elf32_avr_setup_section_lists (output_bfd, &link_info);
88214571Sdim
89214571Sdim  if (ret < 0)
90214571Sdim    einfo ("%X%P: can not setup the input section list: %E\n");
91214571Sdim
92214571Sdim  if (ret <= 0)
93214571Sdim    return;
94214571Sdim
95214571Sdim  /* Call into the BFD backend to do the real "stub"-work.  */
96214571Sdim  if (! elf32_avr_size_stubs (output_bfd, &link_info, TRUE))
97214571Sdim    einfo ("%X%P: can not size stub section: %E\n");
98214571Sdim}
99214571Sdim
100214571Sdim/* This is called before the input files are opened.  We create a new
101214571Sdim   fake input file to hold the stub section and generate the section itself.  */
102214571Sdim
103214571Sdimstatic void
104214571Sdimavr_elf_create_output_section_statements (void)
105214571Sdim{
106214571Sdim  flagword flags;
107214571Sdim
108214571Sdim  stub_file = lang_add_input_file ("linker stubs",
109214571Sdim                                   lang_input_file_is_fake_enum,
110214571Sdim                                   NULL);
111214571Sdim
112214571Sdim  stub_file->the_bfd = bfd_create ("linker stubs", output_bfd);
113214571Sdim  if (stub_file->the_bfd == NULL
114214571Sdim      || !bfd_set_arch_mach (stub_file->the_bfd,
115214571Sdim                             bfd_get_arch (output_bfd),
116214571Sdim                             bfd_get_mach (output_bfd)))
117214571Sdim    {
118214571Sdim      einfo ("%X%P: can not create stub BFD %E\n");
119214571Sdim      return;
120214571Sdim    }
121214571Sdim
122214571Sdim  /* Now we add the stub section.  */
123214571Sdim
124214571Sdim  avr_stub_section = bfd_make_section_anyway (stub_file->the_bfd,
125214571Sdim                                              ".trampolines");
126214571Sdim  if (avr_stub_section == NULL)
127214571Sdim    goto err_ret;
128214571Sdim  
129214571Sdim  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
130214571Sdim           | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP);
131214571Sdim  if (!bfd_set_section_flags (stub_file->the_bfd, avr_stub_section, flags))
132214571Sdim    goto err_ret;
133214571Sdim
134214571Sdim  avr_stub_section->alignment_power = 1;
135214571Sdim  
136214571Sdim  ldlang_add_file (stub_file);
137214571Sdim
138214571Sdim  return;
139214571Sdim
140214571Sdim  err_ret:
141214571Sdim   einfo ("%X%P: can not make stub section: %E\n");
142214571Sdim   return;
143214571Sdim}
144214571Sdim
145214571Sdim/* Re-calculates the size of the stubs so that we won't waste space.  */
146214571Sdim
147214571Sdimstatic void
148214571Sdimavr_elf_finish (void)
149214571Sdim{ 
150214571Sdim  if (!avr_no_stubs)
151214571Sdim    {
152214571Sdim      /* Now build the linker stubs.  */
153214571Sdim      if (stub_file->the_bfd->sections != NULL)
154214571Sdim       {
155214571Sdim         /* Call again the trampoline analyzer to initialize the trampoline
156214571Sdim            stubs with the correct symbol addresses.  Since there could have
157214571Sdim            been relaxation, the symbol addresses that were found during
158214571Sdim            first call may no longer be correct.  */
159214571Sdim         if (!elf32_avr_size_stubs (output_bfd, &link_info, FALSE))
160214571Sdim           {
161214571Sdim             einfo ("%X%P: can not size stub section: %E\n");
162214571Sdim             return;
163214571Sdim           }
164214571Sdim
165214571Sdim         if (!elf32_avr_build_stubs (&link_info))
166214571Sdim           einfo ("%X%P: can not build stubs: %E\n");
167214571Sdim       }
168214571Sdim    }
169214571Sdim
170214571Sdim  gld${EMULATION_NAME}_finish ();
171214571Sdim}
172214571Sdim
173214571Sdim
174214571SdimEOF
175214571Sdim
176214571Sdim
177214571SdimPARSE_AND_LIST_PROLOGUE='
178214571Sdim
179214571Sdim#define OPTION_NO_CALL_RET_REPLACEMENT 301
180214571Sdim#define OPTION_PMEM_WRAP_AROUND        302
181214571Sdim#define OPTION_NO_STUBS                303
182214571Sdim#define OPTION_DEBUG_STUBS             304
183214571Sdim#define OPTION_DEBUG_RELAX             305
184214571Sdim'
185214571Sdim
186214571SdimPARSE_AND_LIST_LONGOPTS='
187214571Sdim  { "no-call-ret-replacement", no_argument, 
188214571Sdim     NULL, OPTION_NO_CALL_RET_REPLACEMENT},
189214571Sdim  { "pmem-wrap-around", required_argument, 
190214571Sdim    NULL, OPTION_PMEM_WRAP_AROUND},
191214571Sdim  { "no-stubs", no_argument, 
192214571Sdim    NULL, OPTION_NO_STUBS},
193214571Sdim  { "debug-stubs", no_argument, 
194214571Sdim    NULL, OPTION_DEBUG_STUBS},
195214571Sdim  { "debug-relax", no_argument, 
196214571Sdim    NULL, OPTION_DEBUG_RELAX},
197214571Sdim'
198214571Sdim
199214571SdimPARSE_AND_LIST_OPTIONS='
200214571Sdim  fprintf (file, _("     --pmem-wrap-around=<val> "
201214571Sdim                           "Make the linker relaxation machine assume that a\n"
202214571Sdim                   "                              "
203214571Sdim                           "program counter wrap-around occures at address\n"
204214571Sdim                   "                              "
205214571Sdim                           "<val>. Supported values are 8k, 16k, 32k and 64k.\n"));
206214571Sdim  fprintf (file, _("     --no-call-ret-replacement "
207214571Sdim                           "The relaxation machine normally will\n"
208214571Sdim                   "                               "
209214571Sdim                           "substitute two immediately following call/ret\n"
210214571Sdim                   "                               "
211214571Sdim                           "instructions by a single jump instruction.\n"
212214571Sdim                   "                               "
213214571Sdim                           "This option disables this optimization.\n"));
214214571Sdim  fprintf (file, _("     --no-stubs "
215214571Sdim                           "If the linker detects to attempt to access\n"
216214571Sdim                   "                               "
217214571Sdim                           "an instruction beyond 128k by a reloc that\n"
218214571Sdim                   "                               "
219214571Sdim                           "is limited to 128k max, it inserts a jump\n"
220214571Sdim                   "                               "
221214571Sdim                           "stub. You can de-active this with this switch.\n"));
222214571Sdim  fprintf (file, _("     --debug-stubs Used for debugging avr-ld.\n"));
223214571Sdim  fprintf (file, _("     --debug-relax Used for debugging avr-ld.\n"));
224214571Sdim'
225214571Sdim
226214571SdimPARSE_AND_LIST_ARGS_CASES='
227214571Sdim
228214571Sdim    case OPTION_PMEM_WRAP_AROUND:
229214571Sdim      { 
230214571Sdim        /* This variable is defined in the bfd library.  */
231214571Sdim        if ((!strcmp (optarg,"32k"))      || (!strcmp (optarg,"32K")))
232214571Sdim          avr_pc_wrap_around = 32768;
233214571Sdim        else if ((!strcmp (optarg,"8k")) || (!strcmp (optarg,"8K")))
234214571Sdim          avr_pc_wrap_around = 8192;
235214571Sdim        else if ((!strcmp (optarg,"16k")) || (!strcmp (optarg,"16K")))
236214571Sdim          avr_pc_wrap_around = 16384;
237214571Sdim        else if ((!strcmp (optarg,"64k")) || (!strcmp (optarg,"64K")))
238214571Sdim          avr_pc_wrap_around = 0x10000;
239214571Sdim        else
240214571Sdim          return FALSE;
241214571Sdim      }
242214571Sdim      break;
243214571Sdim
244214571Sdim    case OPTION_DEBUG_STUBS:
245214571Sdim      avr_debug_stubs = TRUE;
246214571Sdim      break;
247214571Sdim
248214571Sdim    case OPTION_DEBUG_RELAX:
249214571Sdim      avr_debug_relax = TRUE;
250214571Sdim      break;
251214571Sdim
252214571Sdim    case OPTION_NO_STUBS:
253214571Sdim      avr_no_stubs = TRUE;
254214571Sdim      break;
255214571Sdim
256214571Sdim    case OPTION_NO_CALL_RET_REPLACEMENT:
257214571Sdim      {
258214571Sdim        /* This variable is defined in the bfd library.  */
259214571Sdim        avr_replace_call_ret_sequences = FALSE;
260214571Sdim      }
261214571Sdim      break;
262214571Sdim'
263214571Sdim
264214571Sdim#
265214571Sdim# Put these extra avr-elf routines in ld_${EMULATION_NAME}_emulation
266214571Sdim#
267214571SdimLDEMUL_BEFORE_ALLOCATION=avr_elf_${EMULATION_NAME}_before_allocation
268214571SdimLDEMUL_FINISH=avr_elf_finish
269214571SdimLDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=avr_elf_create_output_section_statements
270