]>
Commit | Line | Data |
---|---|---|
837a17b3 NC |
1 | # This shell script emits a C file. -*- C -*- |
2 | # It does some substitutions. | |
3 | fragment <<EOF | |
4 | /* This file is is generated by a shell script. DO NOT EDIT! */ | |
5 | ||
6 | /* Emulate the original gld for the given ${EMULATION_NAME} | |
fd67aa11 | 7 | Copyright (C) 2014-2024 Free Software Foundation, Inc. |
837a17b3 NC |
8 | Written by Steve Chamberlain steve@cygnus.com |
9 | Extended for the MSP430 by Nick Clifton nickc@redhat.com | |
6c19b93b | 10 | |
837a17b3 NC |
11 | This file is part of the GNU Binutils. |
12 | ||
13 | This program is free software; you can redistribute it and/or modify | |
14 | it under the terms of the GNU General Public License as published by | |
15 | the Free Software Foundation; either version 3 of the License, or | |
16 | (at your option) any later version. | |
17 | ||
18 | This program is distributed in the hope that it will be useful, | |
19 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 | GNU General Public License for more details. | |
22 | ||
23 | You should have received a copy of the GNU General Public License | |
24 | along with this program; if not, write to the Free Software | |
25 | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | |
26 | MA 02110-1301, USA. */ | |
27 | ||
28 | #define TARGET_IS_${EMULATION_NAME} | |
29 | ||
30 | #include "sysdep.h" | |
31 | #include "bfd.h" | |
32 | #include "bfdlink.h" | |
1ff6de03 | 33 | #include "ctf-api.h" |
837a17b3 NC |
34 | |
35 | #include "ld.h" | |
7ef3addb | 36 | #include "getopt.h" |
837a17b3 NC |
37 | #include "ldmain.h" |
38 | #include "ldmisc.h" | |
39 | #include "ldexp.h" | |
40 | #include "ldlang.h" | |
41 | #include "ldfile.h" | |
8d10083c | 42 | #include "ldlex.h" |
837a17b3 NC |
43 | #include "ldemul.h" |
44 | #include "libiberty.h" | |
7ef3addb JL |
45 | #include <ldgram.h> |
46 | ||
47 | enum regions | |
48 | { | |
49 | REGION_NONE = 0, | |
50 | REGION_LOWER, | |
51 | REGION_UPPER, | |
52 | REGION_EITHER = 3, | |
53 | }; | |
54 | ||
55 | enum either_placement_stage | |
56 | { | |
57 | LOWER_TO_UPPER, | |
58 | UPPER_TO_LOWER, | |
59 | }; | |
60 | ||
61 | enum { ROM, RAM }; | |
62 | ||
63 | static int data_region = REGION_NONE; | |
64 | static int code_region = REGION_NONE; | |
f38a2680 | 65 | static bool disable_sec_transformation = false; |
7ef3addb JL |
66 | |
67 | #define MAX_PREFIX_LENGTH 7 | |
837a17b3 NC |
68 | |
69 | EOF | |
70 | ||
71 | # Import any needed special functions and/or overrides. | |
72 | # | |
73 | if test -n "$EXTRA_EM_FILE" ; then | |
74 | source_em ${srcdir}/emultempl/${EXTRA_EM_FILE}.em | |
75 | fi | |
76 | ||
77 | if test x"$LDEMUL_BEFORE_PARSE" != xgld"$EMULATION_NAME"_before_parse; then | |
78 | fragment <<EOF | |
79 | ||
80 | static void | |
81 | gld${EMULATION_NAME}_before_parse (void) | |
82 | { | |
83 | #ifndef TARGET_ /* I.e., if not generic. */ | |
84 | ldfile_set_output_arch ("`echo ${ARCH}`", bfd_arch_unknown); | |
85 | #endif /* not TARGET_ */ | |
86 | ||
87 | /* The MSP430 port *needs* linker relaxtion in order to cope with large | |
88 | functions where conditional branches do not fit into a +/- 1024 byte range. */ | |
0e1862bb | 89 | if (!bfd_link_relocatable (&link_info)) |
837a17b3 NC |
90 | TARGET_ENABLE_RELAXATION; |
91 | } | |
92 | ||
93 | EOF | |
94 | fi | |
95 | ||
96 | if test x"$LDEMUL_GET_SCRIPT" != xgld"$EMULATION_NAME"_get_script; then | |
97 | fragment <<EOF | |
98 | ||
99 | static char * | |
100 | gld${EMULATION_NAME}_get_script (int *isfile) | |
101 | EOF | |
102 | ||
103 | if test x"$COMPILE_IN" = xyes | |
104 | then | |
105 | # Scripts compiled in. | |
106 | ||
107 | # sed commands to quote an ld script as a C string. | |
b8a0c930 | 108 | sc="-f ${srcdir}/emultempl/stringify.sed" |
837a17b3 NC |
109 | |
110 | fragment <<EOF | |
111 | { | |
112 | *isfile = 0; | |
113 | ||
0e1862bb | 114 | if (bfd_link_relocatable (&link_info) && config.build_constructors) |
837a17b3 NC |
115 | return |
116 | EOF | |
117 | sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c | |
0e1862bb | 118 | echo ' ; else if (bfd_link_relocatable (&link_info)) return' >> e${EMULATION_NAME}.c |
837a17b3 NC |
119 | sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c |
120 | echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c | |
121 | sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c | |
122 | echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c | |
123 | sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c | |
124 | echo ' ; else return' >> e${EMULATION_NAME}.c | |
125 | sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c | |
126 | echo '; }' >> e${EMULATION_NAME}.c | |
127 | ||
128 | else | |
129 | # Scripts read from the filesystem. | |
130 | ||
131 | fragment <<EOF | |
132 | { | |
133 | *isfile = 1; | |
134 | ||
0e1862bb | 135 | if (bfd_link_relocatable (&link_info) && config.build_constructors) |
837a17b3 | 136 | return "ldscripts/${EMULATION_NAME}.xu"; |
0e1862bb | 137 | else if (bfd_link_relocatable (&link_info)) |
837a17b3 NC |
138 | return "ldscripts/${EMULATION_NAME}.xr"; |
139 | else if (!config.text_read_only) | |
140 | return "ldscripts/${EMULATION_NAME}.xbn"; | |
141 | else if (!config.magic_demand_paged) | |
142 | return "ldscripts/${EMULATION_NAME}.xn"; | |
143 | else | |
144 | return "ldscripts/${EMULATION_NAME}.x"; | |
145 | } | |
146 | EOF | |
147 | fi | |
148 | fi | |
149 | ||
150 | if test x"$LDEMUL_PLACE_ORPHAN" != xgld"$EMULATION_NAME"_place_orphan; then | |
151 | fragment <<EOF | |
152 | ||
7ef3addb JL |
153 | static unsigned int |
154 | data_statement_size (lang_data_statement_type *d) | |
155 | { | |
156 | unsigned int size = 0; | |
157 | switch (d->type) | |
158 | { | |
159 | case QUAD: | |
160 | case SQUAD: | |
161 | size = QUAD_SIZE; | |
162 | break; | |
163 | case LONG: | |
164 | size = LONG_SIZE; | |
165 | break; | |
166 | case SHORT: | |
167 | size = SHORT_SIZE; | |
168 | break; | |
169 | case BYTE: | |
170 | size = BYTE_SIZE; | |
171 | break; | |
172 | default: | |
d003af55 | 173 | einfo (_("%P: error: unhandled data_statement size\n")); |
7ef3addb JL |
174 | FAIL (); |
175 | } | |
176 | return size; | |
177 | } | |
178 | ||
837a17b3 NC |
179 | /* Helper function for place_orphan that computes the size |
180 | of sections already mapped to the given statement. */ | |
181 | ||
182 | static bfd_size_type | |
183 | scan_children (lang_statement_union_type * l) | |
184 | { | |
185 | bfd_size_type amount = 0; | |
186 | ||
187 | while (l != NULL) | |
188 | { | |
189 | switch (l->header.type) | |
190 | { | |
191 | case lang_input_section_enum: | |
192 | if (l->input_section.section->flags & SEC_ALLOC) | |
193 | amount += l->input_section.section->size; | |
194 | break; | |
195 | ||
196 | case lang_constructors_statement_enum: | |
197 | case lang_assignment_statement_enum: | |
7ef3addb | 198 | case lang_padding_statement_enum: |
837a17b3 NC |
199 | break; |
200 | ||
201 | case lang_wild_statement_enum: | |
6c19b93b | 202 | amount += scan_children (l->wild_statement.children.head); |
837a17b3 NC |
203 | break; |
204 | ||
7ef3addb JL |
205 | case lang_data_statement_enum: |
206 | amount += data_statement_size (&l->data_statement); | |
207 | break; | |
208 | ||
837a17b3 NC |
209 | default: |
210 | fprintf (stderr, "msp430 orphan placer: unhandled lang type %d\n", l->header.type); | |
211 | break; | |
212 | } | |
213 | ||
214 | l = l->header.next; | |
215 | } | |
216 | ||
217 | return amount; | |
218 | } | |
6c19b93b | 219 | |
e25de718 JL |
220 | #define WARN_UPPER 0 |
221 | #define WARN_LOWER 1 | |
222 | #define WARN_TEXT 0 | |
223 | #define WARN_DATA 1 | |
224 | #define WARN_BSS 2 | |
225 | #define WARN_RODATA 3 | |
226 | ||
227 | /* Warn only once per output section. | |
228 | * NAME starts with ".upper." or ".lower.". */ | |
229 | static void | |
230 | warn_no_output_section (const char *name) | |
231 | { | |
f38a2680 AM |
232 | static bool warned[2][4] = {{false, false, false, false}, |
233 | {false, false, false, false}}; | |
e25de718 JL |
234 | int i = WARN_LOWER; |
235 | ||
236 | if (strncmp (name, ".upper.", 7) == 0) | |
237 | i = WARN_UPPER; | |
238 | ||
239 | if (!warned[i][WARN_TEXT] && strcmp (name + 6, ".text") == 0) | |
f38a2680 | 240 | warned[i][WARN_TEXT] = true; |
e25de718 | 241 | else if (!warned[i][WARN_DATA] && strcmp (name + 6, ".data") == 0) |
f38a2680 | 242 | warned[i][WARN_DATA] = true; |
e25de718 | 243 | else if (!warned[i][WARN_BSS] && strcmp (name + 6, ".bss") == 0) |
f38a2680 | 244 | warned[i][WARN_BSS] = true; |
e25de718 | 245 | else if (!warned[i][WARN_RODATA] && strcmp (name + 6, ".rodata") == 0) |
f38a2680 | 246 | warned[i][WARN_RODATA] = true; |
e25de718 JL |
247 | else |
248 | return; | |
249 | einfo ("%P: warning: no input section rule matches %s in linker script\n", | |
250 | name); | |
251 | } | |
252 | ||
253 | ||
837a17b3 NC |
254 | /* Place an orphan section. We use this to put .either sections |
255 | into either their lower or their upper equivalents. */ | |
256 | ||
257 | static lang_output_section_statement_type * | |
258 | gld${EMULATION_NAME}_place_orphan (asection * s, | |
259 | const char * secname, | |
260 | int constraint) | |
261 | { | |
262 | char * lower_name; | |
263 | char * upper_name; | |
264 | char * name; | |
265 | lang_output_section_statement_type * lower; | |
266 | lang_output_section_statement_type * upper; | |
837a17b3 NC |
267 | |
268 | if ((s->flags & SEC_ALLOC) == 0) | |
269 | return NULL; | |
270 | ||
0e1862bb | 271 | if (bfd_link_relocatable (&link_info)) |
837a17b3 NC |
272 | return NULL; |
273 | ||
274 | /* If constraints are involved let the linker handle the placement normally. */ | |
275 | if (constraint != 0) | |
276 | return NULL; | |
277 | ||
e25de718 JL |
278 | if (strncmp (secname, ".upper.", 7) == 0 |
279 | || strncmp (secname, ".lower.", 7) == 0) | |
280 | { | |
281 | warn_no_output_section (secname); | |
282 | return NULL; | |
283 | } | |
284 | ||
837a17b3 NC |
285 | /* We only need special handling for .either sections. */ |
286 | if (strncmp (secname, ".either.", 8) != 0) | |
287 | return NULL; | |
288 | ||
289 | /* Skip the .either prefix. */ | |
290 | secname += 7; | |
291 | ||
292 | /* Compute the names of the corresponding upper and lower | |
293 | sections. If the input section name contains another period, | |
294 | only use the part of the name before the second dot. */ | |
295 | if (strchr (secname + 1, '.') != NULL) | |
296 | { | |
82b94616 | 297 | name = xstrdup (secname); |
837a17b3 NC |
298 | |
299 | * strchr (name + 1, '.') = 0; | |
300 | } | |
301 | else | |
302 | name = (char *) secname; | |
6c19b93b | 303 | |
e1fa0163 NC |
304 | lower_name = concat (".lower", name, NULL); |
305 | upper_name = concat (".upper", name, NULL); | |
837a17b3 NC |
306 | |
307 | /* Find the corresponding lower and upper sections. */ | |
308 | lower = lang_output_section_find (lower_name); | |
309 | upper = lang_output_section_find (upper_name); | |
837a17b3 | 310 | |
7ef3addb JL |
311 | if (lower == NULL && upper == NULL) |
312 | { | |
d003af55 | 313 | einfo (_("%P: error: no section named %s or %s in linker script\n"), |
7ef3addb JL |
314 | lower_name, upper_name); |
315 | goto end; | |
316 | } | |
317 | else if (lower == NULL) | |
837a17b3 | 318 | { |
7ef3addb JL |
319 | lower = lang_output_section_find (name); |
320 | if (lower == NULL) | |
321 | { | |
d003af55 | 322 | einfo (_("%P: error: no section named %s in linker script\n"), name); |
e1fa0163 | 323 | goto end; |
837a17b3 NC |
324 | } |
325 | } | |
7ef3addb JL |
326 | |
327 | /* Always place orphaned sections in lower. Optimal placement of either | |
328 | sections is performed later, once section sizes have been finalized. */ | |
b209b5a6 | 329 | lang_add_section (& lower->children, s, NULL, NULL, lower); |
7ef3addb JL |
330 | end: |
331 | free (upper_name); | |
332 | free (lower_name); | |
7ef3addb JL |
333 | return lower; |
334 | } | |
335 | EOF | |
336 | fi | |
337 | ||
338 | fragment <<EOF | |
339 | ||
f38a2680 | 340 | static bool |
1a9f72a7 | 341 | change_output_section (lang_statement_union_type **head, |
7ef3addb | 342 | asection *s, |
1a9f72a7 JL |
343 | lang_output_section_statement_type *new_os, |
344 | lang_output_section_statement_type *old_os) | |
7ef3addb JL |
345 | { |
346 | asection *is; | |
347 | lang_statement_union_type * prev = NULL; | |
348 | lang_statement_union_type * curr; | |
349 | ||
350 | curr = *head; | |
351 | while (curr != NULL) | |
352 | { | |
353 | switch (curr->header.type) | |
354 | { | |
355 | case lang_input_section_enum: | |
356 | is = curr->input_section.section; | |
357 | if (is == s) | |
358 | { | |
1a9f72a7 JL |
359 | lang_statement_list_type *old_list |
360 | = (lang_statement_list_type *) &old_os->children; | |
7ef3addb | 361 | s->output_section = NULL; |
b209b5a6 AM |
362 | lang_add_section (&new_os->children, s, |
363 | curr->input_section.pattern, NULL, new_os); | |
1a9f72a7 | 364 | |
7ef3addb JL |
365 | /* Remove the section from the old output section. */ |
366 | if (prev == NULL) | |
367 | *head = curr->header.next; | |
368 | else | |
369 | prev->header.next = curr->header.next; | |
1a9f72a7 JL |
370 | /* If the input section we just moved is the tail of the old |
371 | output section, then we also need to adjust that tail. */ | |
372 | if (old_list->tail == (lang_statement_union_type **) curr) | |
373 | old_list->tail = (lang_statement_union_type **) prev; | |
374 | ||
f38a2680 | 375 | return true; |
7ef3addb JL |
376 | } |
377 | break; | |
378 | case lang_wild_statement_enum: | |
379 | if (change_output_section (&(curr->wild_statement.children.head), | |
1a9f72a7 | 380 | s, new_os, old_os)) |
f38a2680 | 381 | return true; |
7ef3addb JL |
382 | break; |
383 | default: | |
384 | break; | |
385 | } | |
386 | prev = curr; | |
387 | curr = curr->header.next; | |
388 | } | |
f38a2680 | 389 | return false; |
7ef3addb JL |
390 | } |
391 | ||
7ef3addb | 392 | static void |
fd361982 AM |
393 | add_region_prefix (bfd *abfd ATTRIBUTE_UNUSED, asection *s, |
394 | void *unused ATTRIBUTE_UNUSED) | |
7ef3addb | 395 | { |
fd361982 | 396 | const char *curr_name = bfd_section_name (s); |
7ef3addb JL |
397 | int region = REGION_NONE; |
398 | ||
399 | if (strncmp (curr_name, ".text", 5) == 0) | |
e25de718 | 400 | region = code_region; |
7ef3addb | 401 | else if (strncmp (curr_name, ".data", 5) == 0) |
e25de718 | 402 | region = data_region; |
7ef3addb | 403 | else if (strncmp (curr_name, ".bss", 4) == 0) |
e25de718 | 404 | region = data_region; |
7ef3addb | 405 | else if (strncmp (curr_name, ".rodata", 7) == 0) |
e25de718 | 406 | region = data_region; |
7ef3addb JL |
407 | else |
408 | return; | |
409 | ||
410 | switch (region) | |
411 | { | |
412 | case REGION_NONE: | |
413 | break; | |
414 | case REGION_UPPER: | |
fd361982 | 415 | bfd_rename_section (s, concat (".upper", curr_name, NULL)); |
7ef3addb JL |
416 | break; |
417 | case REGION_LOWER: | |
fd361982 | 418 | bfd_rename_section (s, concat (".lower", curr_name, NULL)); |
7ef3addb JL |
419 | break; |
420 | case REGION_EITHER: | |
e7d942e0 | 421 | bfd_rename_section (s, concat (".either", curr_name, NULL)); |
7ef3addb JL |
422 | break; |
423 | default: | |
424 | /* Unreachable. */ | |
425 | FAIL (); | |
426 | break; | |
427 | } | |
7ef3addb JL |
428 | } |
429 | ||
430 | static void | |
431 | msp430_elf_after_open (void) | |
432 | { | |
433 | bfd *abfd; | |
434 | ||
435 | gld${EMULATION_NAME}_after_open (); | |
837a17b3 | 436 | |
7ef3addb JL |
437 | /* If neither --code-region or --data-region have been passed, do not |
438 | transform sections names. */ | |
439 | if ((code_region == REGION_NONE && data_region == REGION_NONE) | |
440 | || disable_sec_transformation) | |
441 | return; | |
442 | ||
443 | for (abfd = link_info.input_bfds; abfd != NULL; abfd = abfd->link.next) | |
444 | bfd_map_over_sections (abfd, add_region_prefix, NULL); | |
445 | } | |
446 | ||
7ef3addb JL |
447 | static void |
448 | gld${EMULATION_NAME}_add_options | |
449 | (int ns, char **shortopts, int nl, struct option **longopts, | |
450 | int nrl ATTRIBUTE_UNUSED, struct option **really_longopts ATTRIBUTE_UNUSED) | |
451 | { | |
452 | static const char xtra_short[] = { }; | |
837a17b3 | 453 | |
7ef3addb JL |
454 | static const struct option xtra_long[] = |
455 | { | |
456 | { "code-region", required_argument, NULL, OPTION_CODE_REGION }, | |
457 | { "data-region", required_argument, NULL, OPTION_DATA_REGION }, | |
458 | { "disable-sec-transformation", no_argument, NULL, | |
459 | OPTION_DISABLE_TRANS }, | |
460 | { NULL, no_argument, NULL, 0 } | |
461 | }; | |
462 | ||
463 | *shortopts = (char *) xrealloc (*shortopts, ns + sizeof (xtra_short)); | |
464 | memcpy (*shortopts + ns, &xtra_short, sizeof (xtra_short)); | |
465 | *longopts = (struct option *) | |
466 | xrealloc (*longopts, nl * sizeof (struct option) + sizeof (xtra_long)); | |
467 | memcpy (*longopts + nl, &xtra_long, sizeof (xtra_long)); | |
468 | } | |
837a17b3 | 469 | |
7ef3addb JL |
470 | static void |
471 | gld${EMULATION_NAME}_list_options (FILE * file) | |
472 | { | |
df5f2391 AM |
473 | fprintf (file, _(" --code-region={either,lower,upper,none}\n\ |
474 | Transform .text* sections to {either,lower,upper,none}.text* sections\n")); | |
475 | fprintf (file, _(" --data-region={either,lower,upper,none}\n\ | |
476 | Transform .data*, .rodata* and .bss* sections to\n\ | |
477 | {either,lower,upper,none}.{bss,data,rodata}* sections\n")); | |
478 | fprintf (file, _(" --disable-sec-transformation\n\ | |
479 | Disable transformation of .{text,data,bss,rodata}* sections to\n\ | |
480 | add the {either,lower,upper,none} prefixes\n")); | |
7ef3addb | 481 | } |
837a17b3 | 482 | |
f38a2680 | 483 | static bool |
7ef3addb JL |
484 | gld${EMULATION_NAME}_handle_option (int optc) |
485 | { | |
486 | switch (optc) | |
487 | { | |
488 | case OPTION_CODE_REGION: | |
489 | if (strcmp (optarg, "upper") == 0) | |
490 | code_region = REGION_UPPER; | |
491 | else if (strcmp (optarg, "lower") == 0) | |
492 | code_region = REGION_LOWER; | |
493 | else if (strcmp (optarg, "either") == 0) | |
494 | code_region = REGION_EITHER; | |
495 | else if (strcmp (optarg, "none") == 0) | |
496 | code_region = REGION_NONE; | |
497 | else if (strlen (optarg) == 0) | |
498 | { | |
df5f2391 AM |
499 | einfo (_("%P: --code-region requires an argument: " |
500 | "{upper,lower,either,none}\n")); | |
f38a2680 | 501 | return false; |
7ef3addb | 502 | } |
837a17b3 | 503 | else |
7ef3addb | 504 | { |
df5f2391 AM |
505 | einfo (_("%P: error: unrecognized argument to --code-region= option: " |
506 | "\"%s\"\n"), optarg); | |
f38a2680 | 507 | return false; |
7ef3addb JL |
508 | } |
509 | break; | |
510 | ||
511 | case OPTION_DATA_REGION: | |
512 | if (strcmp (optarg, "upper") == 0) | |
513 | data_region = REGION_UPPER; | |
514 | else if (strcmp (optarg, "lower") == 0) | |
515 | data_region = REGION_LOWER; | |
516 | else if (strcmp (optarg, "either") == 0) | |
517 | data_region = REGION_EITHER; | |
518 | else if (strcmp (optarg, "none") == 0) | |
519 | data_region = REGION_NONE; | |
520 | else if (strlen (optarg) == 0) | |
521 | { | |
df5f2391 AM |
522 | einfo (_("%P: --data-region requires an argument: " |
523 | "{upper,lower,either,none}\n")); | |
f38a2680 | 524 | return false; |
7ef3addb JL |
525 | } |
526 | else | |
527 | { | |
df5f2391 AM |
528 | einfo (_("%P: error: unrecognized argument to --data-region= option: " |
529 | "\"%s\"\n"), optarg); | |
f38a2680 | 530 | return false; |
7ef3addb JL |
531 | } |
532 | break; | |
533 | ||
534 | case OPTION_DISABLE_TRANS: | |
f38a2680 | 535 | disable_sec_transformation = true; |
7ef3addb JL |
536 | break; |
537 | ||
538 | default: | |
f38a2680 | 539 | return false; |
7ef3addb | 540 | } |
f38a2680 | 541 | return true; |
7ef3addb JL |
542 | } |
543 | ||
544 | static void | |
fd361982 AM |
545 | eval_upper_either_sections (bfd *abfd ATTRIBUTE_UNUSED, |
546 | asection *s, void *data) | |
7ef3addb | 547 | { |
96d01d93 | 548 | const char * base_sec_name; |
7ef3addb JL |
549 | const char * curr_name; |
550 | char * either_name; | |
551 | int curr_region; | |
552 | ||
553 | lang_output_section_statement_type * lower; | |
554 | lang_output_section_statement_type * upper; | |
555 | static bfd_size_type *lower_size = 0; | |
556 | static bfd_size_type *upper_size = 0; | |
557 | static bfd_size_type lower_size_rom = 0; | |
558 | static bfd_size_type lower_size_ram = 0; | |
559 | static bfd_size_type upper_size_rom = 0; | |
560 | static bfd_size_type upper_size_ram = 0; | |
561 | ||
562 | if ((s->flags & SEC_ALLOC) == 0) | |
563 | return; | |
564 | if (bfd_link_relocatable (&link_info)) | |
565 | return; | |
566 | ||
96d01d93 | 567 | base_sec_name = (const char *) data; |
fd361982 | 568 | curr_name = bfd_section_name (s); |
7ef3addb JL |
569 | |
570 | /* Only concerned with .either input sections in the upper output section. */ | |
571 | either_name = concat (".either", base_sec_name, NULL); | |
572 | if (strncmp (curr_name, either_name, strlen (either_name)) != 0 | |
573 | || strncmp (s->output_section->name, ".upper", 6) != 0) | |
574 | goto end; | |
575 | ||
576 | lower = lang_output_section_find (concat (".lower", base_sec_name, NULL)); | |
577 | upper = lang_output_section_find (concat (".upper", base_sec_name, NULL)); | |
578 | ||
579 | if (upper == NULL || upper->region == NULL) | |
580 | goto end; | |
581 | else if (lower == NULL) | |
582 | lower = lang_output_section_find (base_sec_name); | |
583 | if (lower == NULL || lower->region == NULL) | |
584 | goto end; | |
585 | ||
586 | if (strcmp (base_sec_name, ".text") == 0 | |
587 | || strcmp (base_sec_name, ".rodata") == 0) | |
588 | curr_region = ROM; | |
589 | else | |
590 | curr_region = RAM; | |
591 | ||
592 | if (curr_region == ROM) | |
593 | { | |
594 | if (lower_size_rom == 0) | |
595 | { | |
596 | lower_size_rom = lower->region->current - lower->region->origin; | |
597 | upper_size_rom = upper->region->current - upper->region->origin; | |
598 | } | |
599 | lower_size = &lower_size_rom; | |
600 | upper_size = &upper_size_rom; | |
601 | } | |
602 | else if (curr_region == RAM) | |
603 | { | |
604 | if (lower_size_ram == 0) | |
605 | { | |
606 | lower_size_ram = lower->region->current - lower->region->origin; | |
607 | upper_size_ram = upper->region->current - upper->region->origin; | |
608 | } | |
609 | lower_size = &lower_size_ram; | |
610 | upper_size = &upper_size_ram; | |
837a17b3 NC |
611 | } |
612 | ||
1a9f72a7 JL |
613 | /* If the upper region is overflowing, try moving sections to the lower |
614 | region. | |
615 | Note that there isn't any general benefit to using lower memory over upper | |
616 | memory, so we only move sections around with the goal of making the program | |
617 | fit. */ | |
618 | if (*upper_size > upper->region->length | |
619 | && *lower_size + s->size < lower->region->length) | |
7ef3addb | 620 | { |
1a9f72a7 | 621 | if (change_output_section (&(upper->children.head), s, lower, upper)) |
7ef3addb JL |
622 | { |
623 | *upper_size -= s->size; | |
624 | *lower_size += s->size; | |
625 | } | |
626 | } | |
e1fa0163 | 627 | end: |
7ef3addb | 628 | free (either_name); |
837a17b3 | 629 | } |
837a17b3 | 630 | |
7ef3addb | 631 | static void |
fd361982 AM |
632 | eval_lower_either_sections (bfd *abfd ATTRIBUTE_UNUSED, |
633 | asection *s, void *data) | |
7ef3addb | 634 | { |
96d01d93 | 635 | const char * base_sec_name; |
7ef3addb JL |
636 | const char * curr_name; |
637 | char * either_name; | |
638 | int curr_region; | |
639 | lang_output_section_statement_type * output_sec; | |
640 | lang_output_section_statement_type * lower; | |
641 | lang_output_section_statement_type * upper; | |
642 | ||
643 | static bfd_size_type *lower_size = 0; | |
644 | static bfd_size_type lower_size_rom = 0; | |
645 | static bfd_size_type lower_size_ram = 0; | |
646 | ||
647 | if ((s->flags & SEC_ALLOC) == 0) | |
648 | return; | |
649 | if (bfd_link_relocatable (&link_info)) | |
650 | return; | |
651 | ||
96d01d93 | 652 | base_sec_name = (const char *) data; |
fd361982 | 653 | curr_name = bfd_section_name (s); |
7ef3addb JL |
654 | |
655 | /* Only concerned with .either input sections in the lower or "default" | |
656 | output section i.e. not in the upper output section. */ | |
657 | either_name = concat (".either", base_sec_name, NULL); | |
658 | if (strncmp (curr_name, either_name, strlen (either_name)) != 0 | |
659 | || strncmp (s->output_section->name, ".upper", 6) == 0) | |
660 | return; | |
661 | ||
662 | if (strcmp (base_sec_name, ".text") == 0 | |
663 | || strcmp (base_sec_name, ".rodata") == 0) | |
664 | curr_region = ROM; | |
665 | else | |
666 | curr_region = RAM; | |
667 | ||
668 | output_sec = lang_output_section_find (s->output_section->name); | |
669 | ||
670 | /* If the output_section doesn't exist, this has already been reported in | |
671 | place_orphan, so don't need to warn again. */ | |
672 | if (output_sec == NULL || output_sec->region == NULL) | |
673 | goto end; | |
674 | ||
675 | /* lower and output_sec might be the same, but in some cases an .either | |
676 | section can end up in base_sec_name if it hasn't been placed by | |
677 | place_orphan. */ | |
678 | lower = lang_output_section_find (concat (".lower", base_sec_name, NULL)); | |
679 | upper = lang_output_section_find (concat (".upper", base_sec_name, NULL)); | |
680 | if (upper == NULL) | |
681 | goto end; | |
682 | ||
683 | if (curr_region == ROM) | |
684 | { | |
685 | if (lower_size_rom == 0) | |
686 | { | |
687 | /* Get the size of other items in the lower region that aren't the | |
688 | sections to be moved around. */ | |
689 | lower_size_rom | |
690 | = (output_sec->region->current - output_sec->region->origin) | |
691 | - scan_children (output_sec->children.head); | |
692 | if (output_sec != lower && lower != NULL) | |
693 | lower_size_rom -= scan_children (lower->children.head); | |
694 | } | |
695 | lower_size = &lower_size_rom; | |
696 | } | |
697 | else if (curr_region == RAM) | |
698 | { | |
699 | if (lower_size_ram == 0) | |
700 | { | |
701 | lower_size_ram | |
702 | = (output_sec->region->current - output_sec->region->origin) | |
703 | - scan_children (output_sec->children.head); | |
704 | if (output_sec != lower && lower != NULL) | |
705 | lower_size_ram -= scan_children (lower->children.head); | |
706 | } | |
707 | lower_size = &lower_size_ram; | |
708 | } | |
709 | /* Move sections that cause the lower region to overflow to the upper region. */ | |
710 | if (*lower_size + s->size > output_sec->region->length) | |
1a9f72a7 | 711 | change_output_section (&(output_sec->children.head), s, upper, output_sec); |
7ef3addb JL |
712 | else |
713 | *lower_size += s->size; | |
714 | end: | |
715 | free (either_name); | |
716 | } | |
717 | ||
718 | /* This function is similar to lang_relax_sections, but without the size | |
719 | evaluation code that is always executed after relaxation. */ | |
720 | static void | |
721 | intermediate_relax_sections (void) | |
722 | { | |
723 | int i = link_info.relax_pass; | |
724 | ||
725 | /* The backend can use it to determine the current pass. */ | |
726 | link_info.relax_pass = 0; | |
727 | ||
728 | while (i--) | |
729 | { | |
f38a2680 | 730 | bool relax_again; |
7ef3addb JL |
731 | |
732 | link_info.relax_trip = -1; | |
733 | do | |
734 | { | |
735 | link_info.relax_trip++; | |
736 | ||
737 | lang_do_assignments (lang_assigning_phase_enum); | |
738 | ||
739 | lang_reset_memory_regions (); | |
740 | ||
f38a2680 AM |
741 | relax_again = false; |
742 | lang_size_sections (&relax_again, false); | |
7ef3addb JL |
743 | } |
744 | while (relax_again); | |
745 | ||
746 | link_info.relax_pass++; | |
747 | } | |
748 | } | |
749 | ||
750 | static void | |
751 | msp430_elf_after_allocation (void) | |
752 | { | |
753 | int relax_count = 0; | |
96d01d93 | 754 | unsigned int i; |
7ef3addb JL |
755 | /* Go over each section twice, once to place either sections that don't fit |
756 | in lower into upper, and then again to move any sections in upper that | |
757 | fit in lower into lower. */ | |
758 | for (i = 0; i < 8; i++) | |
759 | { | |
760 | int placement_stage = (i < 4) ? LOWER_TO_UPPER : UPPER_TO_LOWER; | |
96d01d93 | 761 | const char * base_sec_name; |
7ef3addb JL |
762 | lang_output_section_statement_type * upper; |
763 | ||
764 | switch (i % 4) | |
765 | { | |
96d01d93 | 766 | default: |
7ef3addb | 767 | case 0: |
96d01d93 | 768 | base_sec_name = ".text"; |
7ef3addb JL |
769 | break; |
770 | case 1: | |
96d01d93 | 771 | base_sec_name = ".data"; |
7ef3addb JL |
772 | break; |
773 | case 2: | |
96d01d93 | 774 | base_sec_name = ".bss"; |
7ef3addb JL |
775 | break; |
776 | case 3: | |
96d01d93 | 777 | base_sec_name = ".rodata"; |
7ef3addb JL |
778 | break; |
779 | } | |
780 | upper = lang_output_section_find (concat (".upper", base_sec_name, NULL)); | |
781 | if (upper != NULL) | |
782 | { | |
783 | /* Can't just use one iteration over the all the sections to make | |
784 | both lower->upper and upper->lower transformations because the | |
785 | iterator encounters upper sections before all lower sections have | |
786 | been examined. */ | |
787 | bfd *abfd; | |
788 | ||
789 | if (placement_stage == LOWER_TO_UPPER) | |
790 | { | |
791 | /* Perform relaxation and get the final size of sections | |
792 | before trying to fit .either sections in the correct | |
793 | ouput sections. */ | |
794 | if (relax_count == 0) | |
795 | { | |
796 | intermediate_relax_sections (); | |
797 | relax_count++; | |
798 | } | |
799 | for (abfd = link_info.input_bfds; abfd != NULL; | |
800 | abfd = abfd->link.next) | |
801 | { | |
802 | bfd_map_over_sections (abfd, eval_lower_either_sections, | |
96d01d93 | 803 | (void *) base_sec_name); |
7ef3addb JL |
804 | } |
805 | } | |
806 | else if (placement_stage == UPPER_TO_LOWER) | |
807 | { | |
808 | /* Relax again before moving upper->lower. */ | |
809 | if (relax_count == 1) | |
810 | { | |
811 | intermediate_relax_sections (); | |
812 | relax_count++; | |
813 | } | |
814 | for (abfd = link_info.input_bfds; abfd != NULL; | |
815 | abfd = abfd->link.next) | |
816 | { | |
817 | bfd_map_over_sections (abfd, eval_upper_either_sections, | |
96d01d93 | 818 | (void *) base_sec_name); |
7ef3addb JL |
819 | } |
820 | } | |
821 | ||
822 | } | |
7ef3addb JL |
823 | } |
824 | gld${EMULATION_NAME}_after_allocation (); | |
825 | } | |
837a17b3 | 826 | |
64b63c29 JL |
827 | /* Return TRUE if a non-debug input section in L has positive size and matches |
828 | the given name. */ | |
829 | static int | |
830 | input_section_exists (lang_statement_union_type * l, const char * name) | |
831 | { | |
832 | while (l != NULL) | |
833 | { | |
834 | switch (l->header.type) | |
835 | { | |
836 | case lang_input_section_enum: | |
837 | if ((l->input_section.section->flags & SEC_ALLOC) | |
838 | && l->input_section.section->size > 0 | |
839 | && !strcmp (l->input_section.section->name, name)) | |
f38a2680 | 840 | return true; |
64b63c29 JL |
841 | break; |
842 | ||
843 | case lang_wild_statement_enum: | |
844 | if (input_section_exists (l->wild_statement.children.head, name)) | |
f38a2680 | 845 | return true; |
64b63c29 JL |
846 | break; |
847 | ||
848 | default: | |
849 | break; | |
850 | } | |
851 | l = l->header.next; | |
852 | } | |
f38a2680 | 853 | return false; |
64b63c29 JL |
854 | } |
855 | ||
856 | /* Some MSP430 linker scripts do not include ALIGN directives to ensure | |
857 | __preinit_array_start, __init_array_start or __fini_array_start are word | |
858 | aligned. | |
859 | If __*_array_start symbols are not word aligned, the code in crt0 to run | |
860 | through the array and call the functions will crash. | |
861 | To avoid warning unnecessarily when the .*_array sections are not being | |
862 | used for running constructors/destructors, only emit the warning if | |
863 | the associated section exists and has size. */ | |
864 | static void | |
865 | check_array_section_alignment (void) | |
866 | { | |
867 | int i; | |
868 | lang_output_section_statement_type * rodata_sec; | |
869 | lang_output_section_statement_type * rodata2_sec; | |
870 | const char * array_names[3][2] = { { ".init_array", "__init_array_start" }, | |
871 | { ".preinit_array", "__preinit_array_start" }, | |
872 | { ".fini_array", "__fini_array_start" } }; | |
873 | ||
874 | /* .{preinit,init,fini}_array could be in either .rodata or .rodata2. */ | |
875 | rodata_sec = lang_output_section_find (".rodata"); | |
876 | rodata2_sec = lang_output_section_find (".rodata2"); | |
877 | if (rodata_sec == NULL && rodata2_sec == NULL) | |
878 | return; | |
879 | ||
880 | /* There are 3 .*_array sections which must be checked for alignment. */ | |
881 | for (i = 0; i < 3; i++) | |
882 | { | |
883 | struct bfd_link_hash_entry * sym; | |
884 | if (((rodata_sec && input_section_exists (rodata_sec->children.head, | |
885 | array_names[i][0])) | |
886 | || (rodata2_sec && input_section_exists (rodata2_sec->children.head, | |
887 | array_names[i][0]))) | |
888 | && (sym = bfd_link_hash_lookup (link_info.hash, array_names[i][1], | |
f38a2680 | 889 | false, false, true)) |
64b63c29 JL |
890 | && sym->type == bfd_link_hash_defined |
891 | && sym->u.def.value % 2) | |
892 | { | |
893 | einfo ("%P: warning: \"%s\" symbol (%pU) is not word aligned\n", | |
894 | array_names[i][1], NULL); | |
895 | } | |
896 | } | |
897 | } | |
898 | ||
899 | static void | |
900 | gld${EMULATION_NAME}_finish (void) | |
901 | { | |
902 | finish_default (); | |
903 | check_array_section_alignment (); | |
904 | } | |
837a17b3 | 905 | EOF |
a9261391 L |
906 | |
907 | LDEMUL_AFTER_OPEN=msp430_elf_after_open | |
908 | LDEMUL_AFTER_ALLOCATION=msp430_elf_after_allocation | |
909 | LDEMUL_PLACE_ORPHAN=${LDEMUL_PLACE_ORPHAN-gld${EMULATION_NAME}_place_orphan} | |
910 | LDEMUL_FINISH=gld${EMULATION_NAME}_finish | |
911 | LDEMUL_ADD_OPTIONS=gld${EMULATION_NAME}_add_options | |
912 | LDEMUL_HANDLE_OPTION=gld${EMULATION_NAME}_handle_option | |
913 | LDEMUL_LIST_OPTIONS=gld${EMULATION_NAME}_list_options | |
914 | ||
915 | source_em ${srcdir}/emultempl/emulation.em | |
837a17b3 NC |
916 | # \f |
917 | # Local Variables: | |
918 | # mode: c | |
919 | # End: |