/* This file is is generated by a shell script. DO NOT EDIT! */
/* Emulate the original gld for the given ${EMULATION_NAME}
- Copyright (C) 2014-2017 Free Software Foundation, Inc.
+ Copyright (C) 2014-2021 Free Software Foundation, Inc.
Written by Steve Chamberlain steve@cygnus.com
Extended for the MSP430 by Nick Clifton nickc@redhat.com
#include "sysdep.h"
#include "bfd.h"
#include "bfdlink.h"
+#include "ctf-api.h"
#include "ld.h"
#include "getopt.h"
return amount;
}
+#define WARN_UPPER 0
+#define WARN_LOWER 1
+#define WARN_TEXT 0
+#define WARN_DATA 1
+#define WARN_BSS 2
+#define WARN_RODATA 3
+
+/* Warn only once per output section.
+ * NAME starts with ".upper." or ".lower.". */
+static void
+warn_no_output_section (const char *name)
+{
+ static bfd_boolean warned[2][4] = {{FALSE, FALSE, FALSE, FALSE},
+ {FALSE, FALSE, FALSE, FALSE}};
+ int i = WARN_LOWER;
+
+ if (strncmp (name, ".upper.", 7) == 0)
+ i = WARN_UPPER;
+
+ if (!warned[i][WARN_TEXT] && strcmp (name + 6, ".text") == 0)
+ warned[i][WARN_TEXT] = TRUE;
+ else if (!warned[i][WARN_DATA] && strcmp (name + 6, ".data") == 0)
+ warned[i][WARN_DATA] = TRUE;
+ else if (!warned[i][WARN_BSS] && strcmp (name + 6, ".bss") == 0)
+ warned[i][WARN_BSS] = TRUE;
+ else if (!warned[i][WARN_RODATA] && strcmp (name + 6, ".rodata") == 0)
+ warned[i][WARN_RODATA] = TRUE;
+ else
+ return;
+ einfo ("%P: warning: no input section rule matches %s in linker script\n",
+ name);
+}
+
+
/* Place an orphan section. We use this to put .either sections
into either their lower or their upper equivalents. */
char * lower_name;
char * upper_name;
char * name;
- char * buf = NULL;
lang_output_section_statement_type * lower;
lang_output_section_statement_type * upper;
if (constraint != 0)
return NULL;
+ if (strncmp (secname, ".upper.", 7) == 0
+ || strncmp (secname, ".lower.", 7) == 0)
+ {
+ warn_no_output_section (secname);
+ return NULL;
+ }
+
/* We only need special handling for .either sections. */
if (strncmp (secname, ".either.", 8) != 0)
return NULL;
only use the part of the name before the second dot. */
if (strchr (secname + 1, '.') != NULL)
{
- buf = name = xstrdup (secname);
+ name = xstrdup (secname);
* strchr (name + 1, '.') = 0;
}
end:
free (upper_name);
free (lower_name);
- if (buf)
- free (buf);
return lower;
}
EOF
fragment <<EOF
static bfd_boolean
-change_output_section (lang_statement_union_type ** head,
+change_output_section (lang_statement_union_type **head,
asection *s,
- lang_output_section_statement_type * new_output_section)
+ lang_output_section_statement_type *new_os,
+ lang_output_section_statement_type *old_os)
{
asection *is;
lang_statement_union_type * prev = NULL;
is = curr->input_section.section;
if (is == s)
{
+ lang_statement_list_type *old_list
+ = (lang_statement_list_type *) &old_os->children;
s->output_section = NULL;
- lang_add_section (& (new_output_section->children), s, NULL,
- new_output_section);
+ lang_add_section (&new_os->children, s, NULL, new_os);
+
/* Remove the section from the old output section. */
if (prev == NULL)
*head = curr->header.next;
else
prev->header.next = curr->header.next;
+ /* If the input section we just moved is the tail of the old
+ output section, then we also need to adjust that tail. */
+ if (old_list->tail == (lang_statement_union_type **) curr)
+ old_list->tail = (lang_statement_union_type **) prev;
+
return TRUE;
}
break;
case lang_wild_statement_enum:
if (change_output_section (&(curr->wild_statement.children.head),
- s, new_output_section))
+ s, new_os, old_os))
return TRUE;
break;
default:
}
static void
-move_prefixed_section (asection *s, char *new_name,
- lang_output_section_statement_type * new_output_sec)
-{
- s->name = new_name;
- if (s->output_section == NULL)
- lang_add_section (& (new_output_sec->children), s, NULL, new_output_sec);
- else
- {
- lang_output_section_statement_type * curr_output_sec
- = lang_output_section_find (s->output_section->name);
- change_output_section (&(curr_output_sec->children.head), s,
- new_output_sec);
- }
-}
-
-static void
-add_region_prefix (bfd *abfd, asection *s,
- ATTRIBUTE_UNUSED void *unused)
+add_region_prefix (bfd *abfd ATTRIBUTE_UNUSED, asection *s,
+ void *unused ATTRIBUTE_UNUSED)
{
- const char *curr_name = bfd_get_section_name (abfd, s);
- char * base_name;
- char * new_input_sec_name = NULL;
- char * new_output_sec_name = NULL;
+ const char *curr_name = bfd_section_name (s);
int region = REGION_NONE;
if (strncmp (curr_name, ".text", 5) == 0)
- {
- region = code_region;
- base_name = concat (".text", NULL);
- }
+ region = code_region;
else if (strncmp (curr_name, ".data", 5) == 0)
- {
- region = data_region;
- base_name = concat (".data", NULL);
- }
+ region = data_region;
else if (strncmp (curr_name, ".bss", 4) == 0)
- {
- region = data_region;
- base_name = concat (".bss", NULL);
- }
+ region = data_region;
else if (strncmp (curr_name, ".rodata", 7) == 0)
- {
- region = data_region;
- base_name = concat (".rodata", NULL);
- }
+ region = data_region;
else
return;
case REGION_NONE:
break;
case REGION_UPPER:
- new_input_sec_name = concat (".upper", curr_name, NULL);
- new_output_sec_name = concat (".upper", base_name, NULL);
- lang_output_section_statement_type * upper
- = lang_output_section_find (new_output_sec_name);
- if (upper != NULL)
- {
- move_prefixed_section (s, new_input_sec_name, upper);
- }
- else
- einfo (_("%P: error: no section named %s in linker script\n"),
- new_output_sec_name);
+ bfd_rename_section (s, concat (".upper", curr_name, NULL));
break;
case REGION_LOWER:
- new_input_sec_name = concat (".lower", curr_name, NULL);
- new_output_sec_name = concat (".lower", base_name, NULL);
- lang_output_section_statement_type * lower
- = lang_output_section_find (new_output_sec_name);
- if (lower != NULL)
- {
- move_prefixed_section (s, new_input_sec_name, lower);
- }
- else
- einfo (_("%P: error: no section named %s in linker script\n"),
- new_output_sec_name);
+ bfd_rename_section (s, concat (".lower", curr_name, NULL));
break;
case REGION_EITHER:
s->name = concat (".either", curr_name, NULL);
FAIL ();
break;
}
- free (base_name);
- if (new_input_sec_name)
- {
- free (new_input_sec_name);
- free (new_output_sec_name);
- }
}
static void
static void
gld${EMULATION_NAME}_list_options (FILE * file)
{
- fprintf (file, _("\
- --code-region={either,lower,upper,none}\n\
- \tTransform .text* sections to {either,lower,upper,none}.text* sections.\n\
- --data-region={either,lower,upper,none}\n\
- \tTransform .data*, .rodata* and .bss* sections to\n\
- {either,lower,upper,none}.{bss,data,rodata}* sections\n\
- --disable-sec-transformation\n\
- \tDisable transformation of .{text,data,bss,rodata}* sections to\n\
- \tadd the {either,lower,upper,none} prefixes\n"));
+ fprintf (file, _(" --code-region={either,lower,upper,none}\n\
+ Transform .text* sections to {either,lower,upper,none}.text* sections\n"));
+ fprintf (file, _(" --data-region={either,lower,upper,none}\n\
+ Transform .data*, .rodata* and .bss* sections to\n\
+ {either,lower,upper,none}.{bss,data,rodata}* sections\n"));
+ fprintf (file, _(" --disable-sec-transformation\n\
+ Disable transformation of .{text,data,bss,rodata}* sections to\n\
+ add the {either,lower,upper,none} prefixes\n"));
}
static bfd_boolean
code_region = REGION_NONE;
else if (strlen (optarg) == 0)
{
- einfo (_("%P: --code-region requires an argument: \
- {upper,lower,either,none}\n"));
+ einfo (_("%P: --code-region requires an argument: "
+ "{upper,lower,either,none}\n"));
return FALSE;
}
else
{
- einfo (_("%P: error: unrecognized argument to --code-region= option: \
- \"%s\"\n"), optarg);
+ einfo (_("%P: error: unrecognized argument to --code-region= option: "
+ "\"%s\"\n"), optarg);
return FALSE;
}
break;
data_region = REGION_NONE;
else if (strlen (optarg) == 0)
{
- einfo (_("%P: --data-region requires an argument: \
- {upper,lower,either,none}\n"));
+ einfo (_("%P: --data-region requires an argument: "
+ "{upper,lower,either,none}\n"));
return FALSE;
}
else
{
- einfo (_("%P: error: unrecognized argument to --data-region= option: \
- \"%s\"\n"), optarg);
+ einfo (_("%P: error: unrecognized argument to --data-region= option: "
+ "\"%s\"\n"), optarg);
return FALSE;
}
break;
}
static void
-eval_upper_either_sections (bfd *abfd, asection *s, void *data)
+eval_upper_either_sections (bfd *abfd ATTRIBUTE_UNUSED,
+ asection *s, void *data)
{
const char * base_sec_name;
const char * curr_name;
return;
base_sec_name = (const char *) data;
- curr_name = bfd_get_section_name (abfd, s);
+ curr_name = bfd_section_name (s);
/* Only concerned with .either input sections in the upper output section. */
either_name = concat (".either", base_sec_name, NULL);
upper_size = &upper_size_ram;
}
- /* Move sections in the upper region that would fit in the lower
- region to the lower region. */
- if (*lower_size + s->size < lower->region->length)
+ /* If the upper region is overflowing, try moving sections to the lower
+ region.
+ Note that there isn't any general benefit to using lower memory over upper
+ memory, so we only move sections around with the goal of making the program
+ fit. */
+ if (*upper_size > upper->region->length
+ && *lower_size + s->size < lower->region->length)
{
- if (change_output_section (&(upper->children.head), s, lower))
+ if (change_output_section (&(upper->children.head), s, lower, upper))
{
*upper_size -= s->size;
*lower_size += s->size;
}
static void
-eval_lower_either_sections (bfd *abfd, asection *s, void *data)
+eval_lower_either_sections (bfd *abfd ATTRIBUTE_UNUSED,
+ asection *s, void *data)
{
const char * base_sec_name;
const char * curr_name;
return;
base_sec_name = (const char *) data;
- curr_name = bfd_get_section_name (abfd, s);
+ curr_name = bfd_section_name (s);
/* Only concerned with .either input sections in the lower or "default"
output section i.e. not in the upper output section. */
}
/* Move sections that cause the lower region to overflow to the upper region. */
if (*lower_size + s->size > output_sec->region->length)
- change_output_section (&(output_sec->children.head), s, upper);
+ change_output_section (&(output_sec->children.head), s, upper, output_sec);
else
*lower_size += s->size;
end:
gld${EMULATION_NAME}_after_allocation ();
}
+/* Return TRUE if a non-debug input section in L has positive size and matches
+ the given name. */
+static int
+input_section_exists (lang_statement_union_type * l, const char * name)
+{
+ while (l != NULL)
+ {
+ switch (l->header.type)
+ {
+ case lang_input_section_enum:
+ if ((l->input_section.section->flags & SEC_ALLOC)
+ && l->input_section.section->size > 0
+ && !strcmp (l->input_section.section->name, name))
+ return TRUE;
+ break;
+
+ case lang_wild_statement_enum:
+ if (input_section_exists (l->wild_statement.children.head, name))
+ return TRUE;
+ break;
+
+ default:
+ break;
+ }
+ l = l->header.next;
+ }
+ return FALSE;
+}
+
+/* Some MSP430 linker scripts do not include ALIGN directives to ensure
+ __preinit_array_start, __init_array_start or __fini_array_start are word
+ aligned.
+ If __*_array_start symbols are not word aligned, the code in crt0 to run
+ through the array and call the functions will crash.
+ To avoid warning unnecessarily when the .*_array sections are not being
+ used for running constructors/destructors, only emit the warning if
+ the associated section exists and has size. */
+static void
+check_array_section_alignment (void)
+{
+ int i;
+ lang_output_section_statement_type * rodata_sec;
+ lang_output_section_statement_type * rodata2_sec;
+ const char * array_names[3][2] = { { ".init_array", "__init_array_start" },
+ { ".preinit_array", "__preinit_array_start" },
+ { ".fini_array", "__fini_array_start" } };
+
+ /* .{preinit,init,fini}_array could be in either .rodata or .rodata2. */
+ rodata_sec = lang_output_section_find (".rodata");
+ rodata2_sec = lang_output_section_find (".rodata2");
+ if (rodata_sec == NULL && rodata2_sec == NULL)
+ return;
+
+ /* There are 3 .*_array sections which must be checked for alignment. */
+ for (i = 0; i < 3; i++)
+ {
+ struct bfd_link_hash_entry * sym;
+ if (((rodata_sec && input_section_exists (rodata_sec->children.head,
+ array_names[i][0]))
+ || (rodata2_sec && input_section_exists (rodata2_sec->children.head,
+ array_names[i][0])))
+ && (sym = bfd_link_hash_lookup (link_info.hash, array_names[i][1],
+ FALSE, FALSE, TRUE))
+ && sym->type == bfd_link_hash_defined
+ && sym->u.def.value % 2)
+ {
+ einfo ("%P: warning: \"%s\" symbol (%pU) is not word aligned\n",
+ array_names[i][1], NULL);
+ }
+ }
+}
+
+static void
+gld${EMULATION_NAME}_finish (void)
+{
+ finish_default ();
+ check_array_section_alignment ();
+}
+
struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
{
${LDEMUL_BEFORE_PARSE-gld${EMULATION_NAME}_before_parse},
${LDEMUL_AFTER_PARSE-after_parse_default},
msp430_elf_after_open,
after_check_relocs_default,
+ before_place_orphans_default,
msp430_elf_after_allocation,
${LDEMUL_SET_OUTPUT_ARCH-set_output_arch_default},
${LDEMUL_CHOOSE_TARGET-ldemul_default_target},
${LDEMUL_GET_SCRIPT-gld${EMULATION_NAME}_get_script},
"${EMULATION_NAME}",
"${OUTPUT_FORMAT}",
- ${LDEMUL_FINISH-finish_default},
+ gld${EMULATION_NAME}_finish,
${LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS-NULL},
${LDEMUL_OPEN_DYNAMIC_ARCHIVE-NULL},
${LDEMUL_PLACE_ORPHAN-gld${EMULATION_NAME}_place_orphan},
${LDEMUL_RECOGNIZED_FILE-NULL},
${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL},
${LDEMUL_NEW_VERS_PATTERN-NULL},
- ${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL}
+ ${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL},
+ ${LDEMUL_EMIT_CTF_EARLY-NULL},
+ ${LDEMUL_ACQUIRE_STRINGS_FOR_CTF-NULL},
+ ${LDEMUL_NEW_DYNSYM_FOR_CTF-NULL},
+ ${LDEMUL_PRINT_SYMBOL-NULL}
};
EOF
# \f