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