aboutsummaryrefslogtreecommitdiff
path: root/ld
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2015-05-05 13:38:00 +0100
committerNick Clifton <nickc@redhat.com>2015-05-05 13:38:00 +0100
commit837a17b36c9e297f4bf33727e25dfa9f38360c17 (patch)
tree5cf6ecb482076cf1e20e437b6ea94c00c87cb103 /ld
parentb76f99d702c3501ac320396ea06bc7f9237173c3 (diff)
Add support to the MSP430 linker for the automatic placement of code and data into either low or high memory regions.
gas * config/tc-msp430.c (MAX_OP_LEN): Increase to 4096. (msp430_make_init_symbols): New function. (msp430_section): Call it. (msp430_frob_section): Likewise. ld * emulparams/msp430elf.sh (TEMPLATE_NAME): Change to msp430. * scripttempl/msp430.sc (.text): Add .lower.text and .either.text. (.data): Add .lower.data and .either.data. (.bss): Add .lower.bss and .either.bss. (.rodata): Add .lower.rodata and .either.rodata. * emultempl/msp430.em: New file. Implements a new orphan placement algorithm that divides sections between lower and upper memory regions. * Makefile.am (emsp430elf.c): Depend upon msp430.em. *emsp430X.c): Likewise. * Makefine.in: Regenerate.
Diffstat (limited to 'ld')
-rw-r--r--ld/ChangeLog14
-rw-r--r--ld/Makefile.am2
-rw-r--r--ld/Makefile.in2
-rw-r--r--ld/emulparams/msp430elf.sh2
-rw-r--r--ld/emultempl/msp430.em298
-rw-r--r--ld/scripttempl/elf32msp430.sc20
6 files changed, 336 insertions, 2 deletions
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 3448bbadcf..243bf5f2b5 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,17 @@
+2015-05-05 Nick Clifton <nickc@redhat.com>
+
+ * emulparams/msp430elf.sh (TEMPLATE_NAME): Change to msp430.
+ * scripttempl/msp430.sc (.text): Add .lower.text and .either.text.
+ (.data): Add .lower.data and .either.data.
+ (.bss): Add .lower.bss and .either.bss.
+ (.rodata): Add .lower.rodata and .either.rodata.
+ * emultempl/msp430.em: New file. Implements a new orphan
+ placement algorithm that divides sections between lower and upper
+ memory regions.
+ * Makefile.am (emsp430elf.c): Depend upon msp430.em.
+ *emsp430X.c): Likewise.
+ * Makefine.in: Regenerate.
+
2015-04-28 Andreas Schwab <schwab@linux-m68k.org>
PR ld/18344
diff --git a/ld/Makefile.am b/ld/Makefile.am
index 15f89946ac..ee22e75910 100644
--- a/ld/Makefile.am
+++ b/ld/Makefile.am
@@ -1529,9 +1529,11 @@ emn10300.c: $(srcdir)/emulparams/mn10300.sh \
$(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
emsp430elf.c: $(srcdir)/emulparams/msp430elf.sh \
+ $(ELF_DEPS) $(srcdir)/emultempl/msp430.em \
$(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc ${GEN_DEPENDS}
emsp430X.c: $(srcdir)/emulparams/msp430elf.sh $(srcdir)/emulparams/msp430X.sh \
+ $(ELF_DEPS) $(srcdir)/emultempl/msp430.em \
$(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc ${GEN_DEPENDS}
ends32elf.c: $(srcdir)/emulparams/nds32elf.sh \
diff --git a/ld/Makefile.in b/ld/Makefile.in
index 169fae114a..2d8b09d613 100644
--- a/ld/Makefile.in
+++ b/ld/Makefile.in
@@ -3027,9 +3027,11 @@ emn10300.c: $(srcdir)/emulparams/mn10300.sh \
$(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
emsp430elf.c: $(srcdir)/emulparams/msp430elf.sh \
+ $(ELF_DEPS) $(srcdir)/emultempl/msp430.em \
$(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc ${GEN_DEPENDS}
emsp430X.c: $(srcdir)/emulparams/msp430elf.sh $(srcdir)/emulparams/msp430X.sh \
+ $(ELF_DEPS) $(srcdir)/emultempl/msp430.em \
$(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc ${GEN_DEPENDS}
ends32elf.c: $(srcdir)/emulparams/nds32elf.sh \
diff --git a/ld/emulparams/msp430elf.sh b/ld/emulparams/msp430elf.sh
index b45969853c..a76e9ee30a 100644
--- a/ld/emulparams/msp430elf.sh
+++ b/ld/emulparams/msp430elf.sh
@@ -3,7 +3,7 @@
# This called by genscripts_extra.sh
SCRIPT_NAME=elf32msp430
-TEMPLATE_NAME=generic
+TEMPLATE_NAME=msp430
EXTRA_EM_FILE=genelf
OUTPUT_FORMAT="elf32-msp430"
MACHINE=
diff --git a/ld/emultempl/msp430.em b/ld/emultempl/msp430.em
new file mode 100644
index 0000000000..0eff3f063f
--- /dev/null
+++ b/ld/emultempl/msp430.em
@@ -0,0 +1,298 @@
+# This shell script emits a C file. -*- C -*-
+# It does some substitutions.
+fragment <<EOF
+/* This file is is generated by a shell script. DO NOT EDIT! */
+
+/* Emulate the original gld for the given ${EMULATION_NAME}
+ Copyright (C) 2014-2015 Free Software Foundation, Inc.
+ Written by Steve Chamberlain steve@cygnus.com
+ Extended for the MSP430 by Nick Clifton nickc@redhat.com
+
+ This file is part of the GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#define TARGET_IS_${EMULATION_NAME}
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "bfdlink.h"
+
+#include "ld.h"
+#include "ldmain.h"
+#include "ldmisc.h"
+#include "ldexp.h"
+#include "ldlang.h"
+#include "ldfile.h"
+#include "ldemul.h"
+#include "libiberty.h"
+
+EOF
+
+# Import any needed special functions and/or overrides.
+#
+if test -n "$EXTRA_EM_FILE" ; then
+ source_em ${srcdir}/emultempl/${EXTRA_EM_FILE}.em
+fi
+
+if test x"$LDEMUL_BEFORE_PARSE" != xgld"$EMULATION_NAME"_before_parse; then
+fragment <<EOF
+
+static void
+gld${EMULATION_NAME}_before_parse (void)
+{
+#ifndef TARGET_ /* I.e., if not generic. */
+ ldfile_set_output_arch ("`echo ${ARCH}`", bfd_arch_unknown);
+#endif /* not TARGET_ */
+
+ /* The MSP430 port *needs* linker relaxtion in order to cope with large
+ functions where conditional branches do not fit into a +/- 1024 byte range. */
+ if (! link_info.relocatable)
+ TARGET_ENABLE_RELAXATION;
+}
+
+EOF
+fi
+
+if test x"$LDEMUL_GET_SCRIPT" != xgld"$EMULATION_NAME"_get_script; then
+fragment <<EOF
+
+static char *
+gld${EMULATION_NAME}_get_script (int *isfile)
+EOF
+
+if test x"$COMPILE_IN" = xyes
+then
+# Scripts compiled in.
+
+# sed commands to quote an ld script as a C string.
+sc="-f stringify.sed"
+
+fragment <<EOF
+{
+ *isfile = 0;
+
+ if (link_info.relocatable && config.build_constructors)
+ return
+EOF
+sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c
+echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c
+echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c
+echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c
+echo ' ; else return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c
+echo '; }' >> e${EMULATION_NAME}.c
+
+else
+# Scripts read from the filesystem.
+
+fragment <<EOF
+{
+ *isfile = 1;
+
+ if (link_info.relocatable && config.build_constructors)
+ return "ldscripts/${EMULATION_NAME}.xu";
+ else if (link_info.relocatable)
+ return "ldscripts/${EMULATION_NAME}.xr";
+ else if (!config.text_read_only)
+ return "ldscripts/${EMULATION_NAME}.xbn";
+ else if (!config.magic_demand_paged)
+ return "ldscripts/${EMULATION_NAME}.xn";
+ else
+ return "ldscripts/${EMULATION_NAME}.x";
+}
+EOF
+fi
+fi
+
+if test x"$LDEMUL_PLACE_ORPHAN" != xgld"$EMULATION_NAME"_place_orphan; then
+fragment <<EOF
+
+/* Helper function for place_orphan that computes the size
+ of sections already mapped to the given statement. */
+
+static bfd_size_type
+scan_children (lang_statement_union_type * l)
+{
+ bfd_size_type amount = 0;
+
+ while (l != NULL)
+ {
+ switch (l->header.type)
+ {
+ case lang_input_section_enum:
+ if (l->input_section.section->flags & SEC_ALLOC)
+ amount += l->input_section.section->size;
+ break;
+
+ case lang_constructors_statement_enum:
+ case lang_assignment_statement_enum:
+ break;
+
+ case lang_wild_statement_enum:
+ amount += scan_children (l->wild_statement.children.head);
+ break;
+
+ default:
+ fprintf (stderr, "msp430 orphan placer: unhandled lang type %d\n", l->header.type);
+ break;
+ }
+
+ l = l->header.next;
+ }
+
+ return amount;
+}
+
+/* Place an orphan section. We use this to put .either sections
+ into either their lower or their upper equivalents. */
+
+static lang_output_section_statement_type *
+gld${EMULATION_NAME}_place_orphan (asection * s,
+ const char * secname,
+ int constraint)
+{
+ char * lower_name;
+ char * upper_name;
+ char * name;
+ lang_output_section_statement_type * lower;
+ lang_output_section_statement_type * upper;
+ lang_output_section_statement_type * os;
+
+ if ((s->flags & SEC_ALLOC) == 0)
+ return NULL;
+
+ if (link_info.relocatable)
+ return NULL;
+
+ /* If constraints are involved let the linker handle the placement normally. */
+ if (constraint != 0)
+ return NULL;
+
+ /* We only need special handling for .either sections. */
+ if (strncmp (secname, ".either.", 8) != 0)
+ return NULL;
+
+ /* Skip the .either prefix. */
+ secname += 7;
+
+ /* Compute the names of the corresponding upper and lower
+ sections. If the input section name contains another period,
+ only use the part of the name before the second dot. */
+ if (strchr (secname + 1, '.') != NULL)
+ {
+ name = ACONCAT ((secname, NULL));
+
+ * strchr (name + 1, '.') = 0;
+ }
+ else
+ name = (char *) secname;
+
+ lower_name = ACONCAT ((".lower", name, NULL));
+ upper_name = ACONCAT ((".upper", name, NULL));
+
+ /* Find the corresponding lower and upper sections. */
+ lower = lang_output_section_find (lower_name);
+ upper = lang_output_section_find (upper_name);
+ /* If the upper section does not exist, try again without the suffix. */
+ if (upper == NULL)
+ upper = lang_output_section_find (name);
+
+ if (lower == NULL)
+ {
+ os = upper;
+ if (upper == NULL)
+ {
+ einfo ("%P: error: no section named %s or %s in linker script\n", lower_name, upper_name);
+ return NULL;
+ }
+ }
+ else if (upper == NULL)
+ os = lower;
+ else if (lower->region == NULL)
+ os = lower;
+ /* If the section is too big for the region containing
+ the lower section then do not even try to use it. */
+ else if (lower->region->length < s->size)
+ os = upper;
+ else
+ {
+ bfd_size_type amount = 0;
+ struct lang_output_section_statement_struct * p;
+
+ amount += scan_children (lower->children.head);
+
+ /* Also check forwards for other statements assigned to the same region. */
+ for (p = lower->next; p != NULL; p = p->next)
+ if (p->region == lower->region)
+ amount += scan_children (p->children.head);
+
+ /* Scan backwards as well. */
+ for (p = lower->prev; p != NULL; p = p->prev)
+ if (p->region == lower->region)
+ amount += scan_children (p->children.head);
+
+ if (amount + s->size >= lower->region->length)
+ os = upper;
+ else
+ os = lower;
+ }
+
+ lang_add_section (& os->children, s, NULL, os);
+ return os;
+}
+EOF
+fi
+
+fragment <<EOF
+
+struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
+{
+ ${LDEMUL_BEFORE_PARSE-gld${EMULATION_NAME}_before_parse},
+ ${LDEMUL_SYSLIB-syslib_default},
+ ${LDEMUL_HLL-hll_default},
+ ${LDEMUL_AFTER_PARSE-after_parse_default},
+ ${LDEMUL_AFTER_OPEN-after_open_default},
+ ${LDEMUL_AFTER_ALLOCATION-after_allocation_default},
+ ${LDEMUL_SET_OUTPUT_ARCH-set_output_arch_default},
+ ${LDEMUL_CHOOSE_TARGET-ldemul_default_target},
+ ${LDEMUL_BEFORE_ALLOCATION-before_allocation_default},
+ ${LDEMUL_GET_SCRIPT-gld${EMULATION_NAME}_get_script},
+ "${EMULATION_NAME}",
+ "${OUTPUT_FORMAT}",
+ ${LDEMUL_FINISH-finish_default},
+ ${LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS-NULL},
+ ${LDEMUL_OPEN_DYNAMIC_ARCHIVE-NULL},
+ ${LDEMUL_PLACE_ORPHAN-gld${EMULATION_NAME}_place_orphan},
+ ${LDEMUL_SET_SYMBOLS-NULL},
+ ${LDEMUL_PARSE_ARGS-NULL},
+ ${LDEMUL_ADD_OPTIONS-NULL},
+ ${LDEMUL_HANDLE_OPTION-NULL},
+ ${LDEMUL_UNRECOGNIZED_FILE-NULL},
+ ${LDEMUL_LIST_OPTIONS-NULL},
+ ${LDEMUL_RECOGNIZED_FILE-NULL},
+ ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL},
+ ${LDEMUL_NEW_VERS_PATTERN-NULL},
+ ${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL}
+};
+EOF
+#
+# Local Variables:
+# mode: c
+# End:
diff --git a/ld/scripttempl/elf32msp430.sc b/ld/scripttempl/elf32msp430.sc
index 15d563040f..65105e5200 100644
--- a/ld/scripttempl/elf32msp430.sc
+++ b/ld/scripttempl/elf32msp430.sc
@@ -154,12 +154,17 @@ SECTIONS
${CONSTRUCTING+ __dtors_end = . ; }
${RELOCATING+. = ALIGN(2);}
+ *(.lower.text.* .lower.text)
+
+ ${RELOCATING+. = ALIGN(2);}
*(.text)
${RELOCATING+. = ALIGN(2);}
*(.text.*)
${RELOCATING+. = ALIGN(2);}
*(.text:*)
+ *(.either.text.* .either.text)
+
${RELOCATING+. = ALIGN(2);}
*(SORT_NONE(.fini9))
*(SORT_NONE(.fini8))
@@ -178,11 +183,15 @@ SECTIONS
.rodata :
{
+ ${RELOCATING+. = ALIGN(2);}
+ *(.lower.rodata.* .lower.rodata)
+
. = ALIGN(2);
*(.plt)
*(.rodata .rodata.* .gnu.linkonce.r.* .const .const:*)
*(.rodata1)
+ *(.either.rodata.*) *(.either.rodata)
*(.eh_frame_hdr)
KEEP (*(.eh_frame))
@@ -242,23 +251,32 @@ SECTIONS
*(.data.rel.ro.local) *(.data.rel.ro*)
*(.dynamic)
+ ${RELOCATING+. = ALIGN(2);}
+ *(.lower.data.* .lower.data)
+
*(.data)
*(.data.*)
*(.gnu.linkonce.d*)
KEEP (*(.gnu.linkonce.d.*personality*))
*(.data1)
+
+ *(.either.data.* .either.data)
+
*(.got.plt) *(.got)
${RELOCATING+. = ALIGN(2);}
*(.sdata .sdata.* .gnu.linkonce.s.*)
${RELOCATING+. = ALIGN(2);}
${RELOCATING+ _edata = . ; }
} ${RELOCATING+ > data ${RELOCATING+AT> text}}
-
+
.bss ${RELOCATING+ SIZEOF(.data) + ADDR(.data)} :
{
${RELOCATING+. = ALIGN(2);}
${RELOCATING+ PROVIDE (__bss_start = .) ; }
+ *(.lower.bss.* .lower.bss)
+ ${RELOCATING+. = ALIGN(2);}
*(.bss)
+ *(.either.bss.* .either.bss)
*(COMMON)
${RELOCATING+ PROVIDE (__bss_end = .) ; }
${RELOCATING+ _end = . ; }