]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
MSP430: Fix alignment of __*_array_start symbols in default linker script
authorJozef Lawrynowicz <jozef.l@mittosystems.com>
Fri, 28 Aug 2020 12:56:53 +0000 (13:56 +0100)
committerJozef Lawrynowicz <jozef.l@mittosystems.com>
Fri, 28 Aug 2020 13:01:10 +0000 (14:01 +0100)
__{preinit,init,fini}_array_start symbols must be word aligned in
linker scripts. If the section preceding the __*_array_start symbol
has an odd size, then a NULL byte will be present between the start
symbol and the .*_array section itself, when the section gets
automatically word-aligned.

This results in a branch to an invalid address when the CRT startup
code tries to run through the functions listed in the array sections.

Some MSP430 linker scripts do not align the __*_array start symbols, so
this added warning will catch that problem and help the user avoid
the potential incorrect execution of the program.

ld/ChangeLog:

* emultempl/msp430.em (input_section_exists): New.
(check_array_section_alignment): New.
(gld${EMULATION_NAME}_finish): New.
* scripttempl/elf32msp430.sc: Add ALIGN directives before the
definition of __*_array_start symbols.
* testsuite/ld-msp430-elf/finiarray-warn.ld: New test.
* testsuite/ld-msp430-elf/finiarray-warn.r: New test.
* testsuite/ld-msp430-elf/initarray-nowarn.ld: New test.
* testsuite/ld-msp430-elf/initarray-warn.ld: New test.
* testsuite/ld-msp430-elf/initarray-warn.r: New test.
* testsuite/ld-msp430-elf/initarray.s: New test.
* testsuite/ld-msp430-elf/msp430-elf.exp: Run new tests.
* testsuite/ld-msp430-elf/preinitarray-warn.ld: New test.
* testsuite/ld-msp430-elf/preinitarray-warn.r: New test.

13 files changed:
ld/ChangeLog
ld/emultempl/msp430.em
ld/scripttempl/elf32msp430.sc
ld/testsuite/ld-msp430-elf/finiarray-warn.ld [new file with mode: 0644]
ld/testsuite/ld-msp430-elf/finiarray-warn.r [new file with mode: 0644]
ld/testsuite/ld-msp430-elf/initarray-nowarn.ld [new file with mode: 0644]
ld/testsuite/ld-msp430-elf/initarray-nowarn.r [new file with mode: 0644]
ld/testsuite/ld-msp430-elf/initarray-warn.ld [new file with mode: 0644]
ld/testsuite/ld-msp430-elf/initarray-warn.r [new file with mode: 0644]
ld/testsuite/ld-msp430-elf/initarray.s [new file with mode: 0644]
ld/testsuite/ld-msp430-elf/msp430-elf.exp
ld/testsuite/ld-msp430-elf/preinitarray-warn.ld [new file with mode: 0644]
ld/testsuite/ld-msp430-elf/preinitarray-warn.r [new file with mode: 0644]

index e2ca7f0df3da85843de6da8d099e54e03d3378cc..77e39a56145d7c1d990c77059a0d320eaf98be6f 100644 (file)
@@ -1,3 +1,20 @@
+2020-08-28  Jozef Lawrynowicz  <jozef.l@mittosystems.com>
+
+       * emultempl/msp430.em (input_section_exists): New.
+       (check_array_section_alignment): New.
+       (gld${EMULATION_NAME}_finish): New.
+       * scripttempl/elf32msp430.sc: Add ALIGN directives before the
+       definition of __*_array_start symbols.
+       * testsuite/ld-msp430-elf/finiarray-warn.ld: New test.
+       * testsuite/ld-msp430-elf/finiarray-warn.r: New test.
+       * testsuite/ld-msp430-elf/initarray-nowarn.ld: New test.
+       * testsuite/ld-msp430-elf/initarray-warn.ld: New test.
+       * testsuite/ld-msp430-elf/initarray-warn.r: New test.
+       * testsuite/ld-msp430-elf/initarray.s: New test.
+       * testsuite/ld-msp430-elf/msp430-elf.exp: Run new tests.
+       * testsuite/ld-msp430-elf/preinitarray-warn.ld: New test.
+       * testsuite/ld-msp430-elf/preinitarray-warn.r: New test.
+
 2020-08-28  Jozef Lawrynowicz  <jozef.l@mittosystems.com>
 
        * ldmisc.c (vfinfo): Support new "%pU" format specifier.
index a47998a00a9ae0bf2efccdc963126289044dae20..7b78a53d7e13804466332a5dbfe4fbfbbd090ac1 100644 (file)
@@ -826,6 +826,85 @@ msp430_elf_after_allocation (void)
   gld${EMULATION_NAME}_after_allocation ();
 }
 
+/* Return TRUE if a non-debug input section in L has positive size and matches
+   the given name.  */
+static int
+input_section_exists (lang_statement_union_type * l, const char * name)
+{
+  while (l != NULL)
+    {
+      switch (l->header.type)
+       {
+       case lang_input_section_enum:
+         if ((l->input_section.section->flags & SEC_ALLOC)
+             && l->input_section.section->size > 0
+             && !strcmp (l->input_section.section->name, name))
+           return TRUE;
+         break;
+
+       case lang_wild_statement_enum:
+         if (input_section_exists (l->wild_statement.children.head, name))
+           return TRUE;
+         break;
+
+       default:
+         break;
+       }
+      l = l->header.next;
+    }
+  return FALSE;
+}
+
+/* Some MSP430 linker scripts do not include ALIGN directives to ensure
+   __preinit_array_start, __init_array_start or __fini_array_start are word
+   aligned.
+   If __*_array_start symbols are not word aligned, the code in crt0 to run
+   through the array and call the functions will crash.
+   To avoid warning unnecessarily when the .*_array sections are not being
+   used for running constructors/destructors, only emit the warning if
+   the associated section exists and has size.  */
+static void
+check_array_section_alignment (void)
+{
+  int i;
+  lang_output_section_statement_type * rodata_sec;
+  lang_output_section_statement_type * rodata2_sec;
+  const char * array_names[3][2] = { { ".init_array", "__init_array_start" },
+       { ".preinit_array", "__preinit_array_start" },
+       { ".fini_array", "__fini_array_start" } };
+
+  /* .{preinit,init,fini}_array could be in either .rodata or .rodata2.  */
+  rodata_sec = lang_output_section_find (".rodata");
+  rodata2_sec = lang_output_section_find (".rodata2");
+  if (rodata_sec == NULL && rodata2_sec == NULL)
+    return;
+
+  /* There are 3 .*_array sections which must be checked for alignment.  */
+  for (i = 0; i < 3; i++)
+    {
+      struct bfd_link_hash_entry * sym;
+      if (((rodata_sec && input_section_exists (rodata_sec->children.head,
+                                               array_names[i][0]))
+          || (rodata2_sec && input_section_exists (rodata2_sec->children.head,
+                                                   array_names[i][0])))
+         && (sym = bfd_link_hash_lookup (link_info.hash, array_names[i][1],
+                                         FALSE, FALSE, TRUE))
+         && sym->type == bfd_link_hash_defined
+         && sym->u.def.value % 2)
+       {
+         einfo ("%P: warning: \"%s\" symbol (%pU) is not word aligned\n",
+                array_names[i][1], NULL);
+       }
+    }
+}
+
+static void
+gld${EMULATION_NAME}_finish (void)
+{
+  finish_default ();
+  check_array_section_alignment ();
+}
+
 struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
 {
   ${LDEMUL_BEFORE_PARSE-gld${EMULATION_NAME}_before_parse},
@@ -842,7 +921,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   ${LDEMUL_GET_SCRIPT-gld${EMULATION_NAME}_get_script},
   "${EMULATION_NAME}",
   "${OUTPUT_FORMAT}",
-  ${LDEMUL_FINISH-finish_default},
+  gld${EMULATION_NAME}_finish,
   ${LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS-NULL},
   ${LDEMUL_OPEN_DYNAMIC_ARCHIVE-NULL},
   ${LDEMUL_PLACE_ORPHAN-gld${EMULATION_NAME}_place_orphan},
index f9ee9ff65be38f7e7f88cd58448704332403bbf7..4206d797b871c664d79e742a226cc6c71f28ca12 100644 (file)
@@ -208,15 +208,18 @@ SECTIONS
 
     KEEP (*(.gcc_except_table)) *(.gcc_except_table.*)
 
+    . = ALIGN(2);
     PROVIDE (__preinit_array_start = .);
     KEEP (*(.preinit_array))
     PROVIDE (__preinit_array_end = .);
 
+    . = ALIGN(2);
     PROVIDE (__init_array_start = .);
     KEEP (*(SORT(.init_array.*)))
     KEEP (*(.init_array))
     PROVIDE (__init_array_end = .);
 
+    . = ALIGN(2);
     PROVIDE (__fini_array_start = .);
     KEEP (*(.fini_array))
     KEEP (*(SORT(.fini_array.*)))
diff --git a/ld/testsuite/ld-msp430-elf/finiarray-warn.ld b/ld/testsuite/ld-msp430-elf/finiarray-warn.ld
new file mode 100644 (file)
index 0000000..c934293
--- /dev/null
@@ -0,0 +1,46 @@
+/* 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)
+    . = ALIGN(2);
+    PROVIDE (__preinit_array_start = .);
+    KEEP (*(SORT(.preinit_array.*)))
+    KEEP (*(.preinit_array))
+    PROVIDE (__preinit_array_end = .);
+    . = ALIGN(2);
+    PROVIDE (__init_array_start = .);
+    KEEP (*(SORT(.init_array.*)))
+    KEEP (*(.init_array))
+    PROVIDE (__init_array_end = .);
+    . = ALIGN(2);
+    . += 1;
+    PROVIDE (__fini_array_start = .);
+    KEEP (*(SORT(.fini_array.*)))
+    KEEP (*(.fini_array))
+    PROVIDE (__fini_array_end = .);
+  }
+
+  .data :
+  {
+    . = ALIGN(2);
+    *(.data.* .data)
+  }
+
+  .bss :
+  {
+    . = ALIGN(2);
+    *(.bss.* .bss)
+  }
+}
diff --git a/ld/testsuite/ld-msp430-elf/finiarray-warn.r b/ld/testsuite/ld-msp430-elf/finiarray-warn.r
new file mode 100644 (file)
index 0000000..ba3fa83
--- /dev/null
@@ -0,0 +1 @@
+.*warning: "__fini_array_start" symbol \(finiarray-warn.ld\) is not word aligned
diff --git a/ld/testsuite/ld-msp430-elf/initarray-nowarn.ld b/ld/testsuite/ld-msp430-elf/initarray-nowarn.ld
new file mode 100644 (file)
index 0000000..866c324
--- /dev/null
@@ -0,0 +1,45 @@
+/* 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)
+    . = ALIGN(2);
+    PROVIDE (__preinit_array_start = .);
+    KEEP (*(SORT(.preinit_array.*)))
+    KEEP (*(.preinit_array))
+    PROVIDE (__preinit_array_end = .);
+    . = ALIGN(2);
+    PROVIDE (__init_array_start = .);
+    KEEP (*(SORT(.init_array.*)))
+    KEEP (*(.init_array))
+    PROVIDE (__init_array_end = .);
+    . = ALIGN(2);
+    PROVIDE (__fini_array_start = .);
+    KEEP (*(SORT(.fini_array.*)))
+    KEEP (*(.fini_array))
+    PROVIDE (__fini_array_end = .);
+  }
+
+  .data :
+  {
+    . = ALIGN(2);
+    *(.data.* .data)
+  }
+
+  .bss :
+  {
+    . = ALIGN(2);
+    *(.bss.* .bss)
+  }
+}
diff --git a/ld/testsuite/ld-msp430-elf/initarray-nowarn.r b/ld/testsuite/ld-msp430-elf/initarray-nowarn.r
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/ld/testsuite/ld-msp430-elf/initarray-warn.ld b/ld/testsuite/ld-msp430-elf/initarray-warn.ld
new file mode 100644 (file)
index 0000000..fc00d90
--- /dev/null
@@ -0,0 +1,46 @@
+/* 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)
+    . = ALIGN(2);
+    PROVIDE (__preinit_array_start = .);
+    KEEP (*(SORT(.preinit_array.*)))
+    KEEP (*(.preinit_array))
+    PROVIDE (__preinit_array_end = .);
+    . = ALIGN(2);
+    . += 1;
+    PROVIDE (__init_array_start = .);
+    KEEP (*(SORT(.init_array.*)))
+    KEEP (*(.init_array))
+    PROVIDE (__init_array_end = .);
+    . = ALIGN(2);
+    PROVIDE (__fini_array_start = .);
+    KEEP (*(SORT(.fini_array.*)))
+    KEEP (*(.fini_array))
+    PROVIDE (__fini_array_end = .);
+  }
+
+  .data :
+  {
+    . = ALIGN(2);
+    *(.data.* .data)
+  }
+
+  .bss :
+  {
+    . = ALIGN(2);
+    *(.bss.* .bss)
+  }
+}
diff --git a/ld/testsuite/ld-msp430-elf/initarray-warn.r b/ld/testsuite/ld-msp430-elf/initarray-warn.r
new file mode 100644 (file)
index 0000000..35abd7b
--- /dev/null
@@ -0,0 +1 @@
+.*warning: "__init_array_start" symbol \(initarray-warn.ld\) is not word aligned
diff --git a/ld/testsuite/ld-msp430-elf/initarray.s b/ld/testsuite/ld-msp430-elf/initarray.s
new file mode 100644 (file)
index 0000000..abbf86e
--- /dev/null
@@ -0,0 +1,21 @@
+.text
+       .section        .preinit_array,"aw"
+       .short 42
+
+       .section        .init_array,"aw"
+       .short 43
+
+       .section        .fini_array,"aw"
+       .short 44
+
+.text
+       .global main
+       .type   main, @function
+main:
+       MOV #__preinit_array_start, R8
+       MOV #__init_array_start, R9
+       MOV #__fini_array_start, R10
+  CALL @R8
+  CALL @R9
+  CALL @R10
+       RET
index e9a0fdc6292973f959f040716205c498507e9bc5..a2fa4db48d45bec9a39b9aca54e47e42f29f67d6 100644 (file)
@@ -163,6 +163,19 @@ set msp430warntests {
         {{ld warn-no-lower-data.r}} "warn-no-lower-data"}
 }
 
+set msp430arraytests {
+    { "Warn when __preinit_array_start is not word aligned" "-T preinitarray-warn.ld" "" ""
+        {initarray.s} {{ld preinitarray-warn.r}} "preinitarray-warn"}
+    { "Warn when __init_array_start is not word aligned" "-T initarray-warn.ld" "" ""
+        {initarray.s} {{ld initarray-warn.r}} "initarray-warn"}
+    { "Warn when __fini_array_start is not word aligned" "-T finiarray-warn.ld" "" ""
+        {initarray.s} {{ld finiarray-warn.r}} "finiarray-warn"}
+    { "Don't warn when __{preinit,init,fini}_array_start are word aligned" "-T initarray-nowarn.ld" "" ""
+        {initarray.s} {{ld initarray-nowarn.r}} "initarray-nowarn"}
+}
+
+run_ld_link_tests $msp430arraytests
+
 # Don't run further tests when msp430 ISA is selected
 if {[string match "*-mcpu=msp430 *" [board_info [target_info name] multilib_flags]]
   || [string match "*-mcpu=msp430" [board_info [target_info name] multilib_flags]]} {
diff --git a/ld/testsuite/ld-msp430-elf/preinitarray-warn.ld b/ld/testsuite/ld-msp430-elf/preinitarray-warn.ld
new file mode 100644 (file)
index 0000000..acbe7f5
--- /dev/null
@@ -0,0 +1,46 @@
+/* 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)
+    . = ALIGN(2);
+    . += 1;
+    PROVIDE (__preinit_array_start = .);
+    KEEP (*(SORT(.preinit_array.*)))
+    KEEP (*(.preinit_array))
+    PROVIDE (__preinit_array_end = .);
+    . = ALIGN(2);
+    PROVIDE (__init_array_start = .);
+    KEEP (*(SORT(.init_array.*)))
+    KEEP (*(.init_array))
+    PROVIDE (__init_array_end = .);
+    . = ALIGN(2);
+    PROVIDE (__fini_array_start = .);
+    KEEP (*(SORT(.fini_array.*)))
+    KEEP (*(.fini_array))
+    PROVIDE (__fini_array_end = .);
+  }
+
+  .data :
+  {
+    . = ALIGN(2);
+    *(.data.* .data)
+  }
+
+  .bss :
+  {
+    . = ALIGN(2);
+    *(.bss.* .bss)
+  }
+}
diff --git a/ld/testsuite/ld-msp430-elf/preinitarray-warn.r b/ld/testsuite/ld-msp430-elf/preinitarray-warn.r
new file mode 100644 (file)
index 0000000..ab12e42
--- /dev/null
@@ -0,0 +1 @@
+.*warning: "__preinit_array_start" symbol \(preinitarray-warn.ld\) is not word aligned