diff --git a/Makefile.include b/Makefile.include index 06ca9e5b6e2f..0aa8c48fb2c9 100644 --- a/Makefile.include +++ b/Makefile.include @@ -233,6 +233,11 @@ export PREFIX ?= $(if $(TARGET_ARCH),$(TARGET_ARCH)-) # Add standard include directories INCLUDES += -I$(RIOTBASE)/core/include -I$(RIOTBASE)/drivers/include -I$(RIOTBASE)/sys/include +# Augmentation ldscript for cross file arrays (XFA) +# this argument must come before any other -T options on the command line, +# otherwise we get an error message ".text not found for insert" +LINKFLAGS += -Txfa.ld + # process provided features -include $(RIOTBOARD)/$(BOARD)/Makefile.features @@ -252,6 +257,10 @@ TOOLCHAINS_SUPPORTED ?= gnu # Import all toolchain settings include $(RIOTMAKE)/toolchain/$(TOOLCHAIN).inc.mk +# Append ldscript path after importing CPU and board makefiles to allow +# overriding the core ldscripts +LINKFLAGS += -L$(RIOTBASE)/core/ldscripts + # Tell ccache to pass the original file to the compiler, instead of passing the # preprocessed code. Without this setting, the compilation will fail with # -Wimplicit-fallthrough warnings even when the fall through case is properly diff --git a/core/include/xfa.h b/core/include/xfa.h new file mode 100644 index 000000000000..20ce349a5c9d --- /dev/null +++ b/core/include/xfa.h @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2016 Kaspar Schleiser + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup core_util + * @brief Cross File Arrays + * @{ + * + * This macro, in combination with an entry in the linker scripts, allows the + * definition of constant arrays to be spread over multiple C compilation + * units. These arrays are called "cross-file arrays" or short xfa. + * + * + * + * @file + * @author Kaspar Schleiser + */ + +#ifndef XFA_H +#define XFA_H + +/** + * @brief helper macro for other XFA_* macros + * + * @internal + */ +#define _XFA(name, prio) __attribute__((used, section(".xfa." #name "." #prio))) + +/** + * @brief helper macro for other XFA_* macros + * + * @internal + */ +#define _XFA_CONST(name, prio) __attribute__((used, section(".roxfa." #name "." #prio))) const + +/** + * @brief Define a read-only cross-file array + * + * This macro defines the symbols necessary to use XFA_START() and XFA_END(). + * It needs to be part of one single compilation unit. + * + * @param[in] type name of the cross-file array + * @param[in] name name of the cross-file array + */ +#define XFA_INIT_CONST(type, name) \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wpedantic\"") \ + _XFA_CONST(name, 0_) const type name [0] = {}; \ + _XFA_CONST(name, 9_) const type name ## _end [0] = {}; \ + _Pragma("GCC diagnostic pop") \ + extern const unsigned __xfa_dummy + +/** + * @brief Define a writable cross-file array + * + * This macro defines the symbols necessary to use XFA_START() and XFA_END(). + * It needs to be part of one single compilation unit. + * + * @param[in] type name of the cross-file array + * @param[in] name name of the cross-file array + */ +#define XFA_INIT(type, name) \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wpedantic\"") \ + _XFA(name, 0_) type name [0] = {}; \ + _XFA(name, 9_) type name ## _end [0] = {}; \ + _Pragma("GCC diagnostic pop") \ + extern const unsigned __xfa_dummy + +/** + * @brief Declare an external read-only cross-file array + * + * This macro defines the symbols necessary to use XFA_START() and XFA_END(). + * Think of this as XFA_INIT() but with "extern" keyword. + * It is supposed to be used in compilation units where the cross file array is + * being accessed, but not defined using XFA_INIT. + * + * @param[in] type name of the cross-file array + * @param[in] name name of the cross-file array + */ +#define XFA_USE_CONST(type, name) \ + extern const type name []; \ + extern const type name ## _end [] + +/** + * @brief Declare an external writable cross-file array + * + * This macro defines the symbols necessary to use XFA_START() and XFA_END(). + * Think of this as XFA_INIT() but with "extern" keyword. + * It is supposed to be used in compilation units where the cross file array is + * being accessed, but not defined using XFA_INIT. + * + * @param[in] type name of the cross-file array + * @param[in] name name of the cross-file array + */ +#define XFA_USE(type, name) \ + extern type name []; \ + extern type name ## _end [] + +/** + * @brief Define variable in writable cross-file array + * + * Variables will end up sorted by prio. + * + * Add this to the type in a variable definition, e.g.: + * + * XFA(driver_params, 0) driver_params_t _onboard = { .pin=42 }; + * + * @param[in] name name of the xfa + * @param[in] prio priority within the xfa + */ +#define XFA(xfa_name, prio) _XFA(xfa_name, 5_ ##prio) + +/** + * @brief Define variable in read-only cross-file array + * + * Variables will end up sorted by prio. + * + * Add this to the type in a variable definition, e.g.: + * + * XFA(driver_params, 0) driver_params_t _onboard = { .pin=42 }; + * + * @param[in] name name of the xfa + * @param[in] prio priority within the xfa + */ +#define XFA_CONST(xfa_name, prio) _XFA_CONST(xfa_name, 5_ ##prio) + +/** + * @brief Add a pointer to cross-file array + * + * Pointers will end up sorted by prio. + * + * @param[in] xfa_name name of the xfa + * @param[in] prio priority within the xfa + * @param[in] name symbol name + * @param[in] entry pointer variable to add to xfa + */ +#define XFA_ADD_PTR(xfa_name, prio, name, entry) \ + _XFA_CONST(xfa_name, 5_ ##prio) \ + const typeof(entry) xfa_name ## _ ## prio ## _ ## name = entry + +/** + * @brief Calculate number of entries in cross-file array + */ +#define XFA_LEN(type, name) (((const char*)name ## _end - (const char*)name) / sizeof(type)) + +/** @} */ +#endif /* XFA_H */ diff --git a/core/ldscripts/xfa.ld b/core/ldscripts/xfa.ld new file mode 100644 index 000000000000..34b7d7635fe0 --- /dev/null +++ b/core/ldscripts/xfa.ld @@ -0,0 +1,23 @@ +SECTIONS +{ + .data : + { + KEEP (*(SORT(.xfa.*))) + } + __data_start = ADDR(.data); + __data_load_start = LOADADDR(.data); + __data_end = (__data_start + SIZEOF(.data)); + __data_load_end = (__data_load_start + SIZEOF(.data)); +} + +INSERT AFTER .text; + +SECTIONS +{ + .rodata : + { + KEEP (*(SORT(.roxfa.*))) + } +} + +INSERT AFTER .text; diff --git a/core/sched.c b/core/sched.c index 84151433d041..0bd9e0e31771 100644 --- a/core/sched.c +++ b/core/sched.c @@ -65,13 +65,13 @@ static uint32_t runqueue_bitcache = 0; #endif FORCE_USED_SECTION -uint8_t max_threads = sizeof(sched_threads) / sizeof(thread_t*); +const uint8_t max_threads = sizeof(sched_threads) / sizeof(thread_t*); #ifdef DEVELHELP /* OpenOCD can't determine struct offsets and additionally this member is only * available if compiled with DEVELHELP */ FORCE_USED_SECTION -uint8_t _tcb_name_offset = offsetof(thread_t, name); +const uint8_t _tcb_name_offset = offsetof(thread_t, name); #endif #ifdef MODULE_SCHEDSTATISTICS diff --git a/cpu/atmega_common/Makefile.include b/cpu/atmega_common/Makefile.include index 717ec08ab640..3e8c1a6ca686 100644 --- a/cpu/atmega_common/Makefile.include +++ b/cpu/atmega_common/Makefile.include @@ -8,6 +8,7 @@ export CFLAGS_OPT ?= -Os export CFLAGS += $(CFLAGS_CPU) $(CFLAGS_LINK) $(CFLAGS_DBG) $(CFLAGS_OPT) export ASFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG) +LINKFLAGS += -L$(RIOTCPU)/atmega_common/ldscripts export LINKFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG) $(CFLAGS_OPT) -static -lgcc -e reset_handler -Wl,--gc-sections # export the peripheral drivers to be linked into the final binary diff --git a/cpu/atmega_common/ldscripts/xfa.ld b/cpu/atmega_common/ldscripts/xfa.ld new file mode 100644 index 000000000000..29b85699c9a9 --- /dev/null +++ b/cpu/atmega_common/ldscripts/xfa.ld @@ -0,0 +1,16 @@ +SECTIONS +{ + .data : + { + /* Special case for AVR (Harvard architecture) where .rodata is merged + * into .data by the toolchain default ldscripts. */ + KEEP (*(SORT(.roxfa.*))) + KEEP (*(SORT(.xfa.*))) + } + __data_start = ADDR(.data); + __data_load_start = LOADADDR(.data); + __data_end = (__data_start + SIZEOF(.data)); + __data_load_end = (__data_load_start + SIZEOF(.data)); +} + +INSERT AFTER .text; diff --git a/cpu/cortexm_common/ldscripts/cortexm_base.ld b/cpu/cortexm_common/ldscripts/cortexm_base.ld index c6413900cae1..8363727e515c 100644 --- a/cpu/cortexm_common/ldscripts/cortexm_base.ld +++ b/cpu/cortexm_common/ldscripts/cortexm_base.ld @@ -1,33 +1,12 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ +/* Copyright (C) 2014-2018 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ -OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +/* Based on the default ldscript in GNU binutils 2.30, adjusted for ROM->RAM + * relocations */ +/* Script for -z combreloc -z now -z relro: combine and sort reloc sections */ +OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") OUTPUT_ARCH(arm) SEARCH_DIR(.) @@ -37,113 +16,290 @@ ENTRY(reset_handler_default) /* Section Definitions */ SECTIONS { - .text : + /* Read-only sections, merged into rom segment: */ + PROVIDE (__executable_start = SEGMENT_START("rom", 0x0)); . = SEGMENT_START("rom", 0x0); + .vectors : { - . = ALIGN(4); - _sfixed = .; _isr_vectors = DEFINED(_isr_vectors) ? _isr_vectors : . ; KEEP(*(SORT(.vectors*))) - *(.text .text.* .gnu.linkonce.t.*) - *(.glue_7t) *(.glue_7) - *(.rodata .rodata* .gnu.linkonce.r.*) - *(.ARM.extab* .gnu.linkonce.armextab.*) - - /* Support C constructors, and C destructors in both user code - and the C library. This also provides support for C++ code. */ . = ALIGN(4); - KEEP(*(.init)) + } + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.dyn : + { + *(.rel.init) + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.fini) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.data.rel.ro .rel.data.rel.ro.* .rel.gnu.linkonce.d.rel.ro.*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + *(.rel.ctors) + *(.rel.dtors) + *(.rel.got) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + PROVIDE_HIDDEN (__rel_iplt_start = .); + *(.rel.iplt) + PROVIDE_HIDDEN (__rel_iplt_end = .); + } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); + } + .rel.plt : + { + *(.rel.plt) + } + .rela.plt : + { + *(.rela.plt) + } + .init : + { + KEEP (*(SORT_NONE(.init))) + } + .plt : { *(.plt) } + .iplt : { *(.iplt) } + .text : + { + . = ALIGN(4); + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx) + . = ALIGN(4); + } + . = ALIGN(4); + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : + { + . = ALIGN(4); + *(.rodata .rodata.* .gnu.linkonce.r.*) + . = ALIGN(4); + } + . = ALIGN(4); + .rodata1 : + { + . = ALIGN(4); + *(.rodata1) . = ALIGN(4); - __preinit_array_start = .; + } + . = ALIGN(4); + .openocd : + { + KEEP (*(.openocd .openocd.*)) + } > rom + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } + PROVIDE_HIDDEN (__exidx_start = .); + .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } + PROVIDE_HIDDEN (__exidx_end = .); + .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges .exception_ranges*) } + /* This violates § 3.2.4.1 of C++ ABI for the ARM Architecture. + * the .preinit_array, .init_array, and .fini_array sections must be writable, + * but must be treated as if they were read-only, to allow for dynamic + * loaders to remap addresses. Ignoring this rule and placing them in ROM + * saves RAM space. */ + .preinit_array : + { + . = ALIGN(4); + PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array)) - __preinit_array_end = .; - + PROVIDE_HIDDEN (__preinit_array_end = .); . = ALIGN(4); - __init_array_start = .; - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array)) - __init_array_end = .; - - . = ALIGN(0x4); - KEEP (*crtbegin.o(.ctors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*crtend.o(.ctors)) - + } > rom + .init_array : + { . = ALIGN(4); - KEEP(*(.fini)) - + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); . = ALIGN(4); - __fini_array_start = .; - KEEP (*(.fini_array)) - KEEP (*(SORT(.fini_array.*))) - __fini_array_end = .; - - KEEP (*crtbegin.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*crtend.o(.dtors)) - + } > rom + .fini_array : + { + . = ALIGN(4); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); . = ALIGN(4); - _efixed = .; /* End of text section */ } > rom - - /* .ARM.exidx is sorted, so has to go in its own output section. */ - PROVIDE_HIDDEN (__exidx_start = .); - .ARM.exidx : + .ctors : { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) } > rom - PROVIDE_HIDDEN (__exidx_end = .); - - /* exception handling */ - . = ALIGN(4); - .eh_frame : + .dtors : { - KEEP (*(.eh_frame)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) } > rom + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) } - . = ALIGN(4); - _etext = .; - - /* stack section */ - .stack (NOLOAD): + /* Writable sections, must be relocated from ROM to RAM during early boot */ + .data : { - KEEP (*(.puf)) - . = ALIGN(8); - _sstack = .; - KEEP (*(.isr_stack)) - . = ALIGN(8); - _estack = .; - } > ram - - .relocate : + . = ALIGN(4); + __data_start = .; + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + . = ALIGN(4); + } > ram AT> rom + __data_load_start = LOADADDR(.data); + .ramfunc : { . = ALIGN(4); - _srelocate = .; - *(.ramfunc .ramfunc.*); - *(.data .data.*); - KEEP (*(.openocd .openocd.*)) + __ramfunc_start = .; + *(.ramfunc .ramfunc.*) . = ALIGN(4); - _erelocate = .; } > ram AT> rom - - /* .bss section which is used for uninitialized data */ - .bss (NOLOAD) : + __ramfunc_end = .; + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } > ram AT> rom + .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } > ram AT> rom + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } > ram AT> rom + .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } > ram AT> rom + /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } > ram AT> rom + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } > ram AT> rom + .data1 : { *(.data1) } > ram AT> rom + __data_end = .; + _edata = .; PROVIDE (edata = .); + .bss (NOLOAD) : { . = ALIGN(4); - _sbss = . ; - _szero = .; - *(.bss .bss.*) + __bss_start = .; + __bss_start__ = .; + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) . = ALIGN(4); - _ebss = . ; - _ezero = .; - } > ram + } + . = ALIGN(32 / 8); + _bss_end__ = . ; __bss_end__ = . ; + __bss_end = .; + __end__ = . ; + _end = .; PROVIDE (end = .); + .stack (NOLOAD) : + { + KEEP (*(.puf)) + . = ALIGN(8); + _sstack = .; + KEEP (*(.isr_stack)) + . = ALIGN(8); + _estack = .; + } /* heap section */ . = ALIGN(4); - _sheap = . ; - _eheap = ORIGIN(ram) + LENGTH(ram); + .heap (NOLOAD) : + { + _sheap = . ; + _eheap = ORIGIN(ram) + LENGTH(ram) ; + } + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } + .debug_addr 0 : { *(.debug_addr) } + .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) } + .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } /* Populate information about ram size */ _sram = ORIGIN(ram); diff --git a/cpu/cortexm_common/vectors_cortexm.c b/cpu/cortexm_common/vectors_cortexm.c index 25b9cf18cbc5..6c8c069566bd 100644 --- a/cpu/cortexm_common/vectors_cortexm.c +++ b/cpu/cortexm_common/vectors_cortexm.c @@ -43,13 +43,12 @@ * @brief Memory markers, defined in the linker script * @{ */ -extern uint32_t _sfixed; -extern uint32_t _efixed; extern uint32_t _etext; -extern uint32_t _srelocate; -extern uint32_t _erelocate; -extern uint32_t _szero; -extern uint32_t _ezero; +extern uint32_t __data_start; +extern uint32_t __data_end; +extern uint32_t __data_load_start; +extern uint32_t __bss_start; +extern uint32_t __bss_end; extern uint32_t _sstack; extern uint32_t _estack; extern uint8_t _sram; @@ -78,10 +77,9 @@ __attribute__((weak)) void post_startup (void) void reset_handler_default(void) { uint32_t *dst; - uint32_t *src = &_etext; #ifdef MODULE_PUF_SRAM - puf_sram_init((uint8_t *)&_srelocate, SEED_RAM_LEN); + puf_sram_init((uint8_t *)&__data_start, SEED_RAM_LEN); #endif pre_startup(); @@ -98,12 +96,13 @@ void reset_handler_default(void) #endif /* load data section from flash to ram */ - for (dst = &_srelocate; dst < &_erelocate; ) { + uint32_t *src = &__data_load_start; + for (dst = &__data_start; dst < &__data_end; ) { *(dst++) = *(src++); } /* default bss section to zero */ - for (dst = &_szero; dst < &_ezero; ) { - *(dst++) = 0; + for (dst = &__bss_start; dst < &__bss_end; ++dst) { + *dst = 0; } #ifdef MODULE_MPU_STACK_GUARD diff --git a/cpu/kinetis/ldscripts/kinetis.ld b/cpu/kinetis/ldscripts/kinetis.ld index 21f62364ea46..69afef317c45 100644 --- a/cpu/kinetis/ldscripts/kinetis.ld +++ b/cpu/kinetis/ldscripts/kinetis.ld @@ -30,7 +30,7 @@ MEMORY vectors : ORIGIN = _rom_start_addr, LENGTH = _vectors_length flashsec : ORIGIN = _rom_start_addr + _vectors_length, LENGTH = _flashsec_length rom (rx) : ORIGIN = _rom_start_addr + _vectors_length + _flashsec_length, LENGTH = _rom_length - (_vectors_length + _flashsec_length) - ram (!rx) : ORIGIN = _ram_start_addr, LENGTH = _ram_length + ram (w!rx) : ORIGIN = _ram_start_addr, LENGTH = _ram_length } SECTIONS diff --git a/cpu/lpc2387/ldscripts/lpc2387.ld b/cpu/lpc2387/ldscripts/lpc2387.ld index 2edb378dd3ea..2a9b0e839d5b 100644 --- a/cpu/lpc2387/ldscripts/lpc2387.ld +++ b/cpu/lpc2387/ldscripts/lpc2387.ld @@ -184,7 +184,7 @@ SECTIONS * collect all initialized .data sections that go into RAM * initial values get placed at the end of .text in flash */ - .data : AT (_etext) + .data : { . = ALIGN(4); /* ensure data is aligned so relocation can use 4-byte operations */ _data = .; /* create a global symbol marking the start of the .data section */ @@ -209,7 +209,7 @@ SECTIONS KEEP(*(SORT(.fini_array.*))) KEEP(*(.fini_array)) PROVIDE_HIDDEN (__fini_array_end = .); - } >ram /* put all the above into RAM (but load the LMA copy into FLASH) */ + } > ram AT> flash /* put all the above into RAM (but load the LMA copy into FLASH) */ . = ALIGN(4); /* ensure data is aligned so relocation can use 4-byte operations */ _edata = .; /* define a global symbol marking the end of the .data section */ diff --git a/cpu/mips_pic32_common/Makefile.include b/cpu/mips_pic32_common/Makefile.include index e0582db5dd7e..648adce56634 100644 --- a/cpu/mips_pic32_common/Makefile.include +++ b/cpu/mips_pic32_common/Makefile.include @@ -2,6 +2,8 @@ include $(RIOTCPU)/mips32r2_common/Makefile.include export INCLUDES += -I$(RIOTCPU)/mips_pic32_common/include +LINKFLAGS += -L$(RIOTCPU)/mips_pic32_common/ldscripts + USEMODULE += mips_pic32_common USEMODULE += mips_pic32_common_periph diff --git a/cpu/mips_pic32_common/ldscripts/xfa.ld b/cpu/mips_pic32_common/ldscripts/xfa.ld new file mode 100644 index 000000000000..ef5e17a9a41b --- /dev/null +++ b/cpu/mips_pic32_common/ldscripts/xfa.ld @@ -0,0 +1,21 @@ +SECTIONS +{ + .data : + { + KEEP (*(SORT(.xfa.*))) + } + _fdata = ADDR(.data); + _edata = (_fdata + SIZEOF(.data)); +} + +INSERT BEFORE .sbss; + +SECTIONS +{ + .rodata : + { + KEEP (*(SORT(.roxfa.*))) + } +} + +INSERT AFTER .dtors; diff --git a/cpu/msp430_common/Makefile.include b/cpu/msp430_common/Makefile.include index ab6e0cf8c0d3..b34ce661583b 100644 --- a/cpu/msp430_common/Makefile.include +++ b/cpu/msp430_common/Makefile.include @@ -7,6 +7,9 @@ export CFLAGS += -DCPU_MODEL_$(MODEL) export UNDEF += $(BINDIR)/msp430_common/startup.o export USEMODULE += msp430_common msp430_common_periph periph_common +# Ignore unknown pragmas (for xfa with gcc 4.6.3) +CFLAGS += -Wno-pragmas + DEFAULT_MODULE += oneway_malloc # include the msp430 common Makefile diff --git a/tests/unittests/tests-core/tests-core-xfa-data1.c b/tests/unittests/tests-core/tests-core-xfa-data1.c new file mode 100644 index 000000000000..af8af9c07828 --- /dev/null +++ b/tests/unittests/tests-core/tests-core-xfa-data1.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2018 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @addtogroup unittests + * @{ + * + * @file + * @brief Data elements for the core/xfa unit test + * + * @author Joakim Nohlgård + */ +#include "xfa.h" +#include "tests-core-xfa.h" + +XFA(xfatest, 0) xfatest_t _xfatest1 = { .val = 12345, .text = "xfatest1" }; +XFA_CONST(xfatest_const, 0) xfatest_t _xfatest_const1 = { .val = 0xcafe, .text = "xfatest_const1" }; + +XFA_INIT(xfatest_t, xfatest_use); +XFA_INIT_CONST(xfatest_t, xfatest_use_const); + +XFA(xfatest_use, 0) xfatest_t _xfatest_use1 = { .val = 3333, .text = "xfatest_use1" }; +XFA(xfatest_use, 0) xfatest_t _xfatest_use_again = { .val = 555, .text = "xfatest use again" }; +XFA_CONST(xfatest_use_const, 0) xfatest_t _xfatest_use_const1 = { .val = 4444, .text = "xfatest_use_const1" }; + +int hack1; +/** @} */ diff --git a/tests/unittests/tests-core/tests-core-xfa-data2.c b/tests/unittests/tests-core/tests-core-xfa-data2.c new file mode 100644 index 000000000000..1084cdb82735 --- /dev/null +++ b/tests/unittests/tests-core/tests-core-xfa-data2.c @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @addtogroup unittests + * @{ + * + * @file + * @brief Data elements for the core/xfa unit test + * + * @author Joakim Nohlgård + */ +#include "xfa.h" +#include "tests-core-xfa.h" + +XFA(xfatest, 0) xfatest_t _xfatest2 = { .val = 0xbeef, .text = "another test string" }; +XFA_CONST(xfatest_const, 0) xfatest_t _xfatest_const2 = { .val = 32444, .text = "const string xfa 2" }; +XFA(xfatest_use, 0) xfatest_t _xfatest_use2 = { .val = 11111, .text = "xfatest_use2" }; +XFA_CONST(xfatest_use_const, 0) xfatest_t _xfatest_use_const2 = { .val = 22222, .text = "xfatest_use_const2" }; + +int hack2; +/** @} */ diff --git a/tests/unittests/tests-core/tests-core-xfa.c b/tests/unittests/tests-core/tests-core-xfa.c new file mode 100644 index 000000000000..f21afd44627b --- /dev/null +++ b/tests/unittests/tests-core/tests-core-xfa.c @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2018 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +#include +#include "xfa.h" + +#include "embUnit.h" + +#include "tests-core.h" +#include "tests-core-xfa.h" + +extern int hack1; +extern int hack2; + +XFA_INIT(xfatest_t, xfatest); +XFA_INIT_CONST(xfatest_t, xfatest_const); +XFA_USE(xfatest_t, xfatest_use); +XFA_USE_CONST(xfatest_t, xfatest_use_const); + +/* Verifying that cross file array linking is correct by iterating over an external array */ +static void test_xfa_data(void) +{ + hack1 = hack2; + + unsigned n = XFA_LEN(xfatest_t, xfatest); + TEST_ASSERT_EQUAL_INT(2, n); + unsigned found = 0; + for (unsigned k = 0; k < n; ++k) { + /* we do not want to enforce the order of the data elements */ + switch (xfatest[k].val) { + case 12345: + /* tests-core-xfa-data1.c */ + TEST_ASSERT_EQUAL_STRING("xfatest1", xfatest[k].text); + ++found; + break; + case 0xbeef: + /* tests-core-xfa-data2.c */ + TEST_ASSERT_EQUAL_STRING("another test string", xfatest[k].text); + ++found; + break; + default: + break; + } + } + TEST_ASSERT_EQUAL_INT(n, found); +} + +static void test_xfa_const_data(void) +{ + unsigned n = XFA_LEN(xfatest_t, xfatest_const); + TEST_ASSERT_EQUAL_INT(2, n); + unsigned found = 0; + for (unsigned k = 0; k < n; ++k) { + /* we do not want to enforce the order of the data elements */ + switch (xfatest_const[k].val) { + case 0xcafe: + /* tests-core-xfa-data1.c */ + TEST_ASSERT_EQUAL_STRING("xfatest_const1", xfatest_const[k].text); + ++found; + break; + case 32444: + /* tests-core-xfa-data2.c */ + TEST_ASSERT_EQUAL_STRING("const string xfa 2", xfatest_const[k].text); + ++found; + break; + default: + break; + } + } + TEST_ASSERT_EQUAL_INT(n, found); +} + +static void test_xfa_use_data(void) +{ + unsigned n = XFA_LEN(xfatest_t, xfatest_use); + TEST_ASSERT_EQUAL_INT(3, n); + unsigned found = 0; + for (unsigned k = 0; k < n; ++k) { + /* we do not want to enforce the order of the data elements */ + switch (xfatest_use[k].val) { + case 3333: + /* tests-core-xfa-data1.c */ + TEST_ASSERT_EQUAL_STRING("xfatest_use1", xfatest_use[k].text); + ++found; + break; + case 555: + /* tests-core-xfa-data1.c */ + TEST_ASSERT_EQUAL_STRING("xfatest use again", xfatest_use[k].text); + ++found; + break; + case 11111: + /* tests-core-xfa-data2.c */ + TEST_ASSERT_EQUAL_STRING("xfatest_use2", xfatest_use[k].text); + ++found; + break; + default: + break; + } + } + TEST_ASSERT_EQUAL_INT(n, found); +} + +static void test_xfa_use_const_data(void) +{ + unsigned n = XFA_LEN(xfatest_t, xfatest_use_const); + TEST_ASSERT_EQUAL_INT(2, n); + unsigned found = 0; + for (unsigned k = 0; k < n; ++k) { + /* we do not want to enforce the order of the data elements */ + switch (xfatest_use_const[k].val) { + case 4444: + /* tests-core-xfa-data1.c */ + TEST_ASSERT_EQUAL_STRING("xfatest_use_const1", xfatest_use_const[k].text); + ++found; + break; + case 22222: + /* tests-core-xfa-data2.c */ + TEST_ASSERT_EQUAL_STRING("xfatest_use_const2", xfatest_use_const[k].text); + ++found; + break; + default: + break; + } + } + TEST_ASSERT_EQUAL_INT(n, found); +} + +Test *tests_core_xfa_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_xfa_data), + new_TestFixture(test_xfa_const_data), + new_TestFixture(test_xfa_use_data), + new_TestFixture(test_xfa_use_const_data), + }; + + EMB_UNIT_TESTCALLER(core_xfa_tests, NULL, NULL, + fixtures); + + return (Test *)&core_xfa_tests; +} diff --git a/tests/unittests/tests-core/tests-core-xfa.h b/tests/unittests/tests-core/tests-core-xfa.h new file mode 100644 index 000000000000..dc7b6b4c2354 --- /dev/null +++ b/tests/unittests/tests-core/tests-core-xfa.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @addtogroup unittests + * @{ + * + * @file + * @brief Declarations for the core/xfa unit test + * + * @author Joakim Nohlgård + */ +#ifndef TESTS_CORE_XFA_H +#define TESTS_CORE_XFA_H + +typedef struct { + unsigned val; + const char *text; +} xfatest_t; + +#endif /* TESTS_CORE_XFA_H */ + +/** @} */ diff --git a/tests/unittests/tests-core/tests-core.c b/tests/unittests/tests-core/tests-core.c index 3551286e5d6e..fe7dfe2af539 100644 --- a/tests/unittests/tests-core/tests-core.c +++ b/tests/unittests/tests-core/tests-core.c @@ -19,4 +19,5 @@ void tests_core(void) TESTS_RUN(tests_core_priority_queue_tests()); TESTS_RUN(tests_core_byteorder_tests()); TESTS_RUN(tests_core_ringbuffer_tests()); + TESTS_RUN(tests_core_xfa_tests()); } diff --git a/tests/unittests/tests-core/tests-core.h b/tests/unittests/tests-core/tests-core.h index a22a58e4d8b1..294e888fe0d4 100644 --- a/tests/unittests/tests-core/tests-core.h +++ b/tests/unittests/tests-core/tests-core.h @@ -92,6 +92,13 @@ Test *tests_core_byteorder_tests(void); */ Test *tests_core_ringbuffer_tests(void); +/** + * @brief Generates tests for xfa.h + * + * @return embUnit tests if successful, NULL if not. + */ +Test *tests_core_xfa_tests(void); + #ifdef __cplusplus } #endif diff --git a/tests/xfa/Makefile b/tests/xfa/Makefile new file mode 100644 index 000000000000..0252e6d773f1 --- /dev/null +++ b/tests/xfa/Makefile @@ -0,0 +1,18 @@ +# name of your application +APPLICATION = xfa +include ../Makefile.tests_common + +TEST_ON_CI_WHITELIST += all +test: + tests/01-run.py + +include $(RIOTBASE)/Makefile.include + +all: static-test +static-test: $(ELFFILE) + $(Q)TEST_STARTADDR=$$($(OBJDUMP) --syms $< | grep -E '\sxfatest_const$$' | awk '{ printf "0x%s", $$1}'); \ + TEST_ENDADDR=$$($(OBJDUMP) --syms $< | grep -E '\sxfatest_const_end$$' | awk '{ printf "0x%s", $$1}'); \ + if test ! $$((TEST_STARTADDR)) -lt $$((TEST_ENDADDR)); then \ + echo "Error: Static check of XFA linked const array failed, verify linker flags and try again" >&2; \ + exit 1; \ + fi diff --git a/tests/xfa/main.c b/tests/xfa/main.c new file mode 100644 index 000000000000..d771850863d8 --- /dev/null +++ b/tests/xfa/main.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015 Kaspar Schleiser + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup test + * @{ + * + * @file + * @brief cross file array (XFA) test application + * + * @author Kaspar Schleiser + * + * @} + */ + +#include +#include + +#include "xfa.h" + +#include "xfatest.h" + +XFA_INIT(xfatest_t, xfatest); +XFA_INIT_CONST(xfatest_t, xfatest_const); + +/* hack to force inclusion of otherwise unused compilation units */ +extern int hack1; +extern int hack2; + +int main(void) +{ + puts("Cross file array test"); + + unsigned n = XFA_LEN(xfatest_t, xfatest); + printf("xfatest[%u]:\n", n); + for (unsigned i = 0; i < n; i++) { + printf("[%u] = %u, \"%s\"\n", i, xfatest[i].val, xfatest[i].text); + } + n = XFA_LEN(xfatest_t, xfatest_const); + printf("xfatest_const[%u]:\n", n); + for (unsigned i = 0; i < n; i++) { + printf("[%u] = %u, \"%s\"\n", i, xfatest_const[i].val, xfatest_const[i].text); + } + + hack1 = hack2; + + return 0; +} diff --git a/tests/xfa/tests/01-run.py b/tests/xfa/tests/01-run.py new file mode 100755 index 000000000000..e19b572a2c24 --- /dev/null +++ b/tests/xfa/tests/01-run.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2018 Gaëtan Harter +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. + +import os +import sys + + +def testfunc(child): + child.expect_exact('Cross file array test') + child.expect_exact('xfatest[2]:') + child.expect_exact('[0] = 1, "xfatest1"') + child.expect_exact('[1] = 2, "xfatest2"') + child.expect_exact('xfatest_const[2]:') + child.expect_exact('[0] = 123, "xfatest_const1"') + child.expect_exact('[1] = 45, "xfatest_const2"') + + +if __name__ == "__main__": + sys.path.append(os.path.join(os.environ['RIOTTOOLS'], 'testrunner')) + from testrunner import run + exit(run(testfunc)) diff --git a/tests/xfa/xfatest.h b/tests/xfa/xfatest.h new file mode 100644 index 000000000000..1511a80e93e3 --- /dev/null +++ b/tests/xfa/xfatest.h @@ -0,0 +1,9 @@ +#ifndef XFATEST_H +#define XFATEST_H + +typedef struct { + unsigned val; + const char *text; +} xfatest_t; + +#endif /* XFATEST_H */ diff --git a/tests/xfa/xfatest1.c b/tests/xfa/xfatest1.c new file mode 100644 index 000000000000..5b6ec26c39a0 --- /dev/null +++ b/tests/xfa/xfatest1.c @@ -0,0 +1,7 @@ +#include "xfa.h" +#include "xfatest.h" + +XFA(xfatest, 0) xfatest_t _xfatest1 = { .val = 1, .text = "xfatest1" }; +XFA_CONST(xfatest_const, 0) xfatest_t _xfatest_const1 = { .val = 123, .text = "xfatest_const1" }; + +int hack1; diff --git a/tests/xfa/xfatest2.c b/tests/xfa/xfatest2.c new file mode 100644 index 000000000000..622967efce63 --- /dev/null +++ b/tests/xfa/xfatest2.c @@ -0,0 +1,7 @@ +#include "xfa.h" +#include "xfatest.h" + +XFA(xfatest, 0) xfatest_t _xfatest2 = { .val = 2, .text = "xfatest2" }; +XFA_CONST(xfatest_const, 0) xfatest_t _xfatest_const2 = { .val = 45, .text = "xfatest_const2" }; + +int hack2;