cskyelf.em revision 1.1.1.2 1 1.1 christos # This shell script emits a C file. -*- C -*-
2 1.1.1.2 christos # Copyright (C) 2013-2022 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 christos einfo (_("%F%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_PROLOGUE='
292 1.1 christos #define OPTION_BRANCH_STUB 301
293 1.1 christos #define OPTION_NO_BRANCH_STUB 302
294 1.1 christos #define OPTION_STUBGROUP_SIZE 303
295 1.1 christos '
296 1.1 christos
297 1.1 christos PARSE_AND_LIST_LONGOPTS='
298 1.1 christos {"branch-stub", no_argument, NULL, OPTION_BRANCH_STUB},
299 1.1 christos {"no-branch-stub", no_argument, NULL, OPTION_NO_BRANCH_STUB},
300 1.1 christos {"stub-group-size", required_argument, NULL, OPTION_STUBGROUP_SIZE},
301 1.1 christos '
302 1.1 christos PARSE_AND_LIST_OPTIONS='
303 1.1.1.2 christos fprintf (file, _(" --[no-]branch-stub "
304 1.1.1.2 christos "Disable/enable use of stubs to expand branch\n"
305 1.1.1.2 christos " "
306 1.1.1.2 christos " instructions that cannot reach the target.\n"));
307 1.1.1.2 christos fprintf (file, _(" --stub-group-size=N "
308 1.1.1.2 christos "Maximum size of a group of input sections\n"
309 1.1.1.2 christos " "
310 1.1.1.2 christos " handled by one stub section.\n"));
311 1.1 christos '
312 1.1 christos
313 1.1 christos PARSE_AND_LIST_ARGS_CASES='
314 1.1 christos case OPTION_BRANCH_STUB:
315 1.1.1.2 christos use_branch_stub = true;
316 1.1 christos break;
317 1.1 christos case OPTION_NO_BRANCH_STUB:
318 1.1.1.2 christos use_branch_stub = false;
319 1.1 christos break;
320 1.1 christos
321 1.1 christos case OPTION_STUBGROUP_SIZE:
322 1.1 christos {
323 1.1 christos const char *end;
324 1.1 christos
325 1.1 christos group_size = bfd_scan_vma (optarg, &end, 0);
326 1.1 christos if (*end)
327 1.1 christos einfo (_("%F%P: invalid number `%s'\''\n"), optarg);
328 1.1 christos }
329 1.1 christos break;
330 1.1 christos '
331 1.1 christos
332 1.1 christos case ${target} in
333 1.1 christos csky-*-linux-*) LDEMUL_BEFORE_PARSE=csky_elf_before_parse ;;
334 1.1 christos esac
335 1.1 christos LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation
336 1.1 christos LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=csky_elf_create_output_section_statements
337 1.1 christos LDEMUL_FINISH=gld${EMULATION_NAME}_finish
338