X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=ld%2Femultempl%2Fmsp430.em;h=e3ea3c69a909b48b8b0bcbd76196da3e37b0b284;hb=f9a6a8f09dc2310d5f4a482a2e7ffc1be3984cd7;hp=2cd15d6a526591a2d7d63af447ffde645b30ca20;hpb=219d1afa89d0d53ca93a684cac341f16470f3ca0;p=binutils-gdb.git diff --git a/ld/emultempl/msp430.em b/ld/emultempl/msp430.em index 2cd15d6a526..e3ea3c69a90 100644 --- a/ld/emultempl/msp430.em +++ b/ld/emultempl/msp430.em @@ -4,7 +4,7 @@ fragment <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: @@ -341,51 +388,20 @@ change_output_section (lang_statement_union_type ** head, } 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; @@ -394,30 +410,10 @@ add_region_prefix (bfd *abfd, asection *s, 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); @@ -427,12 +423,6 @@ add_region_prefix (bfd *abfd, asection *s, FAIL (); break; } - free (base_name); - if (new_input_sec_name) - { - free (new_input_sec_name); - free (new_output_sec_name); - } } static void @@ -482,15 +472,14 @@ gld${EMULATION_NAME}_add_options 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 @@ -509,14 +498,14 @@ gld${EMULATION_NAME}_handle_option (int optc) 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; @@ -532,14 +521,14 @@ gld${EMULATION_NAME}_handle_option (int optc) 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; @@ -555,7 +544,8 @@ gld${EMULATION_NAME}_handle_option (int optc) } 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; @@ -577,7 +567,7 @@ eval_upper_either_sections (bfd *abfd, asection *s, void *data) 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); @@ -622,11 +612,15 @@ eval_upper_either_sections (bfd *abfd, asection *s, void *data) 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; @@ -637,7 +631,8 @@ eval_upper_either_sections (bfd *abfd, asection *s, void *data) } 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; @@ -657,7 +652,7 @@ eval_lower_either_sections (bfd *abfd, asection *s, void *data) 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. */ @@ -715,7 +710,7 @@ eval_lower_either_sections (bfd *abfd, asection *s, void *data) } /* 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: @@ -831,6 +826,85 @@ msp430_elf_after_allocation (void) 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}, @@ -839,6 +913,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = ${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}, @@ -846,7 +921,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = ${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}, @@ -859,7 +934,11 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = ${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 #