mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-26 09:08:59 +00:00
MSP430: Fix alignment of __*_array_start symbols in default linker script
__{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.
This commit is contained in:
17
ld/ChangeLog
17
ld/ChangeLog
@@ -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.
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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.*)))
|
||||
|
||||
46
ld/testsuite/ld-msp430-elf/finiarray-warn.ld
Normal file
46
ld/testsuite/ld-msp430-elf/finiarray-warn.ld
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
1
ld/testsuite/ld-msp430-elf/finiarray-warn.r
Normal file
1
ld/testsuite/ld-msp430-elf/finiarray-warn.r
Normal file
@@ -0,0 +1 @@
|
||||
.*warning: "__fini_array_start" symbol \(finiarray-warn.ld\) is not word aligned
|
||||
45
ld/testsuite/ld-msp430-elf/initarray-nowarn.ld
Normal file
45
ld/testsuite/ld-msp430-elf/initarray-nowarn.ld
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
0
ld/testsuite/ld-msp430-elf/initarray-nowarn.r
Normal file
0
ld/testsuite/ld-msp430-elf/initarray-nowarn.r
Normal file
46
ld/testsuite/ld-msp430-elf/initarray-warn.ld
Normal file
46
ld/testsuite/ld-msp430-elf/initarray-warn.ld
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
1
ld/testsuite/ld-msp430-elf/initarray-warn.r
Normal file
1
ld/testsuite/ld-msp430-elf/initarray-warn.r
Normal file
@@ -0,0 +1 @@
|
||||
.*warning: "__init_array_start" symbol \(initarray-warn.ld\) is not word aligned
|
||||
21
ld/testsuite/ld-msp430-elf/initarray.s
Normal file
21
ld/testsuite/ld-msp430-elf/initarray.s
Normal file
@@ -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
|
||||
@@ -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]]} {
|
||||
|
||||
46
ld/testsuite/ld-msp430-elf/preinitarray-warn.ld
Normal file
46
ld/testsuite/ld-msp430-elf/preinitarray-warn.ld
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
1
ld/testsuite/ld-msp430-elf/preinitarray-warn.r
Normal file
1
ld/testsuite/ld-msp430-elf/preinitarray-warn.r
Normal file
@@ -0,0 +1 @@
|
||||
.*warning: "__preinit_array_start" symbol \(preinitarray-warn.ld\) is not word aligned
|
||||
Reference in New Issue
Block a user