Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions core/include/xfa.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de>
*
* 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 <kaspar@schleiser.de>
*/

#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 Define a 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\"") \
const _XFA(name, 0_) type name [0] = {}; \
const _XFA(name, 9_) type name ## _end [0] = {}; \
_Pragma("GCC diagnostic pop") \
extern unsigned __xfa_dummy
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this dummy required?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without the dummy, gcc complains about an extra ;:

 XFA_INIT(xfatest_t, xfatest);```


/**
* @brief Declare an external 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 const type name [0]; \
extern const type name ## _end [0];

/**
* @brief Define variable in 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 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(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) (((char*)name ## _end - (char*)name)/sizeof(type))

/** @} */
#endif /* XFA_H */
265 changes: 265 additions & 0 deletions cpu/atmega2560/ldscripts/atmega2560.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
/* Script for -n: mix text and data on same page */
/* Copyright (C) 2014-2016 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-avr","elf32-avr","elf32-avr")
OUTPUT_ARCH(avr:6)
__TEXT_REGION_LENGTH__ = DEFINED(__TEXT_REGION_LENGTH__) ? __TEXT_REGION_LENGTH__ : 1024K;
__DATA_REGION_LENGTH__ = DEFINED(__DATA_REGION_LENGTH__) ? __DATA_REGION_LENGTH__ : 0xfe00;
__EEPROM_REGION_LENGTH__ = DEFINED(__EEPROM_REGION_LENGTH__) ? __EEPROM_REGION_LENGTH__ : 64K;
__FUSE_REGION_LENGTH__ = DEFINED(__FUSE_REGION_LENGTH__) ? __FUSE_REGION_LENGTH__ : 1K;
__LOCK_REGION_LENGTH__ = DEFINED(__LOCK_REGION_LENGTH__) ? __LOCK_REGION_LENGTH__ : 1K;
__SIGNATURE_REGION_LENGTH__ = DEFINED(__SIGNATURE_REGION_LENGTH__) ? __SIGNATURE_REGION_LENGTH__ : 1K;
__USER_SIGNATURE_REGION_LENGTH__ = DEFINED(__USER_SIGNATURE_REGION_LENGTH__) ? __USER_SIGNATURE_REGION_LENGTH__ : 1K;
MEMORY
{
text (rx) : ORIGIN = 0, LENGTH = __TEXT_REGION_LENGTH__
data (rw!x) : ORIGIN = 0x800200, LENGTH = __DATA_REGION_LENGTH__
eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = __EEPROM_REGION_LENGTH__
fuse (rw!x) : ORIGIN = 0x820000, LENGTH = __FUSE_REGION_LENGTH__
lock (rw!x) : ORIGIN = 0x830000, LENGTH = __LOCK_REGION_LENGTH__
signature (rw!x) : ORIGIN = 0x840000, LENGTH = __SIGNATURE_REGION_LENGTH__
user_signatures (rw!x) : ORIGIN = 0x850000, LENGTH = __USER_SIGNATURE_REGION_LENGTH__
}
SECTIONS
{
/* Read-only sections, merged into text segment: */
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rel.init : { *(.rel.init) }
.rela.init : { *(.rela.init) }
.rel.text :
{
*(.rel.text)
*(.rel.text.*)
*(.rel.gnu.linkonce.t*)
}
.rela.text :
{
*(.rela.text)
*(.rela.text.*)
*(.rela.gnu.linkonce.t*)
}
.rel.fini : { *(.rel.fini) }
.rela.fini : { *(.rela.fini) }
.rel.rodata :
{
*(.rel.rodata)
*(.rel.rodata.*)
*(.rel.gnu.linkonce.r*)
}
.rela.rodata :
{
*(.rela.rodata)
*(.rela.rodata.*)
*(.rela.gnu.linkonce.r*)
}
.rel.data :
{
*(.rel.data)
*(.rel.data.*)
*(.rel.gnu.linkonce.d*)
}
.rela.data :
{
*(.rela.data)
*(.rela.data.*)
*(.rela.gnu.linkonce.d*)
}
.rel.ctors : { *(.rel.ctors) }
.rela.ctors : { *(.rela.ctors) }
.rel.dtors : { *(.rel.dtors) }
.rela.dtors : { *(.rela.dtors) }
.rel.got : { *(.rel.got) }
.rela.got : { *(.rela.got) }
.rel.bss : { *(.rel.bss) }
.rela.bss : { *(.rela.bss) }
.rel.plt : { *(.rel.plt) }
.rela.plt : { *(.rela.plt) }
/* Internal text space or external memory. */
.text :
{
*(.vectors)
KEEP(*(.vectors))
/* For data that needs to reside in the lower 64k of progmem. */
*(.progmem.gcc*)
/* PR 13812: Placing the trampolines here gives a better chance
that they will be in range of the code that uses them. */
. = ALIGN(2);
__trampolines_start = . ;
/* The jump trampolines for the 16-bit limited relocs will reside here. */
*(.trampolines)
*(.trampolines*)
__trampolines_end = . ;
/* avr-libc expects these data to reside in lower 64K. */
*libprintf_flt.a:*(.progmem.data)
*libc.a:*(.progmem.data)
*(.progmem*)
. = ALIGN(2);
/* For future tablejump instruction arrays for 3 byte pc devices.
We don't relax jump/call instructions within these sections. */
*(.jumptables)
*(.jumptables*)
/* For code that needs to reside in the lower 128k progmem. */
*(.lowtext)
*(.lowtext*)
__ctors_start = . ;
*(.ctors)
__ctors_end = . ;
__dtors_start = . ;
*(.dtors)
__dtors_end = . ;
KEEP(SORT(*)(.ctors))
KEEP(SORT(*)(.dtors))
/* From this point on, we don't bother about wether the insns are
below or above the 16 bits boundary. */
*(.init0) /* Start here after reset. */
KEEP (*(.init0))
*(.init1)
KEEP (*(.init1))
*(.init2) /* Clear __zero_reg__, set up stack pointer. */
KEEP (*(.init2))
*(.init3)
KEEP (*(.init3))
*(.init4) /* Initialize data and BSS. */
KEEP (*(.init4))
*(.init5)
KEEP (*(.init5))
*(.init6) /* C++ constructors. */
KEEP (*(.init6))
*(.init7)
KEEP (*(.init7))
*(.init8)
KEEP (*(.init8))
*(.init9) /* Call main(). */
KEEP (*(.init9))
*(.text)
. = ALIGN(2);
*(.text.*)
. = ALIGN(2);
*(.fini9) /* _exit() starts here. */
KEEP (*(.fini9))
*(.fini8)
KEEP (*(.fini8))
*(.fini7)
KEEP (*(.fini7))
*(.fini6) /* C++ destructors. */
KEEP (*(.fini6))
*(.fini5)
KEEP (*(.fini5))
*(.fini4)
KEEP (*(.fini4))
*(.fini3)
KEEP (*(.fini3))
*(.fini2)
KEEP (*(.fini2))
*(.fini1)
KEEP (*(.fini1))
*(.fini0) /* Infinite loop after program termination. */
KEEP (*(.fini0))

_etext = . ;
} > text
.data :
{
PROVIDE (__data_start = .) ;
*(.data)
*(.data*)
*(.rodata) /* We need to include .rodata here if gcc is used */
*(.rodata*) /* with -fdata-sections. */
*(.gnu.linkonce.d*)

. = ALIGN(2);
KEEP (*(SORT(.xfa.*)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You will need to define that in every cpu's ldscript. Maybe you could put it in a "linked" single ldscript. The main problem of what I propose is that every cpu's ldscript need to have the same interface (define the same memory areas, output sections...), which is currently not the case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In your branch, you have 2 different scripts, and I think it could be more than ok to have different ways on doing it for cpus familys.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have 2 different scripts because the linker scripts interfaces are not the same. But the features are the same. While it is ok to have differents ways to do something, it may be nice to not copy/past the same way everywhere.

KEEP (*(.xfa))

. = ALIGN(2);
_edata = . ;
PROVIDE (__data_end = .) ;
} > data AT> text
.bss ADDR(.data) + SIZEOF (.data) : AT (ADDR (.bss))
{
PROVIDE (__bss_start = .) ;
*(.bss)
*(.bss*)
*(COMMON)
PROVIDE (__bss_end = .) ;
} > data
__data_load_start = LOADADDR(.data);
__data_load_end = __data_load_start + SIZEOF(.data);
/* Global data not cleared after reset. */
.noinit ADDR(.bss) + SIZEOF (.bss) : AT (ADDR (.noinit))
{
PROVIDE (__noinit_start = .) ;
*(.noinit*)
PROVIDE (__noinit_end = .) ;
_end = . ;
PROVIDE (__heap_start = .) ;
} > data
.eeprom :
{
/* See .data above... */
KEEP(*(.eeprom*))
__eeprom_end = . ;
} > eeprom
.fuse :
{
KEEP(*(.fuse))
KEEP(*(.lfuse))
KEEP(*(.hfuse))
KEEP(*(.efuse))
} > fuse
.lock :
{
KEEP(*(.lock*))
} > lock
.signature :
{
KEEP(*(.signature*))
} > signature
/* 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) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
/* 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) }
}

4 changes: 3 additions & 1 deletion cpu/atmega_common/Makefile.include
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ export CFLAGS_OPT ?= -Os

export CFLAGS += $(CFLAGS_CPU) $(CFLAGS_LINK) $(CFLAGS_DBG) $(CFLAGS_OPT)
export ASFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG)
export LINKFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG) $(CFLAGS_OPT) -static -lgcc -e reset_handler -Wl,--gc-sections

LINKER_SCRIPT := -T${RIOTBASE}/cpu/${CPU}/ldscripts/${CPU}.ld
export LINKFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG) $(CFLAGS_OPT) ${LINKER_SCRIPT} -static -lgcc -e reset_handler -Wl,--gc-sections

# export the peripheral drivers to be linked into the final binary
export USEMODULE += atmega_common_periph
Expand Down
4 changes: 4 additions & 0 deletions cpu/cortexm_common/ldscripts/cortexm_base.ld
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ SECTIONS
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))

. = ALIGN(4);
KEEP (*(SORT(.xfa.*)))
KEEP (*(.xfa))

. = ALIGN(4);
_efixed = .; /* End of text section */
} > rom
Expand Down
2 changes: 2 additions & 0 deletions cpu/native/Makefile.include
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ endif
USEMODULE += periph
USEMODULE += periph_uart

LINKFLAGS += -T$(RIOTCPU)/native/ldscripts/xfa.ld

ifeq ($(shell uname -s),Darwin)
export CFLAGS += -D_XOPEN_SOURCE=600 -D_DARWIN_C_SOURCE
endif
Loading