From 64b63c2993db8606334f6f0852b4e7bb70b5682a Mon Sep 17 00:00:00 2001 From: Jozef Lawrynowicz Date: Fri, 28 Aug 2020 13:56:53 +0100 Subject: 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. --- ld/ChangeLog | 17 ++++++ ld/emultempl/msp430.em | 81 ++++++++++++++++++++++++- ld/scripttempl/elf32msp430.sc | 3 + ld/testsuite/ld-msp430-elf/finiarray-warn.ld | 46 ++++++++++++++ ld/testsuite/ld-msp430-elf/finiarray-warn.r | 1 + ld/testsuite/ld-msp430-elf/initarray-nowarn.ld | 45 ++++++++++++++ ld/testsuite/ld-msp430-elf/initarray-nowarn.r | 0 ld/testsuite/ld-msp430-elf/initarray-warn.ld | 46 ++++++++++++++ ld/testsuite/ld-msp430-elf/initarray-warn.r | 1 + ld/testsuite/ld-msp430-elf/initarray.s | 21 +++++++ ld/testsuite/ld-msp430-elf/msp430-elf.exp | 13 ++++ ld/testsuite/ld-msp430-elf/preinitarray-warn.ld | 46 ++++++++++++++ ld/testsuite/ld-msp430-elf/preinitarray-warn.r | 1 + 13 files changed, 320 insertions(+), 1 deletion(-) create mode 100644 ld/testsuite/ld-msp430-elf/finiarray-warn.ld create mode 100644 ld/testsuite/ld-msp430-elf/finiarray-warn.r create mode 100644 ld/testsuite/ld-msp430-elf/initarray-nowarn.ld create mode 100644 ld/testsuite/ld-msp430-elf/initarray-nowarn.r create mode 100644 ld/testsuite/ld-msp430-elf/initarray-warn.ld create mode 100644 ld/testsuite/ld-msp430-elf/initarray-warn.r create mode 100644 ld/testsuite/ld-msp430-elf/initarray.s create mode 100644 ld/testsuite/ld-msp430-elf/preinitarray-warn.ld create mode 100644 ld/testsuite/ld-msp430-elf/preinitarray-warn.r (limited to 'ld') diff --git a/ld/ChangeLog b/ld/ChangeLog index e2ca7f0..77e39a5 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,5 +1,22 @@ 2020-08-28 Jozef Lawrynowicz + * 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 + * ldmisc.c (vfinfo): Support new "%pU" format specifier. 2020-08-28 Cooper Qu diff --git a/ld/emultempl/msp430.em b/ld/emultempl/msp430.em index a47998a..7b78a53 100644 --- a/ld/emultempl/msp430.em +++ b/ld/emultempl/msp430.em @@ -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}, diff --git a/ld/scripttempl/elf32msp430.sc b/ld/scripttempl/elf32msp430.sc index f9ee9ff..4206d79 100644 --- a/ld/scripttempl/elf32msp430.sc +++ b/ld/scripttempl/elf32msp430.sc @@ -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 index 0000000..c934293 --- /dev/null +++ b/ld/testsuite/ld-msp430-elf/finiarray-warn.ld @@ -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 index 0000000..ba3fa83 --- /dev/null +++ b/ld/testsuite/ld-msp430-elf/finiarray-warn.r @@ -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 index 0000000..866c324 --- /dev/null +++ b/ld/testsuite/ld-msp430-elf/initarray-nowarn.ld @@ -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 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 index 0000000..fc00d90 --- /dev/null +++ b/ld/testsuite/ld-msp430-elf/initarray-warn.ld @@ -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 index 0000000..35abd7b --- /dev/null +++ b/ld/testsuite/ld-msp430-elf/initarray-warn.r @@ -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 index 0000000..abbf86e --- /dev/null +++ b/ld/testsuite/ld-msp430-elf/initarray.s @@ -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 diff --git a/ld/testsuite/ld-msp430-elf/msp430-elf.exp b/ld/testsuite/ld-msp430-elf/msp430-elf.exp index e9a0fdc..a2fa4db 100644 --- a/ld/testsuite/ld-msp430-elf/msp430-elf.exp +++ b/ld/testsuite/ld-msp430-elf/msp430-elf.exp @@ -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 index 0000000..acbe7f5 --- /dev/null +++ b/ld/testsuite/ld-msp430-elf/preinitarray-warn.ld @@ -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 index 0000000..ab12e42 --- /dev/null +++ b/ld/testsuite/ld-msp430-elf/preinitarray-warn.r @@ -0,0 +1 @@ +.*warning: "__preinit_array_start" symbol \(preinitarray-warn.ld\) is not word aligned -- cgit v1.1