Merge pull request #15002 from kaspar030/pr/xfa_v3
core: introduce crossfile arrays (xfa) v3
This commit is contained in:
commit
15124e4769
@ -416,6 +416,10 @@ TOOLCHAINS_SUPPORTED ?= gnu
|
|||||||
# Import all toolchain settings
|
# Import all toolchain settings
|
||||||
include $(RIOTMAKE)/toolchain/$(TOOLCHAIN).inc.mk
|
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
|
# Tell ccache to pass the original file to the compiler, instead of passing the
|
||||||
# preprocessed code. Without this setting, the compilation will fail with
|
# preprocessed code. Without this setting, the compilation will fail with
|
||||||
# -Wimplicit-fallthrough warnings even when the fall through case is properly
|
# -Wimplicit-fallthrough warnings even when the fall through case is properly
|
||||||
|
|||||||
@ -59,6 +59,9 @@ else
|
|||||||
LINKFLAGS += -ldl
|
LINKFLAGS += -ldl
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# XFA (cross file array) support
|
||||||
|
LINKFLAGS += -T$(RIOTBASE)/cpu/native/ldscripts/xfa.ld
|
||||||
|
|
||||||
# clean up unused functions
|
# clean up unused functions
|
||||||
CFLAGS += -ffunction-sections -fdata-sections
|
CFLAGS += -ffunction-sections -fdata-sections
|
||||||
ifeq ($(OS),Darwin)
|
ifeq ($(OS),Darwin)
|
||||||
|
|||||||
186
core/include/xfa.h
Normal file
186
core/include/xfa.h
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @experimental This API is considered experimental and will probably change
|
||||||
|
* without notice!
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XFA_H
|
||||||
|
#define XFA_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unfortunately, current gcc trips over accessing XFA's because of their
|
||||||
|
* zero-size start/end array that are used of symbol markers, with an "array
|
||||||
|
* index out of bounds" warning. So until a solution for that is found, we
|
||||||
|
* need to disable array bounds checks for files using XFAs.
|
||||||
|
*/
|
||||||
|
#ifndef DOXYGEN
|
||||||
|
_Pragma("GCC diagnostic ignored \"-Warray-bounds\"")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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)))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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.
|
||||||
|
*
|
||||||
|
* The pragmas prevent these errors:
|
||||||
|
*
|
||||||
|
* error: ISO C forbids empty initializer braces
|
||||||
|
* error: ISO C forbids zero-size array ‘xfatest_const_end’
|
||||||
|
*
|
||||||
|
* @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 volatile type name [0] = {}; \
|
||||||
|
_XFA_CONST(name, 9_) const volatile 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.
|
||||||
|
*
|
||||||
|
* The pragmas prevent these errors:
|
||||||
|
*
|
||||||
|
* error: ISO C forbids empty initializer braces
|
||||||
|
* error: ISO C forbids zero-size array ‘xfatest_end’
|
||||||
|
*
|
||||||
|
* @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] xfa_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] xfa_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))
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
/* making externc happy */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* XFA_H */
|
||||||
|
/** @} */
|
||||||
16
cpu/atmega_common/ldscripts/xfa.ld
Normal file
16
cpu/atmega_common/ldscripts/xfa.ld
Normal file
@ -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;
|
||||||
@ -55,6 +55,7 @@ SECTIONS
|
|||||||
*(.text .text.* .gnu.linkonce.t.*)
|
*(.text .text.* .gnu.linkonce.t.*)
|
||||||
*(.glue_7t) *(.glue_7)
|
*(.glue_7t) *(.glue_7)
|
||||||
*(.rodata .rodata* .gnu.linkonce.r.*)
|
*(.rodata .rodata* .gnu.linkonce.r.*)
|
||||||
|
KEEP (*(SORT(.roxfa.*)))
|
||||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||||
|
|
||||||
/* Support C constructors, and C destructors in both user code
|
/* Support C constructors, and C destructors in both user code
|
||||||
@ -167,6 +168,7 @@ SECTIONS
|
|||||||
_srelocate = .;
|
_srelocate = .;
|
||||||
*(.ramfunc .ramfunc.*);
|
*(.ramfunc .ramfunc.*);
|
||||||
*(.data .data.*);
|
*(.data .data.*);
|
||||||
|
KEEP (*(SORT(.xfa.*)))
|
||||||
KEEP (*(.openocd .openocd.*))
|
KEEP (*(.openocd .openocd.*))
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_erelocate = .;
|
_erelocate = .;
|
||||||
|
|||||||
@ -158,6 +158,7 @@ SECTIONS
|
|||||||
_data_start = ABSOLUTE(.);
|
_data_start = ABSOLUTE(.);
|
||||||
*(.data)
|
*(.data)
|
||||||
*(.data.*)
|
*(.data.*)
|
||||||
|
KEEP (*(SORT(.xfa.*)))
|
||||||
*(.gnu.linkonce.d.*)
|
*(.gnu.linkonce.d.*)
|
||||||
*(.data1)
|
*(.data1)
|
||||||
*(.sdata)
|
*(.sdata)
|
||||||
@ -243,6 +244,7 @@ SECTIONS
|
|||||||
_rodata_start = ABSOLUTE(.);
|
_rodata_start = ABSOLUTE(.);
|
||||||
*(.rodata)
|
*(.rodata)
|
||||||
*(.rodata.*)
|
*(.rodata.*)
|
||||||
|
KEEP (*(SORT(.roxfa.*)))
|
||||||
*(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */
|
*(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */
|
||||||
*(.gnu.linkonce.r.*)
|
*(.gnu.linkonce.r.*)
|
||||||
*(.rodata1)
|
*(.rodata1)
|
||||||
|
|||||||
@ -61,9 +61,10 @@ endif
|
|||||||
|
|
||||||
ARCHIVES += -lgcc -lwpa -lcore -lnet80211 -lphy -lpp -lstdc++
|
ARCHIVES += -lgcc -lwpa -lcore -lnet80211 -lphy -lpp -lstdc++
|
||||||
|
|
||||||
LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp8266.rom.ld
|
LINKFLAGS += -L$(RIOTCPU)/$(CPU)/ld
|
||||||
LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp8266.riot-os.ld
|
LINKFLAGS += -Tesp8266.rom.ld
|
||||||
LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp8266.peripherals.ld
|
LINKFLAGS += -Tesp8266.riot-os.ld
|
||||||
|
LINKFLAGS += -Tesp8266.peripherals.ld
|
||||||
|
|
||||||
LINKFLAGS += -Wl,-wrap=pp_attach
|
LINKFLAGS += -Wl,-wrap=pp_attach
|
||||||
LINKFLAGS += -Wl,-wrap=pm_attach
|
LINKFLAGS += -Wl,-wrap=pm_attach
|
||||||
|
|||||||
@ -105,6 +105,7 @@ SECTIONS
|
|||||||
*(.sdata2.*)
|
*(.sdata2.*)
|
||||||
*(.gnu.linkonce.s2.*)
|
*(.gnu.linkonce.s2.*)
|
||||||
*(.jcr)
|
*(.jcr)
|
||||||
|
KEEP (*(SORT(.xfa.*)))
|
||||||
_data_end = ABSOLUTE(.);
|
_data_end = ABSOLUTE(.);
|
||||||
} >dram0_0_seg :dram0_0_phdr
|
} >dram0_0_seg :dram0_0_phdr
|
||||||
|
|
||||||
@ -139,6 +140,7 @@ SECTIONS
|
|||||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||||
KEEP (*(SORT(.dtors.*)))
|
KEEP (*(SORT(.dtors.*)))
|
||||||
KEEP (*(.dtors))
|
KEEP (*(.dtors))
|
||||||
|
KEEP (*(SORT(.roxfa.*)))
|
||||||
/* C++ exception handlers table: */
|
/* C++ exception handlers table: */
|
||||||
__XT_EXCEPTION_DESCS__ = ABSOLUTE(.);
|
__XT_EXCEPTION_DESCS__ = ABSOLUTE(.);
|
||||||
*(.xt_except_desc)
|
*(.xt_except_desc)
|
||||||
|
|||||||
@ -65,6 +65,7 @@ SECTIONS
|
|||||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||||
KEEP (*(SORT(.dtors.*)))
|
KEEP (*(SORT(.dtors.*)))
|
||||||
KEEP (*crtend.o(.dtors))
|
KEEP (*crtend.o(.dtors))
|
||||||
|
KEEP (*(SORT(.roxfa.*)))
|
||||||
|
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_efixed = .; /* End of text section */
|
_efixed = .; /* End of text section */
|
||||||
@ -163,6 +164,7 @@ SECTIONS
|
|||||||
*(.ramfunc .ramfunc.*);
|
*(.ramfunc .ramfunc.*);
|
||||||
*(.data .data.*);
|
*(.data .data.*);
|
||||||
KEEP (*(.openocd .openocd.*))
|
KEEP (*(.openocd .openocd.*))
|
||||||
|
KEEP (*(SORT(.xfa.*)))
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_erelocate = .;
|
_erelocate = .;
|
||||||
} > ram AT> rom
|
} > ram AT> rom
|
||||||
|
|||||||
@ -6,7 +6,6 @@ include $(RIOTCPU)/mips32r2_common/Makefile.include
|
|||||||
CFLAGS += -D_SYS__PTHREADTYPES_H_
|
CFLAGS += -D_SYS__PTHREADTYPES_H_
|
||||||
|
|
||||||
CFLAGS += -DCPU_FAM_$(call uppercase_and_underscore,$(CPU_FAM))
|
CFLAGS += -DCPU_FAM_$(call uppercase_and_underscore,$(CPU_FAM))
|
||||||
|
LINKFLAGS += -L$(RIOTCPU)/mips_pic32_common/ldscripts
|
||||||
INCLUDES += -I$(RIOTCPU)/mips_pic32_common/include
|
INCLUDES += -I$(RIOTCPU)/mips_pic32_common/include
|
||||||
|
|
||||||
DIRS += $(RIOTCPU)/$(CPU)/$(CPU_MODEL)
|
DIRS += $(RIOTCPU)/$(CPU)/$(CPU_MODEL)
|
||||||
|
|||||||
21
cpu/mips_pic32_common/ldscripts/xfa.ld
Normal file
21
cpu/mips_pic32_common/ldscripts/xfa.ld
Normal file
@ -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;
|
||||||
24
cpu/msp430_common/ldscripts/xfa.ld
Normal file
24
cpu/msp430_common/ldscripts/xfa.ld
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.rodata :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT(.roxfa.*)))
|
||||||
|
} > ROM
|
||||||
|
}
|
||||||
|
|
||||||
|
INSERT AFTER .rodata;
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT(.xfa.*)))
|
||||||
|
} > RAM AT> ROM
|
||||||
|
|
||||||
|
. = ALIGN(2);
|
||||||
|
_edata = .;
|
||||||
|
PROVIDE (edata = .);
|
||||||
|
PROVIDE (__dataend = .);
|
||||||
|
}
|
||||||
|
|
||||||
|
INSERT AFTER .data;
|
||||||
19
cpu/native/ldscripts/xfa.ld
Normal file
19
cpu/native/ldscripts/xfa.ld
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT(.xfa.*)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INSERT AFTER .text;
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.rodata :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT(.roxfa.*)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INSERT AFTER .text;
|
||||||
@ -61,6 +61,7 @@ SECTIONS
|
|||||||
*(.rdata)
|
*(.rdata)
|
||||||
*(.rodata .rodata.*)
|
*(.rodata .rodata.*)
|
||||||
*(.gnu.linkonce.r.*)
|
*(.gnu.linkonce.r.*)
|
||||||
|
KEEP (*(SORT(.roxfa.*)))
|
||||||
} >flash AT>flash :flash
|
} >flash AT>flash :flash
|
||||||
|
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
@ -182,6 +183,7 @@ SECTIONS
|
|||||||
*(.srodata.cst4)
|
*(.srodata.cst4)
|
||||||
*(.srodata.cst2)
|
*(.srodata.cst2)
|
||||||
*(.srodata .srodata.*)
|
*(.srodata .srodata.*)
|
||||||
|
KEEP (*(SORT(.xfa.*)))
|
||||||
} >ram AT>flash :ram_init
|
} >ram AT>flash :ram_init
|
||||||
|
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
|||||||
@ -9,8 +9,11 @@ CFLAGS_OPT ?= -Os
|
|||||||
|
|
||||||
CFLAGS += $(CFLAGS_CPU) $(CFLAGS_LINK) $(CFLAGS_DBG) $(CFLAGS_OPT)
|
CFLAGS += $(CFLAGS_CPU) $(CFLAGS_LINK) $(CFLAGS_DBG) $(CFLAGS_OPT)
|
||||||
ASFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG)
|
ASFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG)
|
||||||
|
|
||||||
|
# needed for xfa support. Order is important.
|
||||||
|
LINKFLAGS += -T$(RIOTCPU)/atmega_common/ldscripts/xfa.ld
|
||||||
|
|
||||||
LINKFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG) $(CFLAGS_OPT) -static -lgcc -e reset_handler -Wl,--gc-sections
|
LINKFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG) $(CFLAGS_OPT) -static -lgcc -e reset_handler -Wl,--gc-sections
|
||||||
OFLAGS += -j .text -j .data
|
|
||||||
|
|
||||||
# Use ROM_LEN and RAM_LEN during link
|
# Use ROM_LEN and RAM_LEN during link
|
||||||
$(if $(ROM_LEN),,$(error ROM_LEN is not defined))
|
$(if $(ROM_LEN),,$(error ROM_LEN is not defined))
|
||||||
|
|||||||
@ -64,6 +64,9 @@ LINKFLAGS += -L$(RIOTCPU)/$(CPU)/ldscripts
|
|||||||
LINKFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG) $(CFLAGS_OPT)
|
LINKFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG) $(CFLAGS_OPT)
|
||||||
LINKFLAGS += -Wl,--gc-sections
|
LINKFLAGS += -Wl,--gc-sections
|
||||||
|
|
||||||
|
# XFA support
|
||||||
|
LINKFLAGS += -T$(RIOTCPU)/mips_pic32_common/ldscripts/xfa.ld
|
||||||
|
|
||||||
OPTIONAL_CFLAGS_BLACKLIST += -Wformat-overflow
|
OPTIONAL_CFLAGS_BLACKLIST += -Wformat-overflow
|
||||||
OPTIONAL_CFLAGS_BLACKLIST += -Wformat-truncation
|
OPTIONAL_CFLAGS_BLACKLIST += -Wformat-truncation
|
||||||
OPTIONAL_CFLAGS_BLACKLIST += -gz
|
OPTIONAL_CFLAGS_BLACKLIST += -gz
|
||||||
|
|||||||
@ -15,6 +15,8 @@ ASFLAGS += $(CFLAGS_CPU) --defsym $(CPU_MODEL)=1 $(CFLAGS_DBG)
|
|||||||
|
|
||||||
LINKFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG) $(CFLAGS_OPT)
|
LINKFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG) $(CFLAGS_OPT)
|
||||||
LINKFLAGS += -Wl,--gc-sections -Wl,-L$(MSP430_SUPPORT_FILES)/include
|
LINKFLAGS += -Wl,--gc-sections -Wl,-L$(MSP430_SUPPORT_FILES)/include
|
||||||
|
LINKFLAGS += -T $(MSP430_SUPPORT_FILES)/include/$(CPU_MODEL).ld
|
||||||
|
LINKFLAGS += $(RIOTCPU)/msp430_common/ldscripts/xfa.ld
|
||||||
|
|
||||||
OPTIONAL_CFLAGS_BLACKLIST += -fdiagnostics-color
|
OPTIONAL_CFLAGS_BLACKLIST += -fdiagnostics-color
|
||||||
OPTIONAL_CFLAGS_BLACKLIST += -Wformat-overflow
|
OPTIONAL_CFLAGS_BLACKLIST += -Wformat-overflow
|
||||||
|
|||||||
32
tests/unittests/tests-core/tests-core-xfa-data1.c
Normal file
32
tests/unittests/tests-core/tests-core-xfa-data1.c
Normal file
@ -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 <joakim.nohlgard@eistec.se>
|
||||||
|
*/
|
||||||
|
#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;
|
||||||
|
/** @} */
|
||||||
26
tests/unittests/tests-core/tests-core-xfa-data2.c
Normal file
26
tests/unittests/tests-core/tests-core-xfa-data2.c
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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 <joakim.nohlgard@eistec.se>
|
||||||
|
*/
|
||||||
|
#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" };
|
||||||
|
|
||||||
|
/** @} */
|
||||||
144
tests/unittests/tests-core/tests-core-xfa.c
Normal file
144
tests/unittests/tests-core/tests-core-xfa.c
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* 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 <stdint.h>
|
||||||
|
#include "bitarithm.h"
|
||||||
|
#include "xfa.h"
|
||||||
|
|
||||||
|
#include "embUnit.h"
|
||||||
|
|
||||||
|
#include "tests-core.h"
|
||||||
|
#include "tests-core-xfa.h"
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
TEST_ASSERT(!(found & BIT0));
|
||||||
|
found |= BIT0;
|
||||||
|
break;
|
||||||
|
case 0xbeef:
|
||||||
|
/* tests-core-xfa-data2.c */
|
||||||
|
TEST_ASSERT_EQUAL_STRING("another test string", xfatest[k].text);
|
||||||
|
TEST_ASSERT(!(found & BIT1));
|
||||||
|
found |= BIT1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TEST_ASSERT_EQUAL_INT((1U << n) - 1, 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;
|
||||||
|
}
|
||||||
36
tests/unittests/tests-core/tests-core-xfa.h
Normal file
36
tests/unittests/tests-core/tests-core-xfa.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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 <joakim.nohlgard@eistec.se>
|
||||||
|
*/
|
||||||
|
#ifndef TESTS_CORE_XFA_H
|
||||||
|
#define TESTS_CORE_XFA_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned val;
|
||||||
|
const char *text;
|
||||||
|
} xfatest_t;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* TESTS_CORE_XFA_H */
|
||||||
|
|
||||||
|
/** @} */
|
||||||
@ -19,4 +19,5 @@ void tests_core(void)
|
|||||||
TESTS_RUN(tests_core_priority_queue_tests());
|
TESTS_RUN(tests_core_priority_queue_tests());
|
||||||
TESTS_RUN(tests_core_byteorder_tests());
|
TESTS_RUN(tests_core_byteorder_tests());
|
||||||
TESTS_RUN(tests_core_ringbuffer_tests());
|
TESTS_RUN(tests_core_ringbuffer_tests());
|
||||||
|
TESTS_RUN(tests_core_xfa_tests());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -92,6 +92,13 @@ Test *tests_core_byteorder_tests(void);
|
|||||||
*/
|
*/
|
||||||
Test *tests_core_ringbuffer_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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
12
tests/xfa/Makefile
Normal file
12
tests/xfa/Makefile
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
include ../Makefile.tests_common
|
||||||
|
|
||||||
|
include $(RIOTBASE)/Makefile.include
|
||||||
|
|
||||||
|
all: static-test
|
||||||
|
static-test: $(ELFFILE)
|
||||||
|
$(Q)TEST_STARTADDR=$$($(OBJDUMP) -t $< | grep -E '\sxfatest_const$$' | awk '{ printf "0x%s", $$1}'); \
|
||||||
|
TEST_ENDADDR=$$($(OBJDUMP) -t $< | 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
|
||||||
47
tests/xfa/main.c
Normal file
47
tests/xfa/main.c
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 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 test
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief cross file array (XFA) test application
|
||||||
|
*
|
||||||
|
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||||
|
*
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "xfa.h"
|
||||||
|
|
||||||
|
#include "xfatest.h"
|
||||||
|
|
||||||
|
XFA_INIT(xfatest_t, xfatest);
|
||||||
|
XFA_INIT_CONST(xfatest_t, xfatest_const);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
26
tests/xfa/tests/01-run.py
Executable file
26
tests/xfa/tests/01-run.py
Executable file
@ -0,0 +1,26 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Copyright (C) 2021 Freie Universität Berlin
|
||||||
|
# 2021 Inria
|
||||||
|
# 2021 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.
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from testrunner import run
|
||||||
|
|
||||||
|
|
||||||
|
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.exit(run(testfunc))
|
||||||
29
tests/xfa/xfatest.h
Normal file
29
tests/xfa/xfatest.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XFATEST_H
|
||||||
|
#define XFATEST_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DOXYGEN /* just a test header, please ignore */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned val;
|
||||||
|
const char *text;
|
||||||
|
} xfatest_t;
|
||||||
|
|
||||||
|
#endif /* DOXYGEN */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* XFATEST_H */
|
||||||
5
tests/xfa/xfatest1.c
Normal file
5
tests/xfa/xfatest1.c
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#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" };
|
||||||
5
tests/xfa/xfatest2.c
Normal file
5
tests/xfa/xfatest2.c
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#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" };
|
||||||
Loading…
x
Reference in New Issue
Block a user