public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/4][MSP430] Improve behaviour of ".either" section placement
@ 2017-07-19 17:08 Jozef Lawrynowicz
  2017-07-19 17:16 ` [PATCH 1/4][MSP430] Add feature to add lower/either/upper prefixes to section names Jozef Lawrynowicz
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Jozef Lawrynowicz @ 2017-07-19 17:08 UTC (permalink / raw)
  To: binutils; +Cc: diwil, Nick Clifton

GCC for the MSP430 target has a feature that allows the user to specify
which memory region to place code and/or data in, using the -mcode-
region and -mdata-region options.
MSP430 devices with a high memory region support this placement of
code/data by defining ".upper" and ".lower" output sections in linker
scripts.
The parameters that can be passed to -mcode/data-region are "none",
"upper", "lower", "either". The use of the "either" option requires some
work to be done by the linker, to place ".either" code and data sections
in either the upper or lower regions to prevent memory region overflow,
if possible. The following patches improve and fix some of the existing
behaviour of this ".either" placement functionality.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/4][MSP430] Add feature to add lower/either/upper prefixes to section names
  2017-07-19 17:08 [PATCH 0/4][MSP430] Improve behaviour of ".either" section placement Jozef Lawrynowicz
@ 2017-07-19 17:16 ` Jozef Lawrynowicz
  2017-07-19 17:22   ` [PATCH 2/4][MSP430] Change .either section placement to be performed after allocation Jozef Lawrynowicz
  2017-07-20 12:36 ` [PATCH 0/4][MSP430] Improve behaviour of ".either" section placement Nick Clifton
  2017-08-24 17:17 ` Jozef Lawrynowicz
  2 siblings, 1 reply; 8+ messages in thread
From: Jozef Lawrynowicz @ 2017-07-19 17:16 UTC (permalink / raw)
  To: binutils; +Cc: Nick Clifton

[-- Attachment #1: Type: text/plain, Size: 790 bytes --]

This patch adds a feature to the linker which adds a lower/either/upper
prefix to code/data sections, depending on the option passed to --code-
region or --data-region. GCC propagates the parameters passed to -mcode-
region and -mdata-region to these linker options. The benefit of this
feature is that precompiled objects or libraries can now be shuffled
around by the linker placement algorithm. For example, simple C++
programs do not build for some devices with small ROM/RAM. Previously,
C++ libraries would take up many kB and would all be placed in lower
memory, but when the sections from the libraries are shuffled between
the regions there is enough space available to successfully link these
programs.

The added tests pass when built with todays GCC trunk and binutils master.


[-- Attachment #2: 0001-MSP430-Add-feature-to-add-lower-either-upper-prefixe.patch --]
[-- Type: text/plain, Size: 30828 bytes --]

From 50594250137c8250e9545037cc643fc91cd3d568 Mon Sep 17 00:00:00 2001
From: Jozef Lawrynowicz <jozef.l@somniumtech.com>
Date: Mon, 10 Jul 2017 13:14:53 +0000
Subject: [PATCH 1/4] MSP430: Add feature to add lower/either/upper prefixes to
 section names

---
 ld/emultempl/msp430.em                             | 276 ++++++++++++++++++++-
 ld/ld.texinfo                                      |  23 ++
 ld/testsuite/ld-msp430-elf/main-bss-lower.d        |   3 +
 ld/testsuite/ld-msp430-elf/main-bss-upper.d        |   3 +
 ld/testsuite/ld-msp430-elf/main-const-lower.d      |   3 +
 ld/testsuite/ld-msp430-elf/main-const-upper.d      |   3 +
 ld/testsuite/ld-msp430-elf/main-text-lower.d       |   3 +
 ld/testsuite/ld-msp430-elf/main-text-upper.d       |   6 +
 ld/testsuite/ld-msp430-elf/main-var-lower.d        |   3 +
 ld/testsuite/ld-msp430-elf/main-var-upper.d        |   3 +
 .../ld-msp430-elf/main-with-data-bss-unique-sec.s  |  78 ++++++
 ld/testsuite/ld-msp430-elf/main-with-data-bss.s    |  74 ++++++
 .../main-with-text-rodata-unique-sec.s             |  59 +++++
 ld/testsuite/ld-msp430-elf/main-with-text-rodata.s |  59 +++++
 ld/testsuite/ld-msp430-elf/msp430-elf.exp          | 112 +++++++++
 ld/testsuite/ld-msp430-elf/msp430-no-lower.ld      |  54 ++++
 ld/testsuite/ld-msp430-elf/msp430.ld               |  78 ++++++
 17 files changed, 836 insertions(+), 4 deletions(-)
 create mode 100644 ld/testsuite/ld-msp430-elf/main-bss-lower.d
 create mode 100644 ld/testsuite/ld-msp430-elf/main-bss-upper.d
 create mode 100644 ld/testsuite/ld-msp430-elf/main-const-lower.d
 create mode 100644 ld/testsuite/ld-msp430-elf/main-const-upper.d
 create mode 100644 ld/testsuite/ld-msp430-elf/main-text-lower.d
 create mode 100644 ld/testsuite/ld-msp430-elf/main-text-upper.d
 create mode 100644 ld/testsuite/ld-msp430-elf/main-var-lower.d
 create mode 100644 ld/testsuite/ld-msp430-elf/main-var-upper.d
 create mode 100644 ld/testsuite/ld-msp430-elf/main-with-data-bss-unique-sec.s
 create mode 100644 ld/testsuite/ld-msp430-elf/main-with-data-bss.s
 create mode 100644 ld/testsuite/ld-msp430-elf/main-with-text-rodata-unique-sec.s
 create mode 100644 ld/testsuite/ld-msp430-elf/main-with-text-rodata.s
 create mode 100644 ld/testsuite/ld-msp430-elf/msp430-elf.exp
 create mode 100644 ld/testsuite/ld-msp430-elf/msp430-no-lower.ld
 create mode 100644 ld/testsuite/ld-msp430-elf/msp430.ld

diff --git a/ld/emultempl/msp430.em b/ld/emultempl/msp430.em
index 949fea0..04f8a2b 100644
--- a/ld/emultempl/msp430.em
+++ b/ld/emultempl/msp430.em
@@ -39,6 +39,21 @@ fragment <<EOF
 #include "ldfile.h"
 #include "ldemul.h"
 #include "libiberty.h"
+#include <ldgram.h>
+
+enum regions
+{
+  REGION_NONE = 0,
+  REGION_LOWER,
+  REGION_UPPER,
+  REGION_EITHER = 3,
+};
+
+static int data_region = REGION_NONE;
+static int code_region = REGION_NONE;
+static bfd_boolean disable_sec_transformation = FALSE;
+
+#define MAX_PREFIX_LENGTH 7
 
 EOF
 
@@ -268,13 +283,266 @@ fi
 
 fragment <<EOF
 
+static bfd_boolean
+change_output_section (lang_statement_union_type ** head,
+		       asection *s,
+		       lang_output_section_statement_type * new_output_section)
+{
+  asection *is;
+  lang_statement_union_type * prev = NULL;
+  lang_statement_union_type * curr;
+  curr = *head;
+  while (curr != NULL)
+    {
+      switch (curr->header.type)
+	{
+	case lang_input_section_enum:
+	  is = curr->input_section.section;
+	  if (is == s)
+	    {
+	      s->output_section = NULL;
+	      lang_add_section (& (new_output_section->children), s, NULL,
+				new_output_section);
+	      /* Remove the section from the old output section.  */
+	      if (prev == NULL)
+		*head = curr->header.next;
+	      else
+		prev->header.next = curr->header.next;
+	      return TRUE;
+	    }
+	  break;
+	case lang_wild_statement_enum:
+	  if (change_output_section (&(curr->wild_statement.children.head),
+				     s, new_output_section))
+	    return TRUE;
+	  break;
+	default:
+	  break;
+	}
+      prev = curr;
+      curr = curr->header.next;
+    }
+  return FALSE;
+}
+
+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)
+{
+  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;
+  int region = REGION_NONE;
+  if (strncmp (curr_name, ".text", 5) == 0)
+    {
+      region = code_region;
+      base_name = concat (".text", NULL);
+    }
+  else if (strncmp (curr_name, ".data", 5) == 0)
+    {
+      region = data_region;
+      base_name = concat (".data", NULL);
+    }
+  else if (strncmp (curr_name, ".bss", 4) == 0)
+    {
+      region = data_region;
+      base_name = concat (".bss", NULL);
+    }
+  else if (strncmp (curr_name, ".rodata", 7) == 0)
+    {
+      region = data_region;
+      base_name = concat (".rodata", NULL);
+    }
+  else
+    return;
+
+  switch (region)
+    {
+    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);
+      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);
+      break;
+    case REGION_EITHER:
+      s->name = concat (".either", curr_name, NULL);
+      break;
+    default:
+      /* Unreachable.  */
+      FAIL ();
+      break;
+    }
+  free (base_name);
+  if (new_input_sec_name)
+    {
+      free (new_input_sec_name);
+      free (new_output_sec_name);
+    }
+}
+
+static void
+msp430_elf_after_open (void)
+{
+  gld${EMULATION_NAME}_after_open ();
+  /* If neither --code-region or --data-region have been passed, do not
+     transform sections names.  */
+  if ((code_region == REGION_NONE && data_region == REGION_NONE)
+      || disable_sec_transformation)
+    return;
+  bfd *abfd;
+  for (abfd = link_info.input_bfds; abfd != NULL; abfd = abfd->link.next)
+    {
+      bfd_map_over_sections (abfd, add_region_prefix, NULL);
+    }
+}
+
+#define OPTION_CODE_REGION		321
+#define OPTION_DATA_REGION		(OPTION_CODE_REGION + 1)
+#define OPTION_DISABLE_TRANS		(OPTION_CODE_REGION + 2)
+
+static void
+gld${EMULATION_NAME}_add_options
+  (int ns, char **shortopts, int nl, struct option **longopts,
+   int nrl ATTRIBUTE_UNUSED, struct option **really_longopts ATTRIBUTE_UNUSED)
+{
+  static const char xtra_short[] = { };
+
+  static const struct option xtra_long[] = {
+	{ "code-region", required_argument, NULL, OPTION_CODE_REGION },
+	{ "data-region", required_argument, NULL, OPTION_DATA_REGION },
+	{ "disable-sec-transformation", no_argument, NULL,
+	  OPTION_DISABLE_TRANS },
+	{ NULL, no_argument, NULL, 0 }
+  };
+
+  *shortopts = (char *) xrealloc (*shortopts, ns + sizeof (xtra_short));
+  memcpy (*shortopts + ns, &xtra_short, sizeof (xtra_short));
+  *longopts = (struct option *)
+    xrealloc (*longopts, nl * sizeof (struct option) + sizeof (xtra_long));
+  memcpy (*longopts + nl, &xtra_long, sizeof (xtra_long));
+}
+
+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"));
+}
+
+static bfd_boolean
+gld${EMULATION_NAME}_handle_option (int optc)
+{
+  switch (optc)
+    {
+    case OPTION_CODE_REGION:
+      if (strcmp (optarg, "upper") == 0)
+	code_region = REGION_UPPER;
+      else if (strcmp (optarg, "lower") == 0)
+	code_region = REGION_LOWER;
+      else if (strcmp (optarg, "either") == 0)
+	code_region = REGION_EITHER;
+      else if (strcmp (optarg, "none") == 0)
+	code_region = REGION_NONE;
+      else if (strlen (optarg) == 0)
+	{
+	  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);
+	  return FALSE;
+	}
+      break;
+
+    case OPTION_DATA_REGION:
+      if (strcmp (optarg, "upper") == 0)
+	data_region = REGION_UPPER;
+      else if (strcmp (optarg, "lower") == 0)
+	data_region = REGION_LOWER;
+      else if (strcmp (optarg, "either") == 0)
+	data_region = REGION_EITHER;
+      else if (strcmp (optarg, "none") == 0)
+	data_region = REGION_NONE;
+      else if (strlen (optarg) == 0)
+	{
+	  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);
+	  return FALSE;
+	}
+      break;
+
+    case OPTION_DISABLE_TRANS:
+      disable_sec_transformation = TRUE;
+      break;
+
+    default:
+      return FALSE;
+    }
+  return TRUE;
+}
+
 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},
+  msp430_elf_after_open,
   ${LDEMUL_AFTER_ALLOCATION-after_allocation_default},
   ${LDEMUL_SET_OUTPUT_ARCH-set_output_arch_default},
   ${LDEMUL_CHOOSE_TARGET-ldemul_default_target},
@@ -288,10 +556,10 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   ${LDEMUL_PLACE_ORPHAN-gld${EMULATION_NAME}_place_orphan},
   ${LDEMUL_SET_SYMBOLS-NULL},
   ${LDEMUL_PARSE_ARGS-NULL},
-  ${LDEMUL_ADD_OPTIONS-NULL},
-  ${LDEMUL_HANDLE_OPTION-NULL},
+  gld${EMULATION_NAME}_add_options,
+  gld${EMULATION_NAME}_handle_option,
   ${LDEMUL_UNRECOGNIZED_FILE-NULL},
-  ${LDEMUL_LIST_OPTIONS-NULL},
+  gld${EMULATION_NAME}_list_options,
   ${LDEMUL_RECOGNIZED_FILE-NULL},
   ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL},
   ${LDEMUL_NEW_VERS_PATTERN-NULL},
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index 987816f..53ccd6a4 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -7252,6 +7252,29 @@ Denotes a portion of RAM located above @samp{.bss} section.
 The last two sections are used by gcc.
 @end table
 
+@table @option
+@cindex MSP430 Options
+@kindex --code-region
+@item --code-region=[either,lower,upper,none]
+This will transform .text* sections to [either,lower,upper].text* sections. The
+argument passed to GCC for -mcode-region is propagated to the linker
+using this option.
+
+@kindex --data-region
+@item --data-region=[either,lower,upper,none]
+This will transform .data*, .bss* and .rodata* sections to
+[either,lower,upper].[data,bss,rodata]* sections. The argument passed to GCC
+for -mdata-region is propagated to the linker using this option.
+
+@kindex --disable-sec-transformation
+@item --disable-sec-transformation
+Prevent the transformation of sections as specified by the @code{--code-region}
+and @code{--data-region} options.
+This is useful if you are compiling and linking using a single call to the GCC
+wrapper, and want to compile the source files using -m[code,data]-region but
+not transform the sections for prebuilt libraries and objects.
+@end table
+
 @ifclear GENERIC
 @lowersections
 @end ifclear
diff --git a/ld/testsuite/ld-msp430-elf/main-bss-lower.d b/ld/testsuite/ld-msp430-elf/main-bss-lower.d
new file mode 100644
index 0000000..6007420
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-bss-lower.d
@@ -0,0 +1,3 @@
+#...
+Disassembly of section .lower.bss:
+#pass
diff --git a/ld/testsuite/ld-msp430-elf/main-bss-upper.d b/ld/testsuite/ld-msp430-elf/main-bss-upper.d
new file mode 100644
index 0000000..2f6376a7
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-bss-upper.d
@@ -0,0 +1,3 @@
+#...
+Disassembly of section .upper.bss:
+#pass
diff --git a/ld/testsuite/ld-msp430-elf/main-const-lower.d b/ld/testsuite/ld-msp430-elf/main-const-lower.d
new file mode 100644
index 0000000..8549961
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-const-lower.d
@@ -0,0 +1,3 @@
+#...
+Disassembly of section .lower.rodata:
+#pass
diff --git a/ld/testsuite/ld-msp430-elf/main-const-upper.d b/ld/testsuite/ld-msp430-elf/main-const-upper.d
new file mode 100644
index 0000000..c84d649
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-const-upper.d
@@ -0,0 +1,3 @@
+#...
+Disassembly of section .upper.rodata:
+#pass
diff --git a/ld/testsuite/ld-msp430-elf/main-text-lower.d b/ld/testsuite/ld-msp430-elf/main-text-lower.d
new file mode 100644
index 0000000..446a305
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-text-lower.d
@@ -0,0 +1,3 @@
+#...
+Disassembly of section .lower.text:
+#pass
diff --git a/ld/testsuite/ld-msp430-elf/main-text-upper.d b/ld/testsuite/ld-msp430-elf/main-text-upper.d
new file mode 100644
index 0000000..f7ae6af
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-text-upper.d
@@ -0,0 +1,6 @@
+
+.*:     file format.*msp430.*
+
+
+Disassembly of section .upper.text:
+#...
diff --git a/ld/testsuite/ld-msp430-elf/main-var-lower.d b/ld/testsuite/ld-msp430-elf/main-var-lower.d
new file mode 100644
index 0000000..f520cf5
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-var-lower.d
@@ -0,0 +1,3 @@
+#...
+Disassembly of section .lower.data:
+#pass
diff --git a/ld/testsuite/ld-msp430-elf/main-var-upper.d b/ld/testsuite/ld-msp430-elf/main-var-upper.d
new file mode 100644
index 0000000..fc3d712
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-var-upper.d
@@ -0,0 +1,3 @@
+#...
+Disassembly of section .upper.data:
+#pass
diff --git a/ld/testsuite/ld-msp430-elf/main-with-data-bss-unique-sec.s b/ld/testsuite/ld-msp430-elf/main-with-data-bss-unique-sec.s
new file mode 100644
index 0000000..7774804
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-with-data-bss-unique-sec.s
@@ -0,0 +1,78 @@
+	.file	"main-with-data-bss.c"
+	.global	glob_var_array
+	.section	.data.glob_var_array,"aw",@progbits
+	.balign 2
+	.type	glob_var_array, @object
+	.size	glob_var_array, 20
+glob_var_array:
+	.short	0
+	.short	1
+	.short	2
+	.short	3
+	.short	4
+	.short	5
+	.short	6
+	.short	7
+	.short	8
+	.short	9
+	.section	.bss.glob_bss_array,"aw",@nobits
+	.balign 2
+	.type	glob_bss_array, @object
+	.size	glob_bss_array, 20
+glob_bss_array:
+	.zero	20
+	.section	.text.main,"ax",@progbits
+	.balign 2
+	.global	main
+	.type	main, @function
+main:
+; start of function
+; framesize_regs:     0
+; framesize_locals:   2
+; framesize_outgoing: 0
+; framesize:          2
+; elim ap -> fp       2
+; elim fp -> sp       2
+; saved regs:(none)
+	; start of prologue
+	SUB.W	#2, R1
+	; end of prologue
+	MOV.W	#0, @R1
+	BR	#.L2
+.L7:
+	MOV.W	@R1, R12
+	ADD.W	R12, R12
+	ADD.W	#glob_var_array, R12
+	MOV.W	@R12, R13
+	MOV.W	R13, R12
+	ADD.W	R12, R12
+	ADD.W	R13, R12
+	rpt	#2 { rlax.w	R12
+	SUB.W	R13, R12
+	CMP.W	#110, R12 { JNE	.L3
+.L4:
+	BR	#.L4
+.L3:
+	MOV.W	@R1, R12
+	ADD.W	R12, R12
+	ADD.W	#glob_bss_array, R12
+	MOV.W	@R12, R13
+	MOV.W	R13, R12
+	ADD.W	R12, R12
+	ADD.W	R13, R12
+	rpt	#2 { rlax.w	R12
+	SUB.W	R13, R12
+	CMP.W	#110, R12 { JNE	.L5
+.L6:
+	BR	#.L6
+.L5:
+	ADD.W	#1, @R1
+.L2:
+	MOV.B	#9, R12
+	CMP.W	@R1, R12 { JGE	.L7
+	MOV.B	#0, R12
+	; start of epilogue
+	.refsym	__crt0_call_exit
+	ADD.W	#2, R1
+	RET
+	.size	main, .-main
diff --git a/ld/testsuite/ld-msp430-elf/main-with-data-bss.s b/ld/testsuite/ld-msp430-elf/main-with-data-bss.s
new file mode 100644
index 0000000..a406b64
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-with-data-bss.s
@@ -0,0 +1,74 @@
+	.file	"main-with-data-bss.c"
+	.global	glob_var_array
+.data
+	.balign 2
+	.type	glob_var_array, @object
+	.size	glob_var_array, 20
+glob_var_array:
+	.short	0
+	.short	1
+	.short	2
+	.short	3
+	.short	4
+	.short	5
+	.short	6
+	.short	7
+	.short	8
+	.short	9
+	.local	glob_bss_array
+	.comm	glob_bss_array,20,2
+.text
+	.balign 2
+	.global	main
+	.type	main, @function
+main:
+; start of function
+; framesize_regs:     0
+; framesize_locals:   2
+; framesize_outgoing: 0
+; framesize:          2
+; elim ap -> fp       2
+; elim fp -> sp       2
+; saved regs:(none)
+	; start of prologue
+	SUB.W	#2, R1
+	; end of prologue
+	MOV.W	#0, @R1
+	BR	#.L2
+.L7:
+	MOV.W	@R1, R12
+	ADD.W	R12, R12
+	ADD.W	#glob_var_array, R12
+	MOV.W	@R12, R13
+	MOV.W	R13, R12
+	ADD.W	R12, R12
+	ADD.W	R13, R12
+	rpt	#2 { rlax.w	R12
+	SUB.W	R13, R12
+	CMP.W	#110, R12 { JNE	.L3
+.L4:
+	BR	#.L4
+.L3:
+	MOV.W	@R1, R12
+	ADD.W	R12, R12
+	ADD.W	#glob_bss_array, R12
+	MOV.W	@R12, R13
+	MOV.W	R13, R12
+	ADD.W	R12, R12
+	ADD.W	R13, R12
+	rpt	#2 { rlax.w	R12
+	SUB.W	R13, R12
+	CMP.W	#110, R12 { JNE	.L5
+.L6:
+	BR	#.L6
+.L5:
+	ADD.W	#1, @R1
+.L2:
+	MOV.B	#9, R12
+	CMP.W	@R1, R12 { JGE	.L7
+	MOV.B	#0, R12
+	; start of epilogue
+	.refsym	__crt0_call_exit
+	ADD.W	#2, R1
+	RET
+	.size	main, .-main
diff --git a/ld/testsuite/ld-msp430-elf/main-with-text-rodata-unique-sec.s b/ld/testsuite/ld-msp430-elf/main-with-text-rodata-unique-sec.s
new file mode 100644
index 0000000..398cf74
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-with-text-rodata-unique-sec.s
@@ -0,0 +1,59 @@
+	.file	"main-with-text-rodata.c"
+	.global	glob_const_array
+	.section	.rodata.glob_const_array,"a",@progbits
+	.balign 2
+	.type	glob_const_array, @object
+	.size	glob_const_array, 20
+glob_const_array:
+	.short	0
+	.short	1
+	.short	2
+	.short	3
+	.short	4
+	.short	5
+	.short	6
+	.short	7
+	.short	8
+	.short	9
+	.section	.text.main,"ax",@progbits
+	.balign 2
+	.global	main
+	.type	main, @function
+main:
+; start of function
+; framesize_regs:     0
+; framesize_locals:   2
+; framesize_outgoing: 0
+; framesize:          2
+; elim ap -> fp       2
+; elim fp -> sp       2
+; saved regs:(none)
+	; start of prologue
+	SUB.W	#2, R1
+	; end of prologue
+	MOV.W	#0, @R1
+	BR	#.L2
+.L5:
+	MOV.W	@R1, R12
+	ADD.W	R12, R12
+	ADD.W	#glob_const_array, R12
+	MOV.W	@R12, R13
+	MOV.W	R13, R12
+	ADD.W	R12, R12
+	ADD.W	R13, R12
+	rpt	#2 { rlax.w	R12
+	SUB.W	R13, R12
+	CMP.W	#110, R12 { JNE	.L3
+.L4:
+	BR	#.L4
+.L3:
+	ADD.W	#1, @R1
+.L2:
+	MOV.B	#9, R12
+	CMP.W	@R1, R12 { JGE	.L5
+	MOV.B	#0, R12
+	; start of epilogue
+	.refsym	__crt0_call_exit
+	ADD.W	#2, R1
+	RET
+	.size	main, .-main
diff --git a/ld/testsuite/ld-msp430-elf/main-with-text-rodata.s b/ld/testsuite/ld-msp430-elf/main-with-text-rodata.s
new file mode 100644
index 0000000..225b5d4
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-with-text-rodata.s
@@ -0,0 +1,59 @@
+	.file	"main-with-text-rodata.c"
+	.global	glob_const_array
+	.section	.rodata
+	.balign 2
+	.type	glob_const_array, @object
+	.size	glob_const_array, 20
+glob_const_array:
+	.short	0
+	.short	1
+	.short	2
+	.short	3
+	.short	4
+	.short	5
+	.short	6
+	.short	7
+	.short	8
+	.short	9
+.text
+	.balign 2
+	.global	main
+	.type	main, @function
+main:
+; start of function
+; framesize_regs:     0
+; framesize_locals:   2
+; framesize_outgoing: 0
+; framesize:          2
+; elim ap -> fp       2
+; elim fp -> sp       2
+; saved regs:(none)
+	; start of prologue
+	SUB.W	#2, R1
+	; end of prologue
+	MOV.W	#0, @R1
+	BR	#.L2
+.L5:
+	MOV.W	@R1, R12
+	ADD.W	R12, R12
+	ADD.W	#glob_const_array, R12
+	MOV.W	@R12, R13
+	MOV.W	R13, R12
+	ADD.W	R12, R12
+	ADD.W	R13, R12
+	rpt	#2 { rlax.w	R12
+	SUB.W	R13, R12
+	CMP.W	#110, R12 { JNE	.L3
+.L4:
+	BR	#.L4
+.L3:
+	ADD.W	#1, @R1
+.L2:
+	MOV.B	#9, R12
+	CMP.W	@R1, R12 { JGE	.L5
+	MOV.B	#0, R12
+	; start of epilogue
+	.refsym	__crt0_call_exit
+	ADD.W	#2, R1
+	RET
+	.size	main, .-main
diff --git a/ld/testsuite/ld-msp430-elf/msp430-elf.exp b/ld/testsuite/ld-msp430-elf/msp430-elf.exp
new file mode 100644
index 0000000..bed2ed8
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/msp430-elf.exp
@@ -0,0 +1,112 @@
+# Expect script for various MSP430 ELF tests.
+#   Copyright (C) 2002-2015 Free Software Foundation, Inc.
+#
+# 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.
+#
+
+if { ![istarget "msp430*elf*"] } {
+    return
+}
+
+# List contains test-items with 3 items followed by 2 lists and one more item:
+# 0:name 1:ld early options 2:ld late options 3:assembler options
+# 4:filenames of assembler files 5: action and options. 6: name of output file
+
+# Actions:
+# objdump: Apply objdump options on result.  Compare with regex (last arg).
+# nm: Apply nm options on result.  Compare with regex (last arg).
+# readelf: Apply readelf options on result.  Compare with regex (last arg).
+
+set msp430regionprefixtests {
+  {"Move main() to .upper.text" "-T msp430.ld --code-region=upper"
+    "" "" {main-with-text-rodata.s} {{objdump -d main-text-upper.d}} "main-upper"}
+  {"Move main() to .upper.text. No .lower.text in ld script" "-T msp430-no-lower.ld --code-region=upper"
+    "" "" {main-with-text-rodata.s} {{objdump -d main-text-upper.d}} "main-upper"}
+  {"Move main() to .lower.text" "-T msp430.ld --code-region=lower"
+    "" "" {main-with-text-rodata.s} {{objdump -d main-text-lower.d}} "main-lower"}
+  {"Move \"either\" main() to .lower.text" "-T msp430.ld --code-region=either"
+    "" "" {main-with-text-rodata.s} {{objdump -d main-text-lower.d}} "main-either"}
+
+  {"Move glob_var to .upper.data" "-T msp430.ld --data-region=upper"
+    "" "" {main-with-data-bss.s} {{objdump -D main-var-upper.d}} "main-var-upper"}
+  {"Move glob_var to .upper.data. No .lower.data in ld script" "-T msp430-no-lower.ld --data-region=upper"
+    "" "" {main-with-data-bss.s} {{objdump -D main-var-upper.d}} "main-var-upper"}
+  {"Move glob_var to .lower.data" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-data-bss.s} {{objdump -D main-var-lower.d}} "main-var-lower"}
+  {"Move \"either\" glob_var to .lower.data" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-data-bss.s} {{objdump -D main-var-lower.d}} "main-var-lower"}
+
+  {"Move glob_zero to .upper.bss" "-T msp430.ld --data-region=upper"
+    "" "" {main-with-data-bss.s} {{objdump -D main-bss-upper.d}} "main-bss-upper"}
+  {"Move glob_zero to .upper.bss. No .lower.bss in ld script." "-T msp430-no-lower.ld --data-region=upper"
+    "" "" {main-with-data-bss.s} {{objdump -D main-bss-upper.d}} "main-bss-upper"}
+  {"Move glob_zero to .lower.bss" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-data-bss.s} {{objdump -D main-bss-lower.d}} "main-bss-lower"}
+  {"Move \"either\" glob_zero to .lower.bss" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-data-bss.s} {{objdump -D main-bss-lower.d}} "main-bss-lower"}
+
+  {"Move glob_const to .upper.rodata" "-T msp430.ld --data-region=upper"
+    "" "" {main-with-text-rodata.s} {{objdump -D main-const-upper.d}} "main-const-upper"}
+  {"Move glob_const to .upper.rodata. No .lower.rodata in ld script." "-T msp430-no-lower.ld --data-region=upper"
+    "" "" {main-with-text-rodata.s} {{objdump -D main-const-upper.d}} "main-const-upper"}
+  {"Move glob_const to .lower.rodata" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-text-rodata.s} {{objdump -D main-const-lower.d}} "main-const-lower"}
+  {"Move \"either\" glob_const to .lower.rodata" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-text-rodata.s} {{objdump -D main-const-lower.d}} "main-const-lower"}
+}
+
+set msp430regionprefixuniquesectiontests {
+  {"Move main() to .upper.text, with -ffunction/data-sections" "-T msp430.ld --code-region=upper"
+    "" "" {main-with-text-rodata-unique-sec.s} {{objdump -d main-text-upper.d}} "main-upper"}
+  {"Move main() to .upper.text. No .lower.text in ld script, with -ffunction/data-sections" "-T msp430-no-lower.ld --code-region=upper"
+    "" "" {main-with-text-rodata-unique-sec.s} {{objdump -d main-text-upper.d}} "main-upper"}
+  {"Move main() to .lower.text, with -ffunction/data-sections" "-T msp430.ld --code-region=lower"
+    "" "" {main-with-text-rodata-unique-sec.s} {{objdump -d main-text-lower.d}} "main-lower"}
+  {"Move \"either\" main() to .lower.text, with -ffunction/data-sections" "-T msp430.ld --code-region=either"
+    "" "" {main-with-text-rodata-unique-sec.s} {{objdump -d main-text-lower.d}} "main-either"}
+
+  {"Move glob_var to .upper.data, with -ffunction/data-sections" "-T msp430.ld --data-region=upper"
+    "" "" {main-with-data-bss-unique-sec.s} {{objdump -D main-var-upper.d}} "main-var-upper"}
+  {"Move glob_var to .upper.data. No .lower.data in ld script, with -ffunction/data-sections" "-T msp430-no-lower.ld --data-region=upper"
+    "" "" {main-with-data-bss-unique-sec.s} {{objdump -D main-var-upper.d}} "main-var-upper"}
+  {"Move glob_var to .lower.data, with -ffunction/data-sections" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-data-bss-unique-sec.s} {{objdump -D main-var-lower.d}} "main-var-lower"}
+  {"Move \"either\" glob_var to .lower.data, with -ffunction/data-sections" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-data-bss-unique-sec.s} {{objdump -D main-var-lower.d}} "main-var-lower"}
+
+  {"Move glob_zero to .upper.bss, with -ffunction/data-sections" "-T msp430.ld --data-region=upper"
+    "" "" {main-with-data-bss-unique-sec.s} {{objdump -D main-bss-upper.d}} "main-bss-upper"}
+  {"Move glob_zero to .upper.bss. No .lower.bss in ld script., with -ffunction/data-sections" "-T msp430-no-lower.ld --data-region=upper"
+    "" "" {main-with-data-bss-unique-sec.s} {{objdump -D main-bss-upper.d}} "main-bss-upper"}
+  {"Move glob_zero to .lower.bss, with -ffunction/data-sections" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-data-bss-unique-sec.s} {{objdump -D main-bss-lower.d}} "main-bss-lower"}
+  {"Move \"either\" glob_zero to .lower.bss, with -ffunction/data-sections" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-data-bss-unique-sec.s} {{objdump -D main-bss-lower.d}} "main-bss-lower"}
+
+  {"Move glob_const to .upper.rodata, with -ffunction/data-sections" "-T msp430.ld --data-region=upper"
+    "" "" {main-with-text-rodata-unique-sec.s} {{objdump -D main-const-upper.d}} "main-const-upper"}
+  {"Move glob_const to .upper.rodata. No .lower.rodata in ld script., with -ffunction/data-sections" "-T msp430-no-lower.ld --data-region=upper"
+    "" "" {main-with-text-rodata-unique-sec.s} {{objdump -D main-const-upper.d}} "main-const-upper"}
+  {"Move glob_const to .lower.rodata, with -ffunction/data-sections" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-text-rodata-unique-sec.s} {{objdump -D main-const-lower.d}} "main-const-lower"}
+  {"Move \"either\" glob_const to .lower.rodata, with -ffunction/data-sections" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-text-rodata-unique-sec.s} {{objdump -D main-const-lower.d}} "main-const-lower"}
+}
+
+run_ld_link_tests $msp430regionprefixtests
+run_ld_link_tests $msp430regionprefixuniquesectiontests
diff --git a/ld/testsuite/ld-msp430-elf/msp430-no-lower.ld b/ld/testsuite/ld-msp430-elf/msp430-no-lower.ld
new file mode 100644
index 0000000..f9a2847
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/msp430-no-lower.ld
@@ -0,0 +1,54 @@
+/* Script for ld testsuite */
+OUTPUT_ARCH(msp430)
+ENTRY(_start)
+
+SECTIONS
+{
+  .text :
+  {
+    PROVIDE (_start = .);
+    . = ALIGN(2);
+    *(.text .stub .text.* .gnu.linkonce.t.* .text:*)
+  }
+
+  .rodata :
+  {
+    *(.rodata.* .rodata)
+  }
+
+  .data :
+  {
+    . = ALIGN(2);
+    *(.data.* .data)
+  }
+
+  .bss :
+  {
+    . = ALIGN(2);
+    *(.bss.* .bss)
+  }
+
+  .upper.text :
+  {
+    . = ALIGN(2);
+    *(.upper.text.* .upper.text)
+  }
+
+  .upper.rodata :
+  {
+    . = ALIGN(2);
+    *(.upper.rodata .upper.rodata.*)
+  }
+
+  .upper.data :
+  {
+    . = ALIGN(2);
+    *(.upper.data .upper.data.*)
+  }
+
+  .upper.bss :
+  {
+    . = ALIGN(2);
+    *(.upper.bss .upper.bss.*)
+  }
+}
diff --git a/ld/testsuite/ld-msp430-elf/msp430.ld b/ld/testsuite/ld-msp430-elf/msp430.ld
new file mode 100644
index 0000000..9c30836
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/msp430.ld
@@ -0,0 +1,78 @@
+/* Script for ld testsuite */
+OUTPUT_ARCH(msp430)
+ENTRY(_start)
+
+SECTIONS
+{
+  .lower.data :
+  {
+    . = ALIGN(2);
+    *(.lower.data .lower.data.*)
+  }
+
+  .lower.bss :
+  {
+    . = ALIGN(2);
+    *(.lower.bss .lower.bss.*)
+  }
+
+  .lower.text :
+  {
+    PROVIDE (_start = .);
+    . = ALIGN(2);
+    *(.lower.text.* .lower.text)
+  }
+
+  .lower.rodata :
+  {
+    . = ALIGN(2);
+    *(.lower.rodata .lower.rodata.*)
+  }
+
+  .text :
+  {
+    . = ALIGN(2);
+    *(.text .stub .text.* .gnu.linkonce.t.* .text:*)
+  }
+
+  .rodata :
+  {
+    *(.rodata.* .rodata)
+  }
+
+  .data :
+  {
+    . = ALIGN(2);
+    *(.data.* .data)
+  }
+
+  .bss :
+  {
+    . = ALIGN(2);
+    *(.bss.* .bss)
+  }
+
+  .upper.text :
+  {
+    . = ALIGN(2);
+    *(.upper.text.* .upper.text)
+  }
+
+  .upper.rodata :
+  {
+    . = ALIGN(2);
+    *(.upper.rodata .upper.rodata.*)
+  }
+
+  .upper.data :
+  {
+    . = ALIGN(2);
+    *(.upper.data .upper.data.*)
+  }
+
+  .upper.bss :
+  {
+    . = ALIGN(2);
+    *(.upper.bss .upper.bss.*)
+  }
+}
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 2/4][MSP430] Change .either section placement to be performed after allocation
  2017-07-19 17:16 ` [PATCH 1/4][MSP430] Add feature to add lower/either/upper prefixes to section names Jozef Lawrynowicz
@ 2017-07-19 17:22   ` Jozef Lawrynowicz
  2017-07-19 17:30     ` [PATCH 3/4][MSP430] Remove .either placement code from place_orphan Jozef Lawrynowicz
  0 siblings, 1 reply; 8+ messages in thread
From: Jozef Lawrynowicz @ 2017-07-19 17:22 UTC (permalink / raw)
  To: binutils; +Cc: Nick Clifton

[-- Attachment #1: Type: text/plain, Size: 780 bytes --]

This patch adds ".either" section placement functionality in the
"after_allocation" stage of the linker. At present, ".either" section
placement is performed only in place_orphan, and at this stage the sizes
of sections have not been finalised, as there is still relaxation to be
performed. This can lead to ROM/RAM overflow, despite there being space
in the upper regions for code/data to be placed. The modified
after_allocation stage relaxes sections just before attempting to move
them, so the section sizes can be assumed accurate. This new placement
stage operates in two passes, firstly to move .either sections in .lower
to .upper if they cause .lower to overflow, and secondly to move .either
sections in .upper to .lower if they fit in .lower and .upper is
overflowing.

[-- Attachment #2: 0002-MSP430-Change-.either-section-placement-to-be-perfor.patch --]
[-- Type: text/plain, Size: 15490 bytes --]

From 4a3c924adcd6e3d9a5adce0a8fe5d414aa320077 Mon Sep 17 00:00:00 2001
From: Jozef Lawrynowicz <jozef.l@somniumtech.com>
Date: Mon, 10 Jul 2017 15:12:18 +0000
Subject: [PATCH 2/4] MSP430: Change .either section placement to be performed
 after allocation

---
 ld/emultempl/msp430.em                        | 309 +++++++++++++++++++++++++-
 ld/testsuite/ld-msp430-elf/msp430-elf.exp     |  29 +++
 ld/testsuite/ld-msp430-elf/msp430-tiny-ram.ld |  49 ++++
 ld/testsuite/ld-msp430-elf/msp430-tiny-rom.ld |  48 ++++
 4 files changed, 434 insertions(+), 1 deletion(-)
 create mode 100644 ld/testsuite/ld-msp430-elf/msp430-tiny-ram.ld
 create mode 100644 ld/testsuite/ld-msp430-elf/msp430-tiny-rom.ld

diff --git a/ld/emultempl/msp430.em b/ld/emultempl/msp430.em
index 04f8a2b..15c60a7 100644
--- a/ld/emultempl/msp430.em
+++ b/ld/emultempl/msp430.em
@@ -139,6 +139,32 @@ fi
 if test x"$LDEMUL_PLACE_ORPHAN" != xgld"$EMULATION_NAME"_place_orphan; then
 fragment <<EOF
 
+static unsigned int
+data_statement_size (lang_data_statement_type *d)
+{
+  unsigned int size = 0;
+  switch (d->type)
+    {
+    case QUAD:
+    case SQUAD:
+      size = QUAD_SIZE;
+      break;
+    case LONG:
+      size = LONG_SIZE;
+      break;
+    case SHORT:
+      size = SHORT_SIZE;
+      break;
+    case BYTE:
+      size = BYTE_SIZE;
+      break;
+    default:
+      einfo ("%P: error: unhandled data_statement size\n");
+      FAIL ();
+    }
+  return size;
+}
+
 /* Helper function for place_orphan that computes the size
    of sections already mapped to the given statement.  */
 
@@ -158,12 +184,17 @@ scan_children (lang_statement_union_type * l)
 
 	case lang_constructors_statement_enum:
 	case lang_assignment_statement_enum:
+	case lang_padding_statement_enum:
 	  break;
 
 	case lang_wild_statement_enum:
 	  amount += scan_children (l->wild_statement.children.head);	  
 	  break;
 
+	case lang_data_statement_enum:
+	  amount += data_statement_size (&l->data_statement);
+	  break;
+
 	default:
 	  fprintf (stderr, "msp430 orphan placer: unhandled lang type %d\n", l->header.type);
 	  break;
@@ -536,6 +567,282 @@ gld${EMULATION_NAME}_handle_option (int optc)
   return TRUE;
 }
 
+enum { ROM, RAM };
+
+static void
+eval_upper_either_sections (bfd *abfd, asection *s, void *data)
+{
+  if ((s->flags & SEC_ALLOC) == 0)
+    return;
+  if (bfd_link_relocatable (&link_info))
+    return;
+
+  char * base_sec_name = (char *) data;
+  const char *curr_name = bfd_get_section_name (abfd, s);
+
+  /* Only concerned with .either input sections in the upper output section.
+   * */
+  char * either_name = concat (".either", base_sec_name, NULL);
+  if (strncmp (curr_name, either_name, strlen (either_name)) != 0
+      || strncmp (s->output_section->name, ".upper", 6) != 0)
+    goto end;
+
+  lang_output_section_statement_type * lower
+    = lang_output_section_find (concat (".lower", base_sec_name, NULL));
+  lang_output_section_statement_type * upper
+    = lang_output_section_find (concat (".upper", base_sec_name, NULL));
+
+
+  if (upper == NULL)
+    goto end;
+  else if (lower == NULL)
+    lower = lang_output_section_find (base_sec_name);
+
+  int curr_region;
+  if (strcmp (base_sec_name, ".text") == 0
+      || strcmp (base_sec_name, ".rodata") == 0)
+    curr_region = ROM;
+  else
+    curr_region = RAM;
+
+  static bfd_size_type *lower_size = 0;
+  static bfd_size_type *upper_size = 0;
+  static bfd_size_type lower_size_rom = 0;
+  static bfd_size_type lower_size_ram = 0;
+  static bfd_size_type upper_size_rom = 0;
+  static bfd_size_type upper_size_ram = 0;
+  if (curr_region == ROM)
+    {
+      if (lower_size_rom == 0)
+	{
+	  lower_size_rom = lower->region->current - lower->region->origin;
+	  upper_size_rom = upper->region->current - upper->region->origin;
+	}
+      lower_size = &lower_size_rom;
+      upper_size = &upper_size_rom;
+    }
+  else if (curr_region == RAM)
+    {
+      if (lower_size_ram == 0)
+	{
+	  lower_size_ram = lower->region->current - lower->region->origin;
+	  upper_size_ram = upper->region->current - upper->region->origin;
+	}
+      lower_size = &lower_size_ram;
+      upper_size = &upper_size_ram;
+    }
+
+  /* Move sections in the upper region that would fit in the lower
+   * region to the lower region if the upper region is overflowing.  */
+  if (*upper_size > upper->region->length
+      && *lower_size + s->size < lower->region->length)
+    {
+      if (change_output_section (&(upper->children.head),
+				 s, lower))
+	{
+	  *upper_size -= s->size;
+	  *lower_size += s->size;
+	}
+    }
+ end:
+  free (either_name);
+}
+
+static void
+eval_lower_either_sections (bfd *abfd, asection *s, void *data)
+{
+  if ((s->flags & SEC_ALLOC) == 0)
+    return;
+  if (bfd_link_relocatable (&link_info))
+    return;
+
+  char * base_sec_name = (char *) data;
+  const char *curr_name = bfd_get_section_name (abfd, s);
+
+  /* Only concerned with .either input sections in the lower or "default"
+   * output section i.e. not in the upper output section.  */
+  char * either_name = concat (".either", base_sec_name, NULL);
+  if (strncmp (curr_name, either_name, strlen (either_name)) != 0
+      || strncmp (s->output_section->name, ".upper", 6) == 0)
+    return;
+
+  int curr_region;
+  if (strcmp (base_sec_name, ".text") == 0
+      || strcmp (base_sec_name, ".rodata") == 0)
+    curr_region = ROM;
+  else
+    curr_region = RAM;
+
+  lang_output_section_statement_type * output_sec
+    = lang_output_section_find (s->output_section->name);
+
+  /* If the output_section doesn't exist, this has already been reported in
+   * place_orphan, so don't need to warn again.  */
+  if (output_sec == NULL)
+    return;
+
+  /* lower and output_sec might be the same, but in some cases an .either
+   * section can end up in base_sec_name if it hasn't been placed by
+   * place_orphan.  */
+  lang_output_section_statement_type * lower
+    = lang_output_section_find (concat (".lower", base_sec_name, NULL));
+  lang_output_section_statement_type * upper
+    = lang_output_section_find (concat (".upper", base_sec_name, NULL));
+  if (upper == NULL)
+    goto end;
+
+  static bfd_size_type *lower_size = 0;
+  static bfd_size_type lower_size_rom = 0;
+  static bfd_size_type lower_size_ram = 0;
+  if (curr_region == ROM)
+    {
+      if (lower_size_rom == 0)
+	{
+	  /* Get the size of other items in the lower region that aren't the
+	   * sections to be moved around.  */
+	  lower_size_rom
+	    = (output_sec->region->current - output_sec->region->origin)
+	    - scan_children (output_sec->children.head);
+	  if (output_sec != lower && lower != NULL)
+	    lower_size_rom -= scan_children (lower->children.head);
+	}
+      lower_size = &lower_size_rom;
+    }
+  else if (curr_region == RAM)
+    {
+      if (lower_size_ram == 0)
+	{
+	  lower_size_ram
+	    = (output_sec->region->current - output_sec->region->origin)
+	    - scan_children (output_sec->children.head);
+	  if (output_sec != lower && lower != NULL)
+	    lower_size_ram -= scan_children (lower->children.head);
+	}
+      lower_size = &lower_size_ram;
+    }
+  /* 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);
+  else
+    *lower_size += s->size;
+ end:
+  free (either_name);
+}
+
+/* This function is similar to lang_relax_sections, but without the size
+ * evaluation code that is always executed after relaxation.  */
+static void
+intermediate_relax_sections (void)
+{
+  int i = link_info.relax_pass;
+
+  /* The backend can use it to determine the current pass.  */
+  link_info.relax_pass = 0;
+
+  while (i--)
+    {
+      bfd_boolean relax_again;
+
+      link_info.relax_trip = -1;
+      do
+	{
+	  link_info.relax_trip++;
+
+	  lang_do_assignments (lang_assigning_phase_enum);
+
+	  lang_reset_memory_regions ();
+
+	  relax_again = FALSE;
+	  lang_size_sections (&relax_again, FALSE);
+	}
+      while (relax_again);
+
+      link_info.relax_pass++;
+    }
+}
+
+enum either_placement_stage
+{
+  LOWER_TO_UPPER,
+  UPPER_TO_LOWER,
+};
+
+static void
+msp430_elf_after_allocation (void)
+{
+  int relax_count = 0;
+  int i;
+  /* Go over each section twice, once to place either sections that don't fit
+   * in lower into upper, and then again to move any sections in upper that fit
+   * in lower into lower.  */
+  for (i = 0; i < 8; i++)
+    {
+      int placement_stage = (i < 4) ? LOWER_TO_UPPER : UPPER_TO_LOWER;
+      char * base_sec_name;
+      switch (i % 4)
+	{
+	case 0:
+	  base_sec_name = concat (".text", NULL);
+	  break;
+	case 1:
+	  base_sec_name = concat (".data", NULL);
+	  break;
+	case 2:
+	  base_sec_name = concat (".bss", NULL);
+	  break;
+	case 3:
+	  base_sec_name = concat (".rodata", NULL);
+	  break;
+	}
+      lang_output_section_statement_type * upper
+	= lang_output_section_find (concat (".upper", base_sec_name, NULL));
+      if (upper != NULL)
+	{
+	  /* Can't just use one iteration over the all the sections to make
+	   * both lower->upper and upper->lower transformations because the
+	   * iterator encounters upper sections before all lower sections have
+	   * been examined.  */
+	  bfd *abfd;
+	  if (placement_stage == LOWER_TO_UPPER)
+	    {
+	      /* Perform relaxation and get the final size of sections before
+	       * trying to fit .either sections in the correct ouput sections.
+	       */
+	      if (relax_count == 0)
+		{
+		  intermediate_relax_sections ();
+		  relax_count++;
+		}
+	      for (abfd = link_info.input_bfds; abfd != NULL;
+		   abfd = abfd->link.next)
+		{
+		  bfd_map_over_sections (abfd, eval_lower_either_sections,
+					 base_sec_name);
+		}
+	    }
+	  else if (placement_stage == UPPER_TO_LOWER)
+	    {
+	      /* Relax again before moving upper->lower.  */
+	      if (relax_count == 1)
+		{
+		  intermediate_relax_sections ();
+		  relax_count++;
+		}
+	      for (abfd = link_info.input_bfds; abfd != NULL;
+		   abfd = abfd->link.next)
+		{
+		  bfd_map_over_sections (abfd, eval_upper_either_sections,
+					 base_sec_name);
+		}
+	    }
+
+	}
+      free (base_sec_name);
+    }
+  gld${EMULATION_NAME}_after_allocation ();
+}
+
 struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
 {
   ${LDEMUL_BEFORE_PARSE-gld${EMULATION_NAME}_before_parse},
@@ -543,7 +850,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   ${LDEMUL_HLL-hll_default},
   ${LDEMUL_AFTER_PARSE-after_parse_default},
   msp430_elf_after_open,
-  ${LDEMUL_AFTER_ALLOCATION-after_allocation_default},
+  msp430_elf_after_allocation,
   ${LDEMUL_SET_OUTPUT_ARCH-set_output_arch_default},
   ${LDEMUL_CHOOSE_TARGET-ldemul_default_target},
   ${LDEMUL_BEFORE_ALLOCATION-before_allocation_default},
diff --git a/ld/testsuite/ld-msp430-elf/msp430-elf.exp b/ld/testsuite/ld-msp430-elf/msp430-elf.exp
index bed2ed8..fa396aa 100644
--- a/ld/testsuite/ld-msp430-elf/msp430-elf.exp
+++ b/ld/testsuite/ld-msp430-elf/msp430-elf.exp
@@ -108,5 +108,34 @@ set msp430regionprefixuniquesectiontests {
     "" "" {main-with-text-rodata-unique-sec.s} {{objdump -D main-const-lower.d}} "main-const-lower"}
 }
 
+set msp430eithershuffletests {
+  {"Move \"either\" main() to .upper.text when it doesn\'t fit in .lower.text"
+    "-T msp430-tiny-rom.ld --code-region=either --data-region=either" "" "" {main-with-text-rodata.s}
+    {{objdump -d main-text-upper.d}} "either-to-upper-text"}
+  {"Move \"either\" glob_var_array to .upper.data when it doesn\'t fit in .lower.data"
+    "-T msp430-tiny-ram.ld --data-region=either" "" "" {main-with-data-bss.s}
+    {{objdump -D main-var-upper.d}} "either-to-upper-data"}
+  {"Move \"either\" glob_bss_array to .upper.bss when it doesn\'t fit in .lower.bss"
+    "-T msp430-tiny-ram.ld --data-region=either" "" "" {main-with-data-bss.s}
+    {{objdump -D main-bss-upper.d}} "either-to-upper-bss"}
+  {"Move \"either\" glob_const_array to .upper.rodata when it doesn\'t fit in .lower.rodata"
+    "-T msp430-tiny-rom.ld --code-region=either --data-region=either" "" "" {main-with-text-rodata.s}
+    {{objdump -D main-const-upper.d}} "either-to-upper-const"}
+
+  {"Move \"either\" main() to .upper.text when it doesn\'t fit in .lower.text, with -ffunction/data-sections"
+    "-T msp430-tiny-rom.ld --code-region=either --data-region=either" "" "" {main-with-text-rodata-unique-sec.s}
+    {{objdump -d main-text-upper.d}} "either-to-upper-text-unique-sec"}
+  {"Move \"either\" glob_var_array to .upper.data when it doesn\'t fit in .lower.data, with -ffunction/data-sections"
+    "-T msp430-tiny-ram.ld --data-region=either" "" "" {main-with-data-bss-unique-sec.s}
+    {{objdump -D main-var-upper.d}} "either-to-upper-data-unique-sec"}
+  {"Move \"either\" glob_bss_array to .upper.bss when it doesn\'t fit in .lower.bss, with -ffunction/data-sections"
+    "-T msp430-tiny-ram.ld --data-region=either" "" "" {main-with-data-bss-unique-sec.s}
+    {{objdump -D main-bss-upper.d}} "either-to-upper-bss-unique-sec"}
+  {"Move \"either\" glob_const_array to .upper.rodata when it doesn\'t fit in .lower.rodata, with -ffunction/data-sections"
+    "-T msp430-tiny-rom.ld --code-region=either --data-region=either" "" "" {main-with-text-rodata-unique-sec.s}
+    {{objdump -D main-const-upper.d}} "either-to-upper-const-unique-sec"}
+}
+
 run_ld_link_tests $msp430regionprefixtests
 run_ld_link_tests $msp430regionprefixuniquesectiontests
+run_ld_link_tests $msp430eithershuffletests
diff --git a/ld/testsuite/ld-msp430-elf/msp430-tiny-ram.ld b/ld/testsuite/ld-msp430-elf/msp430-tiny-ram.ld
new file mode 100644
index 0000000..e2e6f2f
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/msp430-tiny-ram.ld
@@ -0,0 +1,49 @@
+/* Script for ld testsuite */
+OUTPUT_ARCH(msp430)
+ENTRY(_start)
+
+MEMORY
+{
+  RAM : ORIGIN = 0x0, LENGTH = 0x2
+  ROM : ORIGIN = 0x2, LENGTH = 0x1fe
+  HIFRAM : ORIGIN = 0x200, LENGTH = 0x1000
+}
+
+SECTIONS
+{
+  .text :
+  {
+    PROVIDE (_start = .);
+    . = ALIGN(2);
+    *(.text .stub .text.* .gnu.linkonce.t.* .text:*)
+  } > ROM
+
+  .rodata :
+  {
+    *(.upper.rodata.* .rodata)
+  } > ROM
+
+  .data :
+  {
+    . = ALIGN(2);
+    *(.data.* .data)
+  } > RAM AT> ROM
+
+  .bss :
+  {
+    . = ALIGN(2);
+    *(.bss.* .bss)
+  } > RAM
+
+  .upper.data :
+  {
+    . = ALIGN(2);
+    *(.upper.data.* .upper.data)
+  } > HIFRAM AT> ROM
+
+  .upper.bss :
+  {
+    . = ALIGN(2);
+    *(.upper.bss.* .upper.bss)
+  } > HIFRAM
+}
diff --git a/ld/testsuite/ld-msp430-elf/msp430-tiny-rom.ld b/ld/testsuite/ld-msp430-elf/msp430-tiny-rom.ld
new file mode 100644
index 0000000..3e26379
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/msp430-tiny-rom.ld
@@ -0,0 +1,48 @@
+/* Script for ld testsuite */
+OUTPUT_ARCH(msp430)
+ENTRY(_start)
+
+MEMORY
+{
+  ROM : ORIGIN = 0x0, LENGTH = 0x2
+  RAM : ORIGIN = 0x2, LENGTH = 0x1fe
+  HIROM : ORIGIN = 0x200, LENGTH = 0x1000
+}
+
+SECTIONS
+{
+  .text :
+  {
+    PROVIDE (_start = .);
+    . = ALIGN(2);
+    *(.text .stub .text.* .gnu.linkonce.t.* .text:*)
+  } > ROM
+
+  .rodata :
+  {
+    *(.rodata.* .rodata)
+  } > ROM
+
+  .data :
+  {
+    . = ALIGN(2);
+    *(.data.* .data)
+  } > RAM AT> ROM
+
+  .bss :
+  {
+    . = ALIGN(2);
+    *(.bss.* .bss)
+  } > RAM
+
+  .upper.text :
+  {
+    . = ALIGN(2);
+    *(.upper.text.* .upper.text)
+  } > HIROM
+
+  .upper.rodata :
+  {
+    *(.upper.rodata.* .upper.rodata)
+  } > HIROM
+}
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 3/4][MSP430] Remove .either placement code from place_orphan
  2017-07-19 17:22   ` [PATCH 2/4][MSP430] Change .either section placement to be performed after allocation Jozef Lawrynowicz
@ 2017-07-19 17:30     ` Jozef Lawrynowicz
  2017-07-19 17:35       ` [PATCH 4/4][MSP430] Define symbols to initialise high data and high bss when the upper data region could be used Jozef Lawrynowicz
  0 siblings, 1 reply; 8+ messages in thread
From: Jozef Lawrynowicz @ 2017-07-19 17:30 UTC (permalink / raw)
  To: binutils; +Cc: Nick Clifton

[-- Attachment #1: Type: text/plain, Size: 362 bytes --]

This patch removes the existing ".either" placement functionality from
place_orphan. With the addition of the new placement functionality in
Patch 2, this existing code is no longer necessary. place_orphan now
places all orphaned .either sections in the lower memory region.

The tests added in patch 2 pass when built with todays GCC trunk and
binutils master.

[-- Attachment #2: 0003-MSP430-Remove-.either-splitting-code-from-place_orph.patch --]
[-- Type: text/plain, Size: 3093 bytes --]

From 5eb4de4ca70d8488741f43561cb8724db5aceba5 Mon Sep 17 00:00:00 2001
From: Jozef Lawrynowicz <jozef.l@somniumtech.com>
Date: Mon, 10 Jul 2017 16:42:17 +0000
Subject: [PATCH 3/4] MSP430: Remove .either placement code from place_orphan

---
 ld/emultempl/msp430.em | 56 ++++++++++++++------------------------------------
 1 file changed, 15 insertions(+), 41 deletions(-)

diff --git a/ld/emultempl/msp430.em b/ld/emultempl/msp430.em
index 15c60a7..0b3b12a 100644
--- a/ld/emultempl/msp430.em
+++ b/ld/emultempl/msp430.em
@@ -220,7 +220,6 @@ gld${EMULATION_NAME}_place_orphan (asection * s,
   char * buf = NULL;
   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;
@@ -257,57 +256,32 @@ gld${EMULATION_NAME}_place_orphan (asection * s,
   /* 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)
+  if (lower == NULL && upper == NULL)
     {
-      os = upper;
-      if (upper == NULL)
-        {
-          einfo ("%P: error: no section named %s or %s in linker script\n", lower_name, upper_name);
-	  goto end;
-	}
+      einfo ("%P: error: no section named %s or %s in linker script\n",
+	     lower_name, upper_name);
+      goto end;
     }
-  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
+  else if (lower == NULL)
     {
-      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;
+      lower = lang_output_section_find (name);
+      if (lower == NULL)
+	{
+	  einfo ("%P: error: no section named %s in linker script\n", name);
+	  goto end;
+	}
     }
 
-  lang_add_section (& os->children, s, NULL, os);
+  /* Always place orphaned sections in lower. Optimal placement of either
+   * sections is performed later, once section sizes have been finalized.  */
+  lang_add_section (& lower->children, s, NULL, lower);
  end:
   free (upper_name);
   free (lower_name);
   if (buf)
     free (buf);
-  return os;
+  return lower;
 }
 EOF
 fi
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 4/4][MSP430] Define symbols to initialise high data and high bss when the upper data region could be used
  2017-07-19 17:30     ` [PATCH 3/4][MSP430] Remove .either placement code from place_orphan Jozef Lawrynowicz
@ 2017-07-19 17:35       ` Jozef Lawrynowicz
  0 siblings, 0 replies; 8+ messages in thread
From: Jozef Lawrynowicz @ 2017-07-19 17:35 UTC (permalink / raw)
  To: binutils; +Cc: Nick Clifton

[-- Attachment #1: Type: text/plain, Size: 540 bytes --]

This patch adds functionality to gas to define symbols for initialising
high data and high bss, when -mdata-region is used with the "either" or
"upper" parameters. Since the linker can now create upper and either
sections even when none exist at assembly time, the current behaviour of
only defining these symbols when .upper or .either sections exist was
not enough. The parameter passed to GCC for -mdata-region is propagated
to the assembler using this option.

The added tests pass when built with todays GCC trunk and binutils
master.

[-- Attachment #2: 0004-MSP430-Define-symbols-to-initialise-high-data-and-hi.patch --]
[-- Type: text/plain, Size: 5524 bytes --]

From b456fe2652d5b79dd2923206a0c96f23b35d44de Mon Sep 17 00:00:00 2001
From: Jozef Lawrynowicz <jozef.l@somniumtech.com>
Date: Mon, 10 Jul 2017 16:53:05 +0000
Subject: [PATCH 4/4] MSP430: Define symbols to initialise high data and high
 bss when the upper data region could be used

---
 gas/config/tc-msp430.c                       | 23 ++++++++++++++++++++---
 gas/doc/c-msp430.texi                        | 13 +++++++++++++
 gas/testsuite/gas/msp430/high-data-bss-sym.d |  6 ++++++
 gas/testsuite/gas/msp430/high-data-bss-sym.s | 19 +++++++++++++++++++
 gas/testsuite/gas/msp430/msp430.exp          |  2 ++
 5 files changed, 60 insertions(+), 3 deletions(-)
 create mode 100644 gas/testsuite/gas/msp430/high-data-bss-sym.d
 create mode 100644 gas/testsuite/gas/msp430/high-data-bss-sym.s

diff --git a/gas/config/tc-msp430.c b/gas/config/tc-msp430.c
index 91e0a73..62a34ed 100644
--- a/gas/config/tc-msp430.c
+++ b/gas/config/tc-msp430.c
@@ -676,6 +676,8 @@ static bfd_boolean warn_interrupt_nops = TRUE;
 #define OPTION_MCPU 'c'
 #define OPTION_MOVE_DATA 'd'
 static bfd_boolean move_data = FALSE;
+#define OPTION_DATA_REGION 'r'
+static bfd_boolean upper_data_region_in_use = FALSE;
 
 enum
 {
@@ -1448,6 +1450,12 @@ md_parse_option (int c, const char * arg)
     case OPTION_MOVE_DATA:
       move_data = TRUE;
       return 1;
+
+    case OPTION_DATA_REGION:
+      if (strcmp (arg, "upper") == 0
+	  || strcmp (arg, "either") == 0)
+	upper_data_region_in_use = TRUE;
+      return 1;
     }
 
   return 0;
@@ -1478,14 +1486,19 @@ msp430_make_init_symbols (const char * name)
 
   /* Note - data assigned to the .either.data section may end up being
      placed in the .upper.data section if the .lower.data section is
-     full.  Hence the need to define the crt0 symbol.  */
+     full.  Hence the need to define the crt0 symbol.
+     The linker may create upper or either data sections, even when none exist
+     at the moment, so use the value of the data-region flag to determine if
+     the symbol is needed.  */
   if (strncmp (name, ".either.data", 12) == 0
-      || strncmp (name, ".upper.data", 11) == 0)
+      || strncmp (name, ".upper.data", 11) == 0
+      || upper_data_region_in_use)
     (void) symbol_find_or_make ("__crt0_move_highdata");
 
   /* See note about .either.data above.  */
   if (strncmp (name, ".upper.bss", 10) == 0
-      || strncmp (name, ".either.bss", 11) == 0)
+      || strncmp (name, ".either.bss", 11) == 0
+      || upper_data_region_in_use)
     (void) symbol_find_or_make ("__crt0_init_highbss");
 }
 
@@ -1570,6 +1583,7 @@ struct option md_longopts[] =
   {"mY", no_argument, NULL, OPTION_NO_WARN_INTR_NOPS},
   {"my", no_argument, NULL, OPTION_WARN_INTR_NOPS},
   {"md", no_argument, NULL, OPTION_MOVE_DATA},
+  {"mdata-region", required_argument, NULL, OPTION_DATA_REGION},
   {NULL, no_argument, NULL, 0}
 };
 
@@ -1601,6 +1615,9 @@ md_show_usage (FILE * stream)
 	   _("  -my - warn about missing NOPs after changing interrupts (default)\n"));
   fprintf (stream,
 	   _("  -md - Force copying of data from ROM to RAM at startup\n"));
+  fprintf (stream,
+	   _("  -mdata-region={none|lower|upper|either} - select region data will be\n"
+	     "    placed in.\n"));
 }
 
 symbolS *
diff --git a/gas/doc/c-msp430.texi b/gas/doc/c-msp430.texi
index eb0e757..76399a6 100644
--- a/gas/doc/c-msp430.texi
+++ b/gas/doc/c-msp430.texi
@@ -107,6 +107,19 @@ disables warnings about missing NOP instructions.
 mark the object file as one that requires data to copied from ROM to
 RAM at execution startup.  Disabled by default.
 
+@item -mdata-region=@var{region}
+Select the region data will be placed in.
+Region placement is performed by the compiler and linker. The only effect this
+option will have on the assembler is that if @var{upper} or @var{either} is
+selected, then the symbols to initialise high data and bss will be defined.
+Valid @var{region} values are:
+@table @code
+@item none
+@item lower
+@item upper
+@item either
+@end table
+
 @end table
 
 @node MSP430 Syntax
diff --git a/gas/testsuite/gas/msp430/high-data-bss-sym.d b/gas/testsuite/gas/msp430/high-data-bss-sym.d
new file mode 100644
index 0000000..1c8d95b
--- /dev/null
+++ b/gas/testsuite/gas/msp430/high-data-bss-sym.d
@@ -0,0 +1,6 @@
+#objdump: -t
+#name: Check symbols to initialise high data and high bss have been defined
+#...
+.*__crt0_move_highdata.*
+.*__crt0_init_highbss.*
+#pass
diff --git a/gas/testsuite/gas/msp430/high-data-bss-sym.s b/gas/testsuite/gas/msp430/high-data-bss-sym.s
new file mode 100644
index 0000000..1e6bf72
--- /dev/null
+++ b/gas/testsuite/gas/msp430/high-data-bss-sym.s
@@ -0,0 +1,19 @@
+	.file	"main.c"
+.text
+	.balign 2
+	.global	main
+	.type	main, @function
+main:
+; start of function
+; framesize_regs:     0
+; framesize_locals:   0
+; framesize_outgoing: 0
+; framesize:          0
+; elim ap -> fp       2
+; elim fp -> sp       0
+; saved regs:(none)
+	; start of prologue
+	; end of prologue
+.L2:
+	BR	#.L2
+	.size	main, .-main
diff --git a/gas/testsuite/gas/msp430/msp430.exp b/gas/testsuite/gas/msp430/msp430.exp
index b83e1ac..0dfb271 100644
--- a/gas/testsuite/gas/msp430/msp430.exp
+++ b/gas/testsuite/gas/msp430/msp430.exp
@@ -24,4 +24,6 @@ if [expr [istarget "msp430-*-*"]]  then {
     run_dump_test "bad"
     run_dump_test "errata_warns"
     run_dump_test "errata_fixes"
+    run_dump_test "high-data-bss-sym" { { as "-mdata-region=upper" } }
+    run_dump_test "high-data-bss-sym" { { as "-mdata-region=either" } }
 }
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 0/4][MSP430] Improve behaviour of ".either" section placement
  2017-07-19 17:08 [PATCH 0/4][MSP430] Improve behaviour of ".either" section placement Jozef Lawrynowicz
  2017-07-19 17:16 ` [PATCH 1/4][MSP430] Add feature to add lower/either/upper prefixes to section names Jozef Lawrynowicz
@ 2017-07-20 12:36 ` Nick Clifton
  2017-08-24 17:17 ` Jozef Lawrynowicz
  2 siblings, 0 replies; 8+ messages in thread
From: Nick Clifton @ 2017-07-20 12:36 UTC (permalink / raw)
  To: binutils

Hi Jozef,

> GCC for the MSP430 target has a feature that allows the user to specify
> which memory region to place code and/or data in, using the -mcode-
> region and -mdata-region options.
> MSP430 devices with a high memory region support this placement of
> code/data by defining ".upper" and ".lower" output sections in linker
> scripts.
> The parameters that can be passed to -mcode/data-region are "none",
> "upper", "lower", "either". The use of the "either" option requires some
> work to be done by the linker, to place ".either" code and data sections
> in either the upper or lower regions to prevent memory region overflow,
> if possible. The following patches improve and fix some of the existing
> behaviour of this ".either" placement functionality.

Thanks very much for doing this.  It is really nice to see someone interested
in developing the MSP430 toolchain.

Rather than comment on each patch individually I have some general comments
that apply to all of the patches:

  * Please could you provide ChangeLog entries for each of the patches.

  * Please move variable declarations to the start of their containing
    blocks.  I know that modern C compilers allow them anywhere in the
    block, but we still need to support some older compilers that do not.

  * Please used ATTRIBUTE_UNUSED instead of __attribute__((unused)).

  * Please format comments according to the GNU coding standard.  
    Specifically a comment like this:
 
      /* This is a
       * multiline comment.
       */

    Should be formatted as:

     /* This is a
        multiline comment.  */

Also, there is one specific comments on the behaviour of patch series:

  * It seems to me that when performing the last UPPER to LOWER move it
    would be better to move any section that will fit into LOWER, even
    if UPPER is *not* overflowing.  This assumes that LOWER memory is faster
    and hence it is preferable to use as much of it as possible.

But all in all, I think that the patch is great and I am looking forward to 
applying it.

Cheers
  Nick

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 0/4][MSP430] Improve behaviour of ".either" section placement
  2017-07-19 17:08 [PATCH 0/4][MSP430] Improve behaviour of ".either" section placement Jozef Lawrynowicz
  2017-07-19 17:16 ` [PATCH 1/4][MSP430] Add feature to add lower/either/upper prefixes to section names Jozef Lawrynowicz
  2017-07-20 12:36 ` [PATCH 0/4][MSP430] Improve behaviour of ".either" section placement Nick Clifton
@ 2017-08-24 17:17 ` Jozef Lawrynowicz
  2017-08-29 16:21   ` Nick Clifton
  2 siblings, 1 reply; 8+ messages in thread
From: Jozef Lawrynowicz @ 2017-08-24 17:17 UTC (permalink / raw)
  To: binutils; +Cc: Nick Clifton

[-- Attachment #1: Type: text/plain, Size: 1692 bytes --]

On 20/07/2017 13:36, Nick Clifton wrote:
 > Rather than comment on each patch individually I have some general
comments
 > that apply to all of the patches:
 >
 >   * Please could you provide ChangeLog entries for each of the patches.
 >
 >   * Please move variable declarations to the start of their containing
 >     blocks.  I know that modern C compilers allow them anywhere in the
 >     block, but we still need to support some older compilers that do not.
 >
 >   * Please used ATTRIBUTE_UNUSED instead of __attribute__((unused)).
 >
 >   * Please format comments according to the GNU coding standard.
 >     Specifically a comment like this:
 >
 >       /* This is a
 >        * multiline comment.
 >        */
 >
 >     Should be formatted as:
 >
 >      /* This is a
 >         multiline comment.  */
 >
 > Also, there is one specific comments on the behaviour of patch series:
 >
 >   * It seems to me that when performing the last UPPER to LOWER move it
 >     would be better to move any section that will fit into LOWER, even
 >     if UPPER is *not* overflowing.  This assumes that LOWER memory is 
faster
 >     and hence it is preferable to use as much of it as possible.

Thanks for the reply Nick, and apologies for the delay in replying. I've
updated the patches with your advice. It was a good point about filling
the lower region as much as possible, even when upper is not
overflowing, so have made that change as well.

The updated patches are attached.
I will be posting an accompanying patch to gcc-patches which propagates
the -mcode/data-region options to the assembler and linker, which is
necessary to actually make this new functionality useful.

Thanks,
Jozef

[-- Attachment #2: 0001-MSP430-Add-feature-to-add-lower-either-upper-prefixe.patch --]
[-- Type: text/plain, Size: 32115 bytes --]

From ea69037333ae703e8b557b74c2b324354b8b775b Mon Sep 17 00:00:00 2001
From: Jozef Lawrynowicz <jozef.l@somniumtech.com>
Date: Mon, 10 Jul 2017 13:14:53 +0000
Subject: [PATCH 1/4] MSP430: Add feature to add lower/either/upper prefixes to
 section names

2017-08-XX	Jozef Lawrynowicz	<jozef.l@somniumtech.com>
	
	* ld/emultempl/msp430.em (change_output_section): New function.
	(move_prefixed_section): New function.
	(add_region_prefix): New function.
	(msp430_elf_after_open): New function.
	(gld${EMULATION_NAME}_add_options): Implement.
	(gld${EMULATION_NAME}_list_options): Implement.
	(gld${EMULATION_NAME}_handle_option): Implement.
	* ld/ld.texinfo: Document new options.
	
ld/testsuite
2017-08-XX	Jozef Lawrynowicz	<jozef.l@somniumtech.com>

	* ld-msp430-elf/main-bss-lower.d: New.
	* ld-msp430-elf/main-bss-upper.d: New.
	* ld-msp430-elf/main-const-lower.d: New.
	* ld-msp430-elf/main-const-upper.d: New.
	* ld-msp430-elf/main-text-lower.d: New.
	* ld-msp430-elf/main-text-upper.d: New.
	* ld-msp430-elf/main-var-lower.d: New.
	* ld-msp430-elf/main-var-upper.d: New.
	* ld-msp430-elf/main-with-data-bss-unique-sec.s: New.
	* ld-msp430-elf/main-with-data-bss.s: New.
	* ld-msp430-elf/main-with-text-rodata-unique-sec.s: New.
	* ld-msp430-elf/main-with-text-rodata.s: New.
	* ld-msp430-elf/msp430-elf.exp: New.
	* ld-msp430-elf/msp430-no-lower.ld: New.
	* ld-msp430-elf/msp430.ld: New.
---
 ld/emultempl/msp430.em                             | 277 ++++++++++++++++++++-
 ld/ld.texinfo                                      |  23 ++
 ld/testsuite/ld-msp430-elf/main-bss-lower.d        |   3 +
 ld/testsuite/ld-msp430-elf/main-bss-upper.d        |   3 +
 ld/testsuite/ld-msp430-elf/main-const-lower.d      |   3 +
 ld/testsuite/ld-msp430-elf/main-const-upper.d      |   3 +
 ld/testsuite/ld-msp430-elf/main-text-lower.d       |   3 +
 ld/testsuite/ld-msp430-elf/main-text-upper.d       |   6 +
 ld/testsuite/ld-msp430-elf/main-var-lower.d        |   3 +
 ld/testsuite/ld-msp430-elf/main-var-upper.d        |   3 +
 .../ld-msp430-elf/main-with-data-bss-unique-sec.s  |  78 ++++++
 ld/testsuite/ld-msp430-elf/main-with-data-bss.s    |  74 ++++++
 .../main-with-text-rodata-unique-sec.s             |  59 +++++
 ld/testsuite/ld-msp430-elf/main-with-text-rodata.s |  59 +++++
 ld/testsuite/ld-msp430-elf/msp430-elf.exp          | 112 +++++++++
 ld/testsuite/ld-msp430-elf/msp430-no-lower.ld      |  54 ++++
 ld/testsuite/ld-msp430-elf/msp430.ld               |  78 ++++++
 17 files changed, 837 insertions(+), 4 deletions(-)
 create mode 100644 ld/testsuite/ld-msp430-elf/main-bss-lower.d
 create mode 100644 ld/testsuite/ld-msp430-elf/main-bss-upper.d
 create mode 100644 ld/testsuite/ld-msp430-elf/main-const-lower.d
 create mode 100644 ld/testsuite/ld-msp430-elf/main-const-upper.d
 create mode 100644 ld/testsuite/ld-msp430-elf/main-text-lower.d
 create mode 100644 ld/testsuite/ld-msp430-elf/main-text-upper.d
 create mode 100644 ld/testsuite/ld-msp430-elf/main-var-lower.d
 create mode 100644 ld/testsuite/ld-msp430-elf/main-var-upper.d
 create mode 100644 ld/testsuite/ld-msp430-elf/main-with-data-bss-unique-sec.s
 create mode 100644 ld/testsuite/ld-msp430-elf/main-with-data-bss.s
 create mode 100644 ld/testsuite/ld-msp430-elf/main-with-text-rodata-unique-sec.s
 create mode 100644 ld/testsuite/ld-msp430-elf/main-with-text-rodata.s
 create mode 100644 ld/testsuite/ld-msp430-elf/msp430-elf.exp
 create mode 100644 ld/testsuite/ld-msp430-elf/msp430-no-lower.ld
 create mode 100644 ld/testsuite/ld-msp430-elf/msp430.ld

diff --git a/ld/emultempl/msp430.em b/ld/emultempl/msp430.em
index 949fea0..2f3724d 100644
--- a/ld/emultempl/msp430.em
+++ b/ld/emultempl/msp430.em
@@ -32,6 +32,7 @@ fragment <<EOF
 #include "bfdlink.h"
 
 #include "ld.h"
+#include "getopt.h"
 #include "ldmain.h"
 #include "ldmisc.h"
 #include "ldexp.h"
@@ -39,6 +40,21 @@ fragment <<EOF
 #include "ldfile.h"
 #include "ldemul.h"
 #include "libiberty.h"
+#include <ldgram.h>
+
+enum regions
+{
+  REGION_NONE = 0,
+  REGION_LOWER,
+  REGION_UPPER,
+  REGION_EITHER = 3,
+};
+
+static int data_region = REGION_NONE;
+static int code_region = REGION_NONE;
+static bfd_boolean disable_sec_transformation = FALSE;
+
+#define MAX_PREFIX_LENGTH 7
 
 EOF
 
@@ -268,13 +284,266 @@ fi
 
 fragment <<EOF
 
+static bfd_boolean
+change_output_section (lang_statement_union_type ** head,
+		       asection *s,
+		       lang_output_section_statement_type * new_output_section)
+{
+  asection *is;
+  lang_statement_union_type * prev = NULL;
+  lang_statement_union_type * curr;
+  curr = *head;
+  while (curr != NULL)
+    {
+      switch (curr->header.type)
+	{
+	case lang_input_section_enum:
+	  is = curr->input_section.section;
+	  if (is == s)
+	    {
+	      s->output_section = NULL;
+	      lang_add_section (& (new_output_section->children), s, NULL,
+				new_output_section);
+	      /* Remove the section from the old output section.  */
+	      if (prev == NULL)
+		*head = curr->header.next;
+	      else
+		prev->header.next = curr->header.next;
+	      return TRUE;
+	    }
+	  break;
+	case lang_wild_statement_enum:
+	  if (change_output_section (&(curr->wild_statement.children.head),
+				     s, new_output_section))
+	    return TRUE;
+	  break;
+	default:
+	  break;
+	}
+      prev = curr;
+      curr = curr->header.next;
+    }
+  return FALSE;
+}
+
+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)
+{
+  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;
+  int region = REGION_NONE;
+  if (strncmp (curr_name, ".text", 5) == 0)
+    {
+      region = code_region;
+      base_name = concat (".text", NULL);
+    }
+  else if (strncmp (curr_name, ".data", 5) == 0)
+    {
+      region = data_region;
+      base_name = concat (".data", NULL);
+    }
+  else if (strncmp (curr_name, ".bss", 4) == 0)
+    {
+      region = data_region;
+      base_name = concat (".bss", NULL);
+    }
+  else if (strncmp (curr_name, ".rodata", 7) == 0)
+    {
+      region = data_region;
+      base_name = concat (".rodata", NULL);
+    }
+  else
+    return;
+
+  switch (region)
+    {
+    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);
+      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);
+      break;
+    case REGION_EITHER:
+      s->name = concat (".either", curr_name, NULL);
+      break;
+    default:
+      /* Unreachable.  */
+      FAIL ();
+      break;
+    }
+  free (base_name);
+  if (new_input_sec_name)
+    {
+      free (new_input_sec_name);
+      free (new_output_sec_name);
+    }
+}
+
+static void
+msp430_elf_after_open (void)
+{
+  bfd *abfd;
+  gld${EMULATION_NAME}_after_open ();
+  /* If neither --code-region or --data-region have been passed, do not
+     transform sections names.  */
+  if ((code_region == REGION_NONE && data_region == REGION_NONE)
+      || disable_sec_transformation)
+    return;
+  for (abfd = link_info.input_bfds; abfd != NULL; abfd = abfd->link.next)
+    {
+      bfd_map_over_sections (abfd, add_region_prefix, NULL);
+    }
+}
+
+#define OPTION_CODE_REGION		321
+#define OPTION_DATA_REGION		(OPTION_CODE_REGION + 1)
+#define OPTION_DISABLE_TRANS		(OPTION_CODE_REGION + 2)
+
+static void
+gld${EMULATION_NAME}_add_options
+  (int ns, char **shortopts, int nl, struct option **longopts,
+   int nrl ATTRIBUTE_UNUSED, struct option **really_longopts ATTRIBUTE_UNUSED)
+{
+  static const char xtra_short[] = { };
+
+  static const struct option xtra_long[] = {
+	{ "code-region", required_argument, NULL, OPTION_CODE_REGION },
+	{ "data-region", required_argument, NULL, OPTION_DATA_REGION },
+	{ "disable-sec-transformation", no_argument, NULL,
+	  OPTION_DISABLE_TRANS },
+	{ NULL, no_argument, NULL, 0 }
+  };
+
+  *shortopts = (char *) xrealloc (*shortopts, ns + sizeof (xtra_short));
+  memcpy (*shortopts + ns, &xtra_short, sizeof (xtra_short));
+  *longopts = (struct option *)
+    xrealloc (*longopts, nl * sizeof (struct option) + sizeof (xtra_long));
+  memcpy (*longopts + nl, &xtra_long, sizeof (xtra_long));
+}
+
+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"));
+}
+
+static bfd_boolean
+gld${EMULATION_NAME}_handle_option (int optc)
+{
+  switch (optc)
+    {
+    case OPTION_CODE_REGION:
+      if (strcmp (optarg, "upper") == 0)
+	code_region = REGION_UPPER;
+      else if (strcmp (optarg, "lower") == 0)
+	code_region = REGION_LOWER;
+      else if (strcmp (optarg, "either") == 0)
+	code_region = REGION_EITHER;
+      else if (strcmp (optarg, "none") == 0)
+	code_region = REGION_NONE;
+      else if (strlen (optarg) == 0)
+	{
+	  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);
+	  return FALSE;
+	}
+      break;
+
+    case OPTION_DATA_REGION:
+      if (strcmp (optarg, "upper") == 0)
+	data_region = REGION_UPPER;
+      else if (strcmp (optarg, "lower") == 0)
+	data_region = REGION_LOWER;
+      else if (strcmp (optarg, "either") == 0)
+	data_region = REGION_EITHER;
+      else if (strcmp (optarg, "none") == 0)
+	data_region = REGION_NONE;
+      else if (strlen (optarg) == 0)
+	{
+	  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);
+	  return FALSE;
+	}
+      break;
+
+    case OPTION_DISABLE_TRANS:
+      disable_sec_transformation = TRUE;
+      break;
+
+    default:
+      return FALSE;
+    }
+  return TRUE;
+}
+
 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},
+  msp430_elf_after_open,
   ${LDEMUL_AFTER_ALLOCATION-after_allocation_default},
   ${LDEMUL_SET_OUTPUT_ARCH-set_output_arch_default},
   ${LDEMUL_CHOOSE_TARGET-ldemul_default_target},
@@ -288,10 +557,10 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   ${LDEMUL_PLACE_ORPHAN-gld${EMULATION_NAME}_place_orphan},
   ${LDEMUL_SET_SYMBOLS-NULL},
   ${LDEMUL_PARSE_ARGS-NULL},
-  ${LDEMUL_ADD_OPTIONS-NULL},
-  ${LDEMUL_HANDLE_OPTION-NULL},
+  gld${EMULATION_NAME}_add_options,
+  gld${EMULATION_NAME}_handle_option,
   ${LDEMUL_UNRECOGNIZED_FILE-NULL},
-  ${LDEMUL_LIST_OPTIONS-NULL},
+  gld${EMULATION_NAME}_list_options,
   ${LDEMUL_RECOGNIZED_FILE-NULL},
   ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL},
   ${LDEMUL_NEW_VERS_PATTERN-NULL},
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index bbfa9fd..ba19cd7 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -7260,6 +7260,29 @@ Denotes a portion of RAM located above @samp{.bss} section.
 The last two sections are used by gcc.
 @end table
 
+@table @option
+@cindex MSP430 Options
+@kindex --code-region
+@item --code-region=[either,lower,upper,none]
+This will transform .text* sections to [either,lower,upper].text* sections. The
+argument passed to GCC for -mcode-region is propagated to the linker
+using this option.
+
+@kindex --data-region
+@item --data-region=[either,lower,upper,none]
+This will transform .data*, .bss* and .rodata* sections to
+[either,lower,upper].[data,bss,rodata]* sections. The argument passed to GCC
+for -mdata-region is propagated to the linker using this option.
+
+@kindex --disable-sec-transformation
+@item --disable-sec-transformation
+Prevent the transformation of sections as specified by the @code{--code-region}
+and @code{--data-region} options.
+This is useful if you are compiling and linking using a single call to the GCC
+wrapper, and want to compile the source files using -m[code,data]-region but
+not transform the sections for prebuilt libraries and objects.
+@end table
+
 @ifclear GENERIC
 @lowersections
 @end ifclear
diff --git a/ld/testsuite/ld-msp430-elf/main-bss-lower.d b/ld/testsuite/ld-msp430-elf/main-bss-lower.d
new file mode 100644
index 0000000..6007420
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-bss-lower.d
@@ -0,0 +1,3 @@
+#...
+Disassembly of section .lower.bss:
+#pass
diff --git a/ld/testsuite/ld-msp430-elf/main-bss-upper.d b/ld/testsuite/ld-msp430-elf/main-bss-upper.d
new file mode 100644
index 0000000..2f6376a7
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-bss-upper.d
@@ -0,0 +1,3 @@
+#...
+Disassembly of section .upper.bss:
+#pass
diff --git a/ld/testsuite/ld-msp430-elf/main-const-lower.d b/ld/testsuite/ld-msp430-elf/main-const-lower.d
new file mode 100644
index 0000000..8549961
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-const-lower.d
@@ -0,0 +1,3 @@
+#...
+Disassembly of section .lower.rodata:
+#pass
diff --git a/ld/testsuite/ld-msp430-elf/main-const-upper.d b/ld/testsuite/ld-msp430-elf/main-const-upper.d
new file mode 100644
index 0000000..c84d649
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-const-upper.d
@@ -0,0 +1,3 @@
+#...
+Disassembly of section .upper.rodata:
+#pass
diff --git a/ld/testsuite/ld-msp430-elf/main-text-lower.d b/ld/testsuite/ld-msp430-elf/main-text-lower.d
new file mode 100644
index 0000000..446a305
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-text-lower.d
@@ -0,0 +1,3 @@
+#...
+Disassembly of section .lower.text:
+#pass
diff --git a/ld/testsuite/ld-msp430-elf/main-text-upper.d b/ld/testsuite/ld-msp430-elf/main-text-upper.d
new file mode 100644
index 0000000..f7ae6af
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-text-upper.d
@@ -0,0 +1,6 @@
+
+.*:     file format.*msp430.*
+
+
+Disassembly of section .upper.text:
+#...
diff --git a/ld/testsuite/ld-msp430-elf/main-var-lower.d b/ld/testsuite/ld-msp430-elf/main-var-lower.d
new file mode 100644
index 0000000..f520cf5
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-var-lower.d
@@ -0,0 +1,3 @@
+#...
+Disassembly of section .lower.data:
+#pass
diff --git a/ld/testsuite/ld-msp430-elf/main-var-upper.d b/ld/testsuite/ld-msp430-elf/main-var-upper.d
new file mode 100644
index 0000000..fc3d712
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-var-upper.d
@@ -0,0 +1,3 @@
+#...
+Disassembly of section .upper.data:
+#pass
diff --git a/ld/testsuite/ld-msp430-elf/main-with-data-bss-unique-sec.s b/ld/testsuite/ld-msp430-elf/main-with-data-bss-unique-sec.s
new file mode 100644
index 0000000..7774804
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-with-data-bss-unique-sec.s
@@ -0,0 +1,78 @@
+	.file	"main-with-data-bss.c"
+	.global	glob_var_array
+	.section	.data.glob_var_array,"aw",@progbits
+	.balign 2
+	.type	glob_var_array, @object
+	.size	glob_var_array, 20
+glob_var_array:
+	.short	0
+	.short	1
+	.short	2
+	.short	3
+	.short	4
+	.short	5
+	.short	6
+	.short	7
+	.short	8
+	.short	9
+	.section	.bss.glob_bss_array,"aw",@nobits
+	.balign 2
+	.type	glob_bss_array, @object
+	.size	glob_bss_array, 20
+glob_bss_array:
+	.zero	20
+	.section	.text.main,"ax",@progbits
+	.balign 2
+	.global	main
+	.type	main, @function
+main:
+; start of function
+; framesize_regs:     0
+; framesize_locals:   2
+; framesize_outgoing: 0
+; framesize:          2
+; elim ap -> fp       2
+; elim fp -> sp       2
+; saved regs:(none)
+	; start of prologue
+	SUB.W	#2, R1
+	; end of prologue
+	MOV.W	#0, @R1
+	BR	#.L2
+.L7:
+	MOV.W	@R1, R12
+	ADD.W	R12, R12
+	ADD.W	#glob_var_array, R12
+	MOV.W	@R12, R13
+	MOV.W	R13, R12
+	ADD.W	R12, R12
+	ADD.W	R13, R12
+	rpt	#2 { rlax.w	R12
+	SUB.W	R13, R12
+	CMP.W	#110, R12 { JNE	.L3
+.L4:
+	BR	#.L4
+.L3:
+	MOV.W	@R1, R12
+	ADD.W	R12, R12
+	ADD.W	#glob_bss_array, R12
+	MOV.W	@R12, R13
+	MOV.W	R13, R12
+	ADD.W	R12, R12
+	ADD.W	R13, R12
+	rpt	#2 { rlax.w	R12
+	SUB.W	R13, R12
+	CMP.W	#110, R12 { JNE	.L5
+.L6:
+	BR	#.L6
+.L5:
+	ADD.W	#1, @R1
+.L2:
+	MOV.B	#9, R12
+	CMP.W	@R1, R12 { JGE	.L7
+	MOV.B	#0, R12
+	; start of epilogue
+	.refsym	__crt0_call_exit
+	ADD.W	#2, R1
+	RET
+	.size	main, .-main
diff --git a/ld/testsuite/ld-msp430-elf/main-with-data-bss.s b/ld/testsuite/ld-msp430-elf/main-with-data-bss.s
new file mode 100644
index 0000000..a406b64
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-with-data-bss.s
@@ -0,0 +1,74 @@
+	.file	"main-with-data-bss.c"
+	.global	glob_var_array
+.data
+	.balign 2
+	.type	glob_var_array, @object
+	.size	glob_var_array, 20
+glob_var_array:
+	.short	0
+	.short	1
+	.short	2
+	.short	3
+	.short	4
+	.short	5
+	.short	6
+	.short	7
+	.short	8
+	.short	9
+	.local	glob_bss_array
+	.comm	glob_bss_array,20,2
+.text
+	.balign 2
+	.global	main
+	.type	main, @function
+main:
+; start of function
+; framesize_regs:     0
+; framesize_locals:   2
+; framesize_outgoing: 0
+; framesize:          2
+; elim ap -> fp       2
+; elim fp -> sp       2
+; saved regs:(none)
+	; start of prologue
+	SUB.W	#2, R1
+	; end of prologue
+	MOV.W	#0, @R1
+	BR	#.L2
+.L7:
+	MOV.W	@R1, R12
+	ADD.W	R12, R12
+	ADD.W	#glob_var_array, R12
+	MOV.W	@R12, R13
+	MOV.W	R13, R12
+	ADD.W	R12, R12
+	ADD.W	R13, R12
+	rpt	#2 { rlax.w	R12
+	SUB.W	R13, R12
+	CMP.W	#110, R12 { JNE	.L3
+.L4:
+	BR	#.L4
+.L3:
+	MOV.W	@R1, R12
+	ADD.W	R12, R12
+	ADD.W	#glob_bss_array, R12
+	MOV.W	@R12, R13
+	MOV.W	R13, R12
+	ADD.W	R12, R12
+	ADD.W	R13, R12
+	rpt	#2 { rlax.w	R12
+	SUB.W	R13, R12
+	CMP.W	#110, R12 { JNE	.L5
+.L6:
+	BR	#.L6
+.L5:
+	ADD.W	#1, @R1
+.L2:
+	MOV.B	#9, R12
+	CMP.W	@R1, R12 { JGE	.L7
+	MOV.B	#0, R12
+	; start of epilogue
+	.refsym	__crt0_call_exit
+	ADD.W	#2, R1
+	RET
+	.size	main, .-main
diff --git a/ld/testsuite/ld-msp430-elf/main-with-text-rodata-unique-sec.s b/ld/testsuite/ld-msp430-elf/main-with-text-rodata-unique-sec.s
new file mode 100644
index 0000000..398cf74
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-with-text-rodata-unique-sec.s
@@ -0,0 +1,59 @@
+	.file	"main-with-text-rodata.c"
+	.global	glob_const_array
+	.section	.rodata.glob_const_array,"a",@progbits
+	.balign 2
+	.type	glob_const_array, @object
+	.size	glob_const_array, 20
+glob_const_array:
+	.short	0
+	.short	1
+	.short	2
+	.short	3
+	.short	4
+	.short	5
+	.short	6
+	.short	7
+	.short	8
+	.short	9
+	.section	.text.main,"ax",@progbits
+	.balign 2
+	.global	main
+	.type	main, @function
+main:
+; start of function
+; framesize_regs:     0
+; framesize_locals:   2
+; framesize_outgoing: 0
+; framesize:          2
+; elim ap -> fp       2
+; elim fp -> sp       2
+; saved regs:(none)
+	; start of prologue
+	SUB.W	#2, R1
+	; end of prologue
+	MOV.W	#0, @R1
+	BR	#.L2
+.L5:
+	MOV.W	@R1, R12
+	ADD.W	R12, R12
+	ADD.W	#glob_const_array, R12
+	MOV.W	@R12, R13
+	MOV.W	R13, R12
+	ADD.W	R12, R12
+	ADD.W	R13, R12
+	rpt	#2 { rlax.w	R12
+	SUB.W	R13, R12
+	CMP.W	#110, R12 { JNE	.L3
+.L4:
+	BR	#.L4
+.L3:
+	ADD.W	#1, @R1
+.L2:
+	MOV.B	#9, R12
+	CMP.W	@R1, R12 { JGE	.L5
+	MOV.B	#0, R12
+	; start of epilogue
+	.refsym	__crt0_call_exit
+	ADD.W	#2, R1
+	RET
+	.size	main, .-main
diff --git a/ld/testsuite/ld-msp430-elf/main-with-text-rodata.s b/ld/testsuite/ld-msp430-elf/main-with-text-rodata.s
new file mode 100644
index 0000000..225b5d4
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/main-with-text-rodata.s
@@ -0,0 +1,59 @@
+	.file	"main-with-text-rodata.c"
+	.global	glob_const_array
+	.section	.rodata
+	.balign 2
+	.type	glob_const_array, @object
+	.size	glob_const_array, 20
+glob_const_array:
+	.short	0
+	.short	1
+	.short	2
+	.short	3
+	.short	4
+	.short	5
+	.short	6
+	.short	7
+	.short	8
+	.short	9
+.text
+	.balign 2
+	.global	main
+	.type	main, @function
+main:
+; start of function
+; framesize_regs:     0
+; framesize_locals:   2
+; framesize_outgoing: 0
+; framesize:          2
+; elim ap -> fp       2
+; elim fp -> sp       2
+; saved regs:(none)
+	; start of prologue
+	SUB.W	#2, R1
+	; end of prologue
+	MOV.W	#0, @R1
+	BR	#.L2
+.L5:
+	MOV.W	@R1, R12
+	ADD.W	R12, R12
+	ADD.W	#glob_const_array, R12
+	MOV.W	@R12, R13
+	MOV.W	R13, R12
+	ADD.W	R12, R12
+	ADD.W	R13, R12
+	rpt	#2 { rlax.w	R12
+	SUB.W	R13, R12
+	CMP.W	#110, R12 { JNE	.L3
+.L4:
+	BR	#.L4
+.L3:
+	ADD.W	#1, @R1
+.L2:
+	MOV.B	#9, R12
+	CMP.W	@R1, R12 { JGE	.L5
+	MOV.B	#0, R12
+	; start of epilogue
+	.refsym	__crt0_call_exit
+	ADD.W	#2, R1
+	RET
+	.size	main, .-main
diff --git a/ld/testsuite/ld-msp430-elf/msp430-elf.exp b/ld/testsuite/ld-msp430-elf/msp430-elf.exp
new file mode 100644
index 0000000..bed2ed8
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/msp430-elf.exp
@@ -0,0 +1,112 @@
+# Expect script for various MSP430 ELF tests.
+#   Copyright (C) 2002-2015 Free Software Foundation, Inc.
+#
+# 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.
+#
+
+if { ![istarget "msp430*elf*"] } {
+    return
+}
+
+# List contains test-items with 3 items followed by 2 lists and one more item:
+# 0:name 1:ld early options 2:ld late options 3:assembler options
+# 4:filenames of assembler files 5: action and options. 6: name of output file
+
+# Actions:
+# objdump: Apply objdump options on result.  Compare with regex (last arg).
+# nm: Apply nm options on result.  Compare with regex (last arg).
+# readelf: Apply readelf options on result.  Compare with regex (last arg).
+
+set msp430regionprefixtests {
+  {"Move main() to .upper.text" "-T msp430.ld --code-region=upper"
+    "" "" {main-with-text-rodata.s} {{objdump -d main-text-upper.d}} "main-upper"}
+  {"Move main() to .upper.text. No .lower.text in ld script" "-T msp430-no-lower.ld --code-region=upper"
+    "" "" {main-with-text-rodata.s} {{objdump -d main-text-upper.d}} "main-upper"}
+  {"Move main() to .lower.text" "-T msp430.ld --code-region=lower"
+    "" "" {main-with-text-rodata.s} {{objdump -d main-text-lower.d}} "main-lower"}
+  {"Move \"either\" main() to .lower.text" "-T msp430.ld --code-region=either"
+    "" "" {main-with-text-rodata.s} {{objdump -d main-text-lower.d}} "main-either"}
+
+  {"Move glob_var to .upper.data" "-T msp430.ld --data-region=upper"
+    "" "" {main-with-data-bss.s} {{objdump -D main-var-upper.d}} "main-var-upper"}
+  {"Move glob_var to .upper.data. No .lower.data in ld script" "-T msp430-no-lower.ld --data-region=upper"
+    "" "" {main-with-data-bss.s} {{objdump -D main-var-upper.d}} "main-var-upper"}
+  {"Move glob_var to .lower.data" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-data-bss.s} {{objdump -D main-var-lower.d}} "main-var-lower"}
+  {"Move \"either\" glob_var to .lower.data" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-data-bss.s} {{objdump -D main-var-lower.d}} "main-var-lower"}
+
+  {"Move glob_zero to .upper.bss" "-T msp430.ld --data-region=upper"
+    "" "" {main-with-data-bss.s} {{objdump -D main-bss-upper.d}} "main-bss-upper"}
+  {"Move glob_zero to .upper.bss. No .lower.bss in ld script." "-T msp430-no-lower.ld --data-region=upper"
+    "" "" {main-with-data-bss.s} {{objdump -D main-bss-upper.d}} "main-bss-upper"}
+  {"Move glob_zero to .lower.bss" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-data-bss.s} {{objdump -D main-bss-lower.d}} "main-bss-lower"}
+  {"Move \"either\" glob_zero to .lower.bss" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-data-bss.s} {{objdump -D main-bss-lower.d}} "main-bss-lower"}
+
+  {"Move glob_const to .upper.rodata" "-T msp430.ld --data-region=upper"
+    "" "" {main-with-text-rodata.s} {{objdump -D main-const-upper.d}} "main-const-upper"}
+  {"Move glob_const to .upper.rodata. No .lower.rodata in ld script." "-T msp430-no-lower.ld --data-region=upper"
+    "" "" {main-with-text-rodata.s} {{objdump -D main-const-upper.d}} "main-const-upper"}
+  {"Move glob_const to .lower.rodata" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-text-rodata.s} {{objdump -D main-const-lower.d}} "main-const-lower"}
+  {"Move \"either\" glob_const to .lower.rodata" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-text-rodata.s} {{objdump -D main-const-lower.d}} "main-const-lower"}
+}
+
+set msp430regionprefixuniquesectiontests {
+  {"Move main() to .upper.text, with -ffunction/data-sections" "-T msp430.ld --code-region=upper"
+    "" "" {main-with-text-rodata-unique-sec.s} {{objdump -d main-text-upper.d}} "main-upper"}
+  {"Move main() to .upper.text. No .lower.text in ld script, with -ffunction/data-sections" "-T msp430-no-lower.ld --code-region=upper"
+    "" "" {main-with-text-rodata-unique-sec.s} {{objdump -d main-text-upper.d}} "main-upper"}
+  {"Move main() to .lower.text, with -ffunction/data-sections" "-T msp430.ld --code-region=lower"
+    "" "" {main-with-text-rodata-unique-sec.s} {{objdump -d main-text-lower.d}} "main-lower"}
+  {"Move \"either\" main() to .lower.text, with -ffunction/data-sections" "-T msp430.ld --code-region=either"
+    "" "" {main-with-text-rodata-unique-sec.s} {{objdump -d main-text-lower.d}} "main-either"}
+
+  {"Move glob_var to .upper.data, with -ffunction/data-sections" "-T msp430.ld --data-region=upper"
+    "" "" {main-with-data-bss-unique-sec.s} {{objdump -D main-var-upper.d}} "main-var-upper"}
+  {"Move glob_var to .upper.data. No .lower.data in ld script, with -ffunction/data-sections" "-T msp430-no-lower.ld --data-region=upper"
+    "" "" {main-with-data-bss-unique-sec.s} {{objdump -D main-var-upper.d}} "main-var-upper"}
+  {"Move glob_var to .lower.data, with -ffunction/data-sections" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-data-bss-unique-sec.s} {{objdump -D main-var-lower.d}} "main-var-lower"}
+  {"Move \"either\" glob_var to .lower.data, with -ffunction/data-sections" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-data-bss-unique-sec.s} {{objdump -D main-var-lower.d}} "main-var-lower"}
+
+  {"Move glob_zero to .upper.bss, with -ffunction/data-sections" "-T msp430.ld --data-region=upper"
+    "" "" {main-with-data-bss-unique-sec.s} {{objdump -D main-bss-upper.d}} "main-bss-upper"}
+  {"Move glob_zero to .upper.bss. No .lower.bss in ld script., with -ffunction/data-sections" "-T msp430-no-lower.ld --data-region=upper"
+    "" "" {main-with-data-bss-unique-sec.s} {{objdump -D main-bss-upper.d}} "main-bss-upper"}
+  {"Move glob_zero to .lower.bss, with -ffunction/data-sections" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-data-bss-unique-sec.s} {{objdump -D main-bss-lower.d}} "main-bss-lower"}
+  {"Move \"either\" glob_zero to .lower.bss, with -ffunction/data-sections" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-data-bss-unique-sec.s} {{objdump -D main-bss-lower.d}} "main-bss-lower"}
+
+  {"Move glob_const to .upper.rodata, with -ffunction/data-sections" "-T msp430.ld --data-region=upper"
+    "" "" {main-with-text-rodata-unique-sec.s} {{objdump -D main-const-upper.d}} "main-const-upper"}
+  {"Move glob_const to .upper.rodata. No .lower.rodata in ld script., with -ffunction/data-sections" "-T msp430-no-lower.ld --data-region=upper"
+    "" "" {main-with-text-rodata-unique-sec.s} {{objdump -D main-const-upper.d}} "main-const-upper"}
+  {"Move glob_const to .lower.rodata, with -ffunction/data-sections" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-text-rodata-unique-sec.s} {{objdump -D main-const-lower.d}} "main-const-lower"}
+  {"Move \"either\" glob_const to .lower.rodata, with -ffunction/data-sections" "-T msp430.ld --data-region=lower"
+    "" "" {main-with-text-rodata-unique-sec.s} {{objdump -D main-const-lower.d}} "main-const-lower"}
+}
+
+run_ld_link_tests $msp430regionprefixtests
+run_ld_link_tests $msp430regionprefixuniquesectiontests
diff --git a/ld/testsuite/ld-msp430-elf/msp430-no-lower.ld b/ld/testsuite/ld-msp430-elf/msp430-no-lower.ld
new file mode 100644
index 0000000..f9a2847
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/msp430-no-lower.ld
@@ -0,0 +1,54 @@
+/* Script for ld testsuite */
+OUTPUT_ARCH(msp430)
+ENTRY(_start)
+
+SECTIONS
+{
+  .text :
+  {
+    PROVIDE (_start = .);
+    . = ALIGN(2);
+    *(.text .stub .text.* .gnu.linkonce.t.* .text:*)
+  }
+
+  .rodata :
+  {
+    *(.rodata.* .rodata)
+  }
+
+  .data :
+  {
+    . = ALIGN(2);
+    *(.data.* .data)
+  }
+
+  .bss :
+  {
+    . = ALIGN(2);
+    *(.bss.* .bss)
+  }
+
+  .upper.text :
+  {
+    . = ALIGN(2);
+    *(.upper.text.* .upper.text)
+  }
+
+  .upper.rodata :
+  {
+    . = ALIGN(2);
+    *(.upper.rodata .upper.rodata.*)
+  }
+
+  .upper.data :
+  {
+    . = ALIGN(2);
+    *(.upper.data .upper.data.*)
+  }
+
+  .upper.bss :
+  {
+    . = ALIGN(2);
+    *(.upper.bss .upper.bss.*)
+  }
+}
diff --git a/ld/testsuite/ld-msp430-elf/msp430.ld b/ld/testsuite/ld-msp430-elf/msp430.ld
new file mode 100644
index 0000000..9c30836
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/msp430.ld
@@ -0,0 +1,78 @@
+/* Script for ld testsuite */
+OUTPUT_ARCH(msp430)
+ENTRY(_start)
+
+SECTIONS
+{
+  .lower.data :
+  {
+    . = ALIGN(2);
+    *(.lower.data .lower.data.*)
+  }
+
+  .lower.bss :
+  {
+    . = ALIGN(2);
+    *(.lower.bss .lower.bss.*)
+  }
+
+  .lower.text :
+  {
+    PROVIDE (_start = .);
+    . = ALIGN(2);
+    *(.lower.text.* .lower.text)
+  }
+
+  .lower.rodata :
+  {
+    . = ALIGN(2);
+    *(.lower.rodata .lower.rodata.*)
+  }
+
+  .text :
+  {
+    . = ALIGN(2);
+    *(.text .stub .text.* .gnu.linkonce.t.* .text:*)
+  }
+
+  .rodata :
+  {
+    *(.rodata.* .rodata)
+  }
+
+  .data :
+  {
+    . = ALIGN(2);
+    *(.data.* .data)
+  }
+
+  .bss :
+  {
+    . = ALIGN(2);
+    *(.bss.* .bss)
+  }
+
+  .upper.text :
+  {
+    . = ALIGN(2);
+    *(.upper.text.* .upper.text)
+  }
+
+  .upper.rodata :
+  {
+    . = ALIGN(2);
+    *(.upper.rodata .upper.rodata.*)
+  }
+
+  .upper.data :
+  {
+    . = ALIGN(2);
+    *(.upper.data .upper.data.*)
+  }
+
+  .upper.bss :
+  {
+    . = ALIGN(2);
+    *(.upper.bss .upper.bss.*)
+  }
+}
-- 
1.8.3.1


[-- Attachment #3: 0002-MSP430-Change-.either-section-placement-to-be-perfor.patch --]
[-- Type: text/plain, Size: 16334 bytes --]

From 5177beaa4420d915fc4c06435b954e15bba4e889 Mon Sep 17 00:00:00 2001
From: Jozef Lawrynowicz <jozef.l@somniumtech.com>
Date: Mon, 10 Jul 2017 15:12:18 +0000
Subject: [PATCH 2/4] MSP430: Change .either section placement to be performed
 after allocation

2017-08-XX	Jozef Lawrynowicz	<jozef.l@somniumtech.com>
	
	* ld/emultempl/msp430.em (data_statement_size): New.
	(eval_upper_either_sections): New.
	(eval_lower_either_sections): New.
	(intermediate_relax_sections): New.
	(msp430_elf_after_allocation): New.

ld/testsuite
2017-08-XX	Jozef Lawrynowicz	<jozef.l@somniumtech.com>
	* ld-msp430-elf/msp430-elf.exp: Add either "shuffle" tests.
	* ld-msp430-elf/msp430-tiny-ram.ld: New.
	* ld-msp430-elf/msp430-tiny-rom.ld: New.
---
 ld/emultempl/msp430.em                        | 320 +++++++++++++++++++++++++-
 ld/testsuite/ld-msp430-elf/msp430-elf.exp     |  29 +++
 ld/testsuite/ld-msp430-elf/msp430-tiny-ram.ld |  49 ++++
 ld/testsuite/ld-msp430-elf/msp430-tiny-rom.ld |  48 ++++
 4 files changed, 445 insertions(+), 1 deletion(-)
 create mode 100644 ld/testsuite/ld-msp430-elf/msp430-tiny-ram.ld
 create mode 100644 ld/testsuite/ld-msp430-elf/msp430-tiny-rom.ld

diff --git a/ld/emultempl/msp430.em b/ld/emultempl/msp430.em
index 2f3724d..814897b 100644
--- a/ld/emultempl/msp430.em
+++ b/ld/emultempl/msp430.em
@@ -50,6 +50,14 @@ enum regions
   REGION_EITHER = 3,
 };
 
+enum either_placement_stage
+{
+  LOWER_TO_UPPER,
+  UPPER_TO_LOWER,
+};
+
+enum { ROM, RAM };
+
 static int data_region = REGION_NONE;
 static int code_region = REGION_NONE;
 static bfd_boolean disable_sec_transformation = FALSE;
@@ -140,6 +148,32 @@ fi
 if test x"$LDEMUL_PLACE_ORPHAN" != xgld"$EMULATION_NAME"_place_orphan; then
 fragment <<EOF
 
+static unsigned int
+data_statement_size (lang_data_statement_type *d)
+{
+  unsigned int size = 0;
+  switch (d->type)
+    {
+    case QUAD:
+    case SQUAD:
+      size = QUAD_SIZE;
+      break;
+    case LONG:
+      size = LONG_SIZE;
+      break;
+    case SHORT:
+      size = SHORT_SIZE;
+      break;
+    case BYTE:
+      size = BYTE_SIZE;
+      break;
+    default:
+      einfo ("%P: error: unhandled data_statement size\n");
+      FAIL ();
+    }
+  return size;
+}
+
 /* Helper function for place_orphan that computes the size
    of sections already mapped to the given statement.  */
 
@@ -159,12 +193,17 @@ scan_children (lang_statement_union_type * l)
 
 	case lang_constructors_statement_enum:
 	case lang_assignment_statement_enum:
+	case lang_padding_statement_enum:
 	  break;
 
 	case lang_wild_statement_enum:
 	  amount += scan_children (l->wild_statement.children.head);	  
 	  break;
 
+	case lang_data_statement_enum:
+	  amount += data_statement_size (&l->data_statement);
+	  break;
+
 	default:
 	  fprintf (stderr, "msp430 orphan placer: unhandled lang type %d\n", l->header.type);
 	  break;
@@ -537,6 +576,285 @@ gld${EMULATION_NAME}_handle_option (int optc)
   return TRUE;
 }
 
+static void
+eval_upper_either_sections (bfd *abfd, asection *s, void *data)
+{
+  char * base_sec_name;
+  const char * curr_name;
+  char * either_name;
+  int curr_region;
+
+  lang_output_section_statement_type * lower;
+  lang_output_section_statement_type * upper;
+  static bfd_size_type *lower_size = 0;
+  static bfd_size_type *upper_size = 0;
+  static bfd_size_type lower_size_rom = 0;
+  static bfd_size_type lower_size_ram = 0;
+  static bfd_size_type upper_size_rom = 0;
+  static bfd_size_type upper_size_ram = 0;
+
+  if ((s->flags & SEC_ALLOC) == 0)
+    return;
+  if (bfd_link_relocatable (&link_info))
+    return;
+
+  base_sec_name = (char *) data;
+  curr_name = bfd_get_section_name (abfd, s);
+
+  /* Only concerned with .either input sections in the upper output section.
+     */
+  either_name = concat (".either", base_sec_name, NULL);
+  if (strncmp (curr_name, either_name, strlen (either_name)) != 0
+      || strncmp (s->output_section->name, ".upper", 6) != 0)
+    goto end;
+
+  lower = lang_output_section_find (concat (".lower", base_sec_name, NULL));
+  upper = lang_output_section_find (concat (".upper", base_sec_name, NULL));
+
+  if (upper == NULL || upper->region == NULL)
+    goto end;
+  else if (lower == NULL)
+    lower = lang_output_section_find (base_sec_name);
+  if (lower == NULL || lower->region == NULL)
+    goto end;
+
+  if (strcmp (base_sec_name, ".text") == 0
+      || strcmp (base_sec_name, ".rodata") == 0)
+    curr_region = ROM;
+  else
+    curr_region = RAM;
+
+  if (curr_region == ROM)
+    {
+      if (lower_size_rom == 0)
+	{
+	  lower_size_rom = lower->region->current - lower->region->origin;
+	  upper_size_rom = upper->region->current - upper->region->origin;
+	}
+      lower_size = &lower_size_rom;
+      upper_size = &upper_size_rom;
+    }
+  else if (curr_region == RAM)
+    {
+      if (lower_size_ram == 0)
+	{
+	  lower_size_ram = lower->region->current - lower->region->origin;
+	  upper_size_ram = upper->region->current - upper->region->origin;
+	}
+      lower_size = &lower_size_ram;
+      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 (change_output_section (&(upper->children.head),
+				 s, lower))
+	{
+	  *upper_size -= s->size;
+	  *lower_size += s->size;
+	}
+    }
+ end:
+  free (either_name);
+}
+
+static void
+eval_lower_either_sections (bfd *abfd, asection *s, void *data)
+{
+  char * base_sec_name;
+  const char * curr_name;
+  char * either_name;
+  int curr_region;
+
+  lang_output_section_statement_type * output_sec;
+  lang_output_section_statement_type * lower;
+  lang_output_section_statement_type * upper;
+
+  static bfd_size_type *lower_size = 0;
+  static bfd_size_type lower_size_rom = 0;
+  static bfd_size_type lower_size_ram = 0;
+
+  if ((s->flags & SEC_ALLOC) == 0)
+    return;
+  if (bfd_link_relocatable (&link_info))
+    return;
+
+  base_sec_name = (char *) data;
+  curr_name = bfd_get_section_name (abfd, s);
+
+  /* Only concerned with .either input sections in the lower or "default"
+     output section i.e. not in the upper output section.  */
+  either_name = concat (".either", base_sec_name, NULL);
+  if (strncmp (curr_name, either_name, strlen (either_name)) != 0
+      || strncmp (s->output_section->name, ".upper", 6) == 0)
+    return;
+
+  if (strcmp (base_sec_name, ".text") == 0
+      || strcmp (base_sec_name, ".rodata") == 0)
+    curr_region = ROM;
+  else
+    curr_region = RAM;
+
+  output_sec = lang_output_section_find (s->output_section->name);
+
+  /* If the output_section doesn't exist, this has already been reported in
+     place_orphan, so don't need to warn again.  */
+  if (output_sec == NULL || output_sec->region == NULL)
+    goto end;
+
+  /* lower and output_sec might be the same, but in some cases an .either
+     section can end up in base_sec_name if it hasn't been placed by
+     place_orphan.  */
+  lower = lang_output_section_find (concat (".lower", base_sec_name, NULL));
+  upper = lang_output_section_find (concat (".upper", base_sec_name, NULL));
+  if (upper == NULL)
+    goto end;
+
+  if (curr_region == ROM)
+    {
+      if (lower_size_rom == 0)
+	{
+	  /* Get the size of other items in the lower region that aren't the
+	     sections to be moved around.  */
+	  lower_size_rom
+	    = (output_sec->region->current - output_sec->region->origin)
+	    - scan_children (output_sec->children.head);
+	  if (output_sec != lower && lower != NULL)
+	    lower_size_rom -= scan_children (lower->children.head);
+	}
+      lower_size = &lower_size_rom;
+    }
+  else if (curr_region == RAM)
+    {
+      if (lower_size_ram == 0)
+	{
+	  lower_size_ram
+	    = (output_sec->region->current - output_sec->region->origin)
+	    - scan_children (output_sec->children.head);
+	  if (output_sec != lower && lower != NULL)
+	    lower_size_ram -= scan_children (lower->children.head);
+	}
+      lower_size = &lower_size_ram;
+    }
+  /* 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);
+  else
+    *lower_size += s->size;
+ end:
+  free (either_name);
+}
+
+/* This function is similar to lang_relax_sections, but without the size
+   evaluation code that is always executed after relaxation.  */
+static void
+intermediate_relax_sections (void)
+{
+  int i = link_info.relax_pass;
+
+  /* The backend can use it to determine the current pass.  */
+  link_info.relax_pass = 0;
+
+  while (i--)
+    {
+      bfd_boolean relax_again;
+
+      link_info.relax_trip = -1;
+      do
+	{
+	  link_info.relax_trip++;
+
+	  lang_do_assignments (lang_assigning_phase_enum);
+
+	  lang_reset_memory_regions ();
+
+	  relax_again = FALSE;
+	  lang_size_sections (&relax_again, FALSE);
+	}
+      while (relax_again);
+
+      link_info.relax_pass++;
+    }
+}
+
+static void
+msp430_elf_after_allocation (void)
+{
+  int relax_count = 0;
+  int i;
+  /* Go over each section twice, once to place either sections that don't fit
+     in lower into upper, and then again to move any sections in upper that fit
+     in lower into lower.  */
+  for (i = 0; i < 8; i++)
+    {
+      int placement_stage = (i < 4) ? LOWER_TO_UPPER : UPPER_TO_LOWER;
+      char * base_sec_name;
+      lang_output_section_statement_type * upper;
+      switch (i % 4)
+	{
+	case 0:
+	  base_sec_name = concat (".text", NULL);
+	  break;
+	case 1:
+	  base_sec_name = concat (".data", NULL);
+	  break;
+	case 2:
+	  base_sec_name = concat (".bss", NULL);
+	  break;
+	case 3:
+	  base_sec_name = concat (".rodata", NULL);
+	  break;
+	}
+      upper = lang_output_section_find (concat (".upper", base_sec_name, NULL));
+      if (upper != NULL)
+	{
+	  /* Can't just use one iteration over the all the sections to make
+	     both lower->upper and upper->lower transformations because the
+	     iterator encounters upper sections before all lower sections have
+	     been examined.  */
+	  bfd *abfd;
+	  if (placement_stage == LOWER_TO_UPPER)
+	    {
+	      /* Perform relaxation and get the final size of sections before
+		 trying to fit .either sections in the correct ouput sections.
+	       */
+	      if (relax_count == 0)
+		{
+		  intermediate_relax_sections ();
+		  relax_count++;
+		}
+	      for (abfd = link_info.input_bfds; abfd != NULL;
+		   abfd = abfd->link.next)
+		{
+		  bfd_map_over_sections (abfd, eval_lower_either_sections,
+					 base_sec_name);
+		}
+	    }
+	  else if (placement_stage == UPPER_TO_LOWER)
+	    {
+	      /* Relax again before moving upper->lower.  */
+	      if (relax_count == 1)
+		{
+		  intermediate_relax_sections ();
+		  relax_count++;
+		}
+	      for (abfd = link_info.input_bfds; abfd != NULL;
+		   abfd = abfd->link.next)
+		{
+		  bfd_map_over_sections (abfd, eval_upper_either_sections,
+					 base_sec_name);
+		}
+	    }
+
+	}
+      free (base_sec_name);
+    }
+  gld${EMULATION_NAME}_after_allocation ();
+}
+
 struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
 {
   ${LDEMUL_BEFORE_PARSE-gld${EMULATION_NAME}_before_parse},
@@ -544,7 +862,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   ${LDEMUL_HLL-hll_default},
   ${LDEMUL_AFTER_PARSE-after_parse_default},
   msp430_elf_after_open,
-  ${LDEMUL_AFTER_ALLOCATION-after_allocation_default},
+  msp430_elf_after_allocation,
   ${LDEMUL_SET_OUTPUT_ARCH-set_output_arch_default},
   ${LDEMUL_CHOOSE_TARGET-ldemul_default_target},
   ${LDEMUL_BEFORE_ALLOCATION-before_allocation_default},
diff --git a/ld/testsuite/ld-msp430-elf/msp430-elf.exp b/ld/testsuite/ld-msp430-elf/msp430-elf.exp
index bed2ed8..fa396aa 100644
--- a/ld/testsuite/ld-msp430-elf/msp430-elf.exp
+++ b/ld/testsuite/ld-msp430-elf/msp430-elf.exp
@@ -108,5 +108,34 @@ set msp430regionprefixuniquesectiontests {
     "" "" {main-with-text-rodata-unique-sec.s} {{objdump -D main-const-lower.d}} "main-const-lower"}
 }
 
+set msp430eithershuffletests {
+  {"Move \"either\" main() to .upper.text when it doesn\'t fit in .lower.text"
+    "-T msp430-tiny-rom.ld --code-region=either --data-region=either" "" "" {main-with-text-rodata.s}
+    {{objdump -d main-text-upper.d}} "either-to-upper-text"}
+  {"Move \"either\" glob_var_array to .upper.data when it doesn\'t fit in .lower.data"
+    "-T msp430-tiny-ram.ld --data-region=either" "" "" {main-with-data-bss.s}
+    {{objdump -D main-var-upper.d}} "either-to-upper-data"}
+  {"Move \"either\" glob_bss_array to .upper.bss when it doesn\'t fit in .lower.bss"
+    "-T msp430-tiny-ram.ld --data-region=either" "" "" {main-with-data-bss.s}
+    {{objdump -D main-bss-upper.d}} "either-to-upper-bss"}
+  {"Move \"either\" glob_const_array to .upper.rodata when it doesn\'t fit in .lower.rodata"
+    "-T msp430-tiny-rom.ld --code-region=either --data-region=either" "" "" {main-with-text-rodata.s}
+    {{objdump -D main-const-upper.d}} "either-to-upper-const"}
+
+  {"Move \"either\" main() to .upper.text when it doesn\'t fit in .lower.text, with -ffunction/data-sections"
+    "-T msp430-tiny-rom.ld --code-region=either --data-region=either" "" "" {main-with-text-rodata-unique-sec.s}
+    {{objdump -d main-text-upper.d}} "either-to-upper-text-unique-sec"}
+  {"Move \"either\" glob_var_array to .upper.data when it doesn\'t fit in .lower.data, with -ffunction/data-sections"
+    "-T msp430-tiny-ram.ld --data-region=either" "" "" {main-with-data-bss-unique-sec.s}
+    {{objdump -D main-var-upper.d}} "either-to-upper-data-unique-sec"}
+  {"Move \"either\" glob_bss_array to .upper.bss when it doesn\'t fit in .lower.bss, with -ffunction/data-sections"
+    "-T msp430-tiny-ram.ld --data-region=either" "" "" {main-with-data-bss-unique-sec.s}
+    {{objdump -D main-bss-upper.d}} "either-to-upper-bss-unique-sec"}
+  {"Move \"either\" glob_const_array to .upper.rodata when it doesn\'t fit in .lower.rodata, with -ffunction/data-sections"
+    "-T msp430-tiny-rom.ld --code-region=either --data-region=either" "" "" {main-with-text-rodata-unique-sec.s}
+    {{objdump -D main-const-upper.d}} "either-to-upper-const-unique-sec"}
+}
+
 run_ld_link_tests $msp430regionprefixtests
 run_ld_link_tests $msp430regionprefixuniquesectiontests
+run_ld_link_tests $msp430eithershuffletests
diff --git a/ld/testsuite/ld-msp430-elf/msp430-tiny-ram.ld b/ld/testsuite/ld-msp430-elf/msp430-tiny-ram.ld
new file mode 100644
index 0000000..e2e6f2f
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/msp430-tiny-ram.ld
@@ -0,0 +1,49 @@
+/* Script for ld testsuite */
+OUTPUT_ARCH(msp430)
+ENTRY(_start)
+
+MEMORY
+{
+  RAM : ORIGIN = 0x0, LENGTH = 0x2
+  ROM : ORIGIN = 0x2, LENGTH = 0x1fe
+  HIFRAM : ORIGIN = 0x200, LENGTH = 0x1000
+}
+
+SECTIONS
+{
+  .text :
+  {
+    PROVIDE (_start = .);
+    . = ALIGN(2);
+    *(.text .stub .text.* .gnu.linkonce.t.* .text:*)
+  } > ROM
+
+  .rodata :
+  {
+    *(.upper.rodata.* .rodata)
+  } > ROM
+
+  .data :
+  {
+    . = ALIGN(2);
+    *(.data.* .data)
+  } > RAM AT> ROM
+
+  .bss :
+  {
+    . = ALIGN(2);
+    *(.bss.* .bss)
+  } > RAM
+
+  .upper.data :
+  {
+    . = ALIGN(2);
+    *(.upper.data.* .upper.data)
+  } > HIFRAM AT> ROM
+
+  .upper.bss :
+  {
+    . = ALIGN(2);
+    *(.upper.bss.* .upper.bss)
+  } > HIFRAM
+}
diff --git a/ld/testsuite/ld-msp430-elf/msp430-tiny-rom.ld b/ld/testsuite/ld-msp430-elf/msp430-tiny-rom.ld
new file mode 100644
index 0000000..3e26379
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/msp430-tiny-rom.ld
@@ -0,0 +1,48 @@
+/* Script for ld testsuite */
+OUTPUT_ARCH(msp430)
+ENTRY(_start)
+
+MEMORY
+{
+  ROM : ORIGIN = 0x0, LENGTH = 0x2
+  RAM : ORIGIN = 0x2, LENGTH = 0x1fe
+  HIROM : ORIGIN = 0x200, LENGTH = 0x1000
+}
+
+SECTIONS
+{
+  .text :
+  {
+    PROVIDE (_start = .);
+    . = ALIGN(2);
+    *(.text .stub .text.* .gnu.linkonce.t.* .text:*)
+  } > ROM
+
+  .rodata :
+  {
+    *(.rodata.* .rodata)
+  } > ROM
+
+  .data :
+  {
+    . = ALIGN(2);
+    *(.data.* .data)
+  } > RAM AT> ROM
+
+  .bss :
+  {
+    . = ALIGN(2);
+    *(.bss.* .bss)
+  } > RAM
+
+  .upper.text :
+  {
+    . = ALIGN(2);
+    *(.upper.text.* .upper.text)
+  } > HIROM
+
+  .upper.rodata :
+  {
+    *(.upper.rodata.* .upper.rodata)
+  } > HIROM
+}
-- 
1.8.3.1


[-- Attachment #4: 0003-MSP430-Remove-.either-placement-code-from-place_orph.patch --]
[-- Type: text/plain, Size: 3257 bytes --]

From 611a1450e60cc3c3eb2d4b344ec6b5d4e1d0f17b Mon Sep 17 00:00:00 2001
From: Jozef Lawrynowicz <jozef.l@somniumtech.com>
Date: Mon, 10 Jul 2017 16:42:17 +0000
Subject: [PATCH 3/4] MSP430: Remove .either placement code from place_orphan

2017-08-XX	Jozef Lawrynowicz	<jozef.l@somniumtech.com>

	* ld/emultempl/msp430.em (gld${EMULATION_NAME}_place_orphan): Always place
	sections in the lower region.
---
 ld/emultempl/msp430.em | 56 ++++++++++++++------------------------------------
 1 file changed, 15 insertions(+), 41 deletions(-)

diff --git a/ld/emultempl/msp430.em b/ld/emultempl/msp430.em
index 814897b..f1d7205 100644
--- a/ld/emultempl/msp430.em
+++ b/ld/emultempl/msp430.em
@@ -229,7 +229,6 @@ gld${EMULATION_NAME}_place_orphan (asection * s,
   char * buf = NULL;
   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;
@@ -266,57 +265,32 @@ gld${EMULATION_NAME}_place_orphan (asection * s,
   /* 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)
+  if (lower == NULL && upper == NULL)
     {
-      os = upper;
-      if (upper == NULL)
-        {
-          einfo ("%P: error: no section named %s or %s in linker script\n", lower_name, upper_name);
-	  goto end;
-	}
+      einfo ("%P: error: no section named %s or %s in linker script\n",
+	     lower_name, upper_name);
+      goto end;
     }
-  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
+  else if (lower == NULL)
     {
-      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;
+      lower = lang_output_section_find (name);
+      if (lower == NULL)
+	{
+	  einfo ("%P: error: no section named %s in linker script\n", name);
+	  goto end;
+	}
     }
 
-  lang_add_section (& os->children, s, NULL, os);
+  /* Always place orphaned sections in lower.  Optimal placement of either
+     sections is performed later, once section sizes have been finalized.  */
+  lang_add_section (& lower->children, s, NULL, lower);
  end:
   free (upper_name);
   free (lower_name);
   if (buf)
     free (buf);
-  return os;
+  return lower;
 }
 EOF
 fi
-- 
1.8.3.1


[-- Attachment #5: 0004-MSP430-Define-symbols-to-initialise-high-data-and-hi.patch --]
[-- Type: text/plain, Size: 5979 bytes --]

From 0a37be4993c86f2727ab11afb55b4f422de33340 Mon Sep 17 00:00:00 2001
From: Jozef Lawrynowicz <jozef.l@somniumtech.com>
Date: Mon, 10 Jul 2017 16:53:05 +0000
Subject: [PATCH 4/4] MSP430: Define symbols to initialise high data and high
 bss when the upper data region could be used

2017-08-XX	Jozef Lawrynowicz	<jozef.l@somniumtech.com>

	* gas/config/tc-msp430.c (md_parse_option): Define high data and high
	bss symbols if -mdata-region is passed.
	Define -mdata-region open.
	* gas/doc/c-msp430.texi: Document -mdata-region.
	
gas/testsuite
2017-08-XX	Jozef Lawrynowicz	<jozef.l@somniumtech.com>

	* gas/msp430/high-data-bss-sym.d: New test.
	* gas/msp430/high-data-bss-sym.s: New.
	* gas/msp430/msp430.exp: Add -mdata-region tests.
---
 gas/config/tc-msp430.c                       | 23 ++++++++++++++++++++---
 gas/doc/c-msp430.texi                        | 13 +++++++++++++
 gas/testsuite/gas/msp430/high-data-bss-sym.d |  6 ++++++
 gas/testsuite/gas/msp430/high-data-bss-sym.s | 19 +++++++++++++++++++
 gas/testsuite/gas/msp430/msp430.exp          |  2 ++
 5 files changed, 60 insertions(+), 3 deletions(-)
 create mode 100644 gas/testsuite/gas/msp430/high-data-bss-sym.d
 create mode 100644 gas/testsuite/gas/msp430/high-data-bss-sym.s

diff --git a/gas/config/tc-msp430.c b/gas/config/tc-msp430.c
index 91e0a73..62a34ed 100644
--- a/gas/config/tc-msp430.c
+++ b/gas/config/tc-msp430.c
@@ -676,6 +676,8 @@ static bfd_boolean warn_interrupt_nops = TRUE;
 #define OPTION_MCPU 'c'
 #define OPTION_MOVE_DATA 'd'
 static bfd_boolean move_data = FALSE;
+#define OPTION_DATA_REGION 'r'
+static bfd_boolean upper_data_region_in_use = FALSE;
 
 enum
 {
@@ -1448,6 +1450,12 @@ md_parse_option (int c, const char * arg)
     case OPTION_MOVE_DATA:
       move_data = TRUE;
       return 1;
+
+    case OPTION_DATA_REGION:
+      if (strcmp (arg, "upper") == 0
+	  || strcmp (arg, "either") == 0)
+	upper_data_region_in_use = TRUE;
+      return 1;
     }
 
   return 0;
@@ -1478,14 +1486,19 @@ msp430_make_init_symbols (const char * name)
 
   /* Note - data assigned to the .either.data section may end up being
      placed in the .upper.data section if the .lower.data section is
-     full.  Hence the need to define the crt0 symbol.  */
+     full.  Hence the need to define the crt0 symbol.
+     The linker may create upper or either data sections, even when none exist
+     at the moment, so use the value of the data-region flag to determine if
+     the symbol is needed.  */
   if (strncmp (name, ".either.data", 12) == 0
-      || strncmp (name, ".upper.data", 11) == 0)
+      || strncmp (name, ".upper.data", 11) == 0
+      || upper_data_region_in_use)
     (void) symbol_find_or_make ("__crt0_move_highdata");
 
   /* See note about .either.data above.  */
   if (strncmp (name, ".upper.bss", 10) == 0
-      || strncmp (name, ".either.bss", 11) == 0)
+      || strncmp (name, ".either.bss", 11) == 0
+      || upper_data_region_in_use)
     (void) symbol_find_or_make ("__crt0_init_highbss");
 }
 
@@ -1570,6 +1583,7 @@ struct option md_longopts[] =
   {"mY", no_argument, NULL, OPTION_NO_WARN_INTR_NOPS},
   {"my", no_argument, NULL, OPTION_WARN_INTR_NOPS},
   {"md", no_argument, NULL, OPTION_MOVE_DATA},
+  {"mdata-region", required_argument, NULL, OPTION_DATA_REGION},
   {NULL, no_argument, NULL, 0}
 };
 
@@ -1601,6 +1615,9 @@ md_show_usage (FILE * stream)
 	   _("  -my - warn about missing NOPs after changing interrupts (default)\n"));
   fprintf (stream,
 	   _("  -md - Force copying of data from ROM to RAM at startup\n"));
+  fprintf (stream,
+	   _("  -mdata-region={none|lower|upper|either} - select region data will be\n"
+	     "    placed in.\n"));
 }
 
 symbolS *
diff --git a/gas/doc/c-msp430.texi b/gas/doc/c-msp430.texi
index eb0e757..d80f540 100644
--- a/gas/doc/c-msp430.texi
+++ b/gas/doc/c-msp430.texi
@@ -107,6 +107,19 @@ disables warnings about missing NOP instructions.
 mark the object file as one that requires data to copied from ROM to
 RAM at execution startup.  Disabled by default.
 
+@item -mdata-region=@var{region}
+Select the region data will be placed in.
+Region placement is performed by the compiler and linker.  The only effect this
+option will have on the assembler is that if @var{upper} or @var{either} is
+selected, then the symbols to initialise high data and bss will be defined.
+Valid @var{region} values are:
+@table @code
+@item none
+@item lower
+@item upper
+@item either
+@end table
+
 @end table
 
 @node MSP430 Syntax
diff --git a/gas/testsuite/gas/msp430/high-data-bss-sym.d b/gas/testsuite/gas/msp430/high-data-bss-sym.d
new file mode 100644
index 0000000..1c8d95b
--- /dev/null
+++ b/gas/testsuite/gas/msp430/high-data-bss-sym.d
@@ -0,0 +1,6 @@
+#objdump: -t
+#name: Check symbols to initialise high data and high bss have been defined
+#...
+.*__crt0_move_highdata.*
+.*__crt0_init_highbss.*
+#pass
diff --git a/gas/testsuite/gas/msp430/high-data-bss-sym.s b/gas/testsuite/gas/msp430/high-data-bss-sym.s
new file mode 100644
index 0000000..1e6bf72
--- /dev/null
+++ b/gas/testsuite/gas/msp430/high-data-bss-sym.s
@@ -0,0 +1,19 @@
+	.file	"main.c"
+.text
+	.balign 2
+	.global	main
+	.type	main, @function
+main:
+; start of function
+; framesize_regs:     0
+; framesize_locals:   0
+; framesize_outgoing: 0
+; framesize:          0
+; elim ap -> fp       2
+; elim fp -> sp       0
+; saved regs:(none)
+	; start of prologue
+	; end of prologue
+.L2:
+	BR	#.L2
+	.size	main, .-main
diff --git a/gas/testsuite/gas/msp430/msp430.exp b/gas/testsuite/gas/msp430/msp430.exp
index b83e1ac..0dfb271 100644
--- a/gas/testsuite/gas/msp430/msp430.exp
+++ b/gas/testsuite/gas/msp430/msp430.exp
@@ -24,4 +24,6 @@ if [expr [istarget "msp430-*-*"]]  then {
     run_dump_test "bad"
     run_dump_test "errata_warns"
     run_dump_test "errata_fixes"
+    run_dump_test "high-data-bss-sym" { { as "-mdata-region=upper" } }
+    run_dump_test "high-data-bss-sym" { { as "-mdata-region=either" } }
 }
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 0/4][MSP430] Improve behaviour of ".either" section placement
  2017-08-24 17:17 ` Jozef Lawrynowicz
@ 2017-08-29 16:21   ` Nick Clifton
  0 siblings, 0 replies; 8+ messages in thread
From: Nick Clifton @ 2017-08-29 16:21 UTC (permalink / raw)
  To: Jozef Lawrynowicz, binutils

Hi Jozef,

> Thanks for the reply Nick, and apologies for the delay in replying. I've
> updated the patches with your advice. It was a good point about filling
> the lower region as much as possible, even when upper is not
> overflowing, so have made that change as well.
> 
> The updated patches are attached.
> I will be posting an accompanying patch to gcc-patches which propagates
> the -mcode/data-region options to the assembler and linker, which is
> necessary to actually make this new functionality useful.

Thanks for the revised patch - this time it looks good, so I have gone
ahead and checked it in.

Cheers
  Nick


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2017-08-29 16:21 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-07-19 17:08 [PATCH 0/4][MSP430] Improve behaviour of ".either" section placement Jozef Lawrynowicz
2017-07-19 17:16 ` [PATCH 1/4][MSP430] Add feature to add lower/either/upper prefixes to section names Jozef Lawrynowicz
2017-07-19 17:22   ` [PATCH 2/4][MSP430] Change .either section placement to be performed after allocation Jozef Lawrynowicz
2017-07-19 17:30     ` [PATCH 3/4][MSP430] Remove .either placement code from place_orphan Jozef Lawrynowicz
2017-07-19 17:35       ` [PATCH 4/4][MSP430] Define symbols to initialise high data and high bss when the upper data region could be used Jozef Lawrynowicz
2017-07-20 12:36 ` [PATCH 0/4][MSP430] Improve behaviour of ".either" section placement Nick Clifton
2017-08-24 17:17 ` Jozef Lawrynowicz
2017-08-29 16:21   ` Nick Clifton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).