diff --git a/CMakeLists.txt b/CMakeLists.txt
index e297ef57..2457bab5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -63,6 +63,7 @@ endif()
configure_file(conf/kernel.h ${CMAKE_BINARY_DIR}/conf/kernel.h)
add_subdirectory(src)
+add_subdirectory(ld)
if (NOT UNIT_TESTING_BUILD)
# Testsuite contains HIL tests. This is only relevant
# in native build.
diff --git a/ld/CMakeLists.txt b/ld/CMakeLists.txt
new file mode 100644
index 00000000..b74804fc
--- /dev/null
+++ b/ld/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_test(
+ NAME genlink-cmsis
+ COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/tests/genlink-cmsis.sh ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ )
\ No newline at end of file
diff --git a/ld/tests/data/README.txt b/ld/tests/data/README.txt
new file mode 100644
index 00000000..84109e0b
--- /dev/null
+++ b/ld/tests/data/README.txt
@@ -0,0 +1 @@
+Linker scripts collected from various HALs published on the Internet
\ No newline at end of file
diff --git a/ld/tests/data/STM32G491CCUx_FLASH.ld b/ld/tests/data/STM32G491CCUx_FLASH.ld
new file mode 100644
index 00000000..bea404b3
--- /dev/null
+++ b/ld/tests/data/STM32G491CCUx_FLASH.ld
@@ -0,0 +1,189 @@
+/*
+******************************************************************************
+**
+
+** File : LinkerScript.ld
+**
+** Author : STM32CubeMX
+**
+** Abstract : Linker script for STM32G491CCUx series
+** 256Kbytes FLASH and 112Kbytes RAM
+**
+** Set heap size, stack size and stack location according
+** to application requirements.
+**
+** Set memory bank area and size if external memory is used.
+**
+** Target : STMicroelectronics STM32
+**
+** Distribution: The file is distributed “as is,” without any warranty
+** of any kind.
+**
+*****************************************************************************
+** @attention
+**
+**
© COPYRIGHT(c) 2019 STMicroelectronics
+**
+** Redistribution and use in source and binary forms, with or without modification,
+** are permitted provided that the following conditions are met:
+** 1. Redistributions of source code must retain the above copyright notice,
+** this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright notice,
+** this list of conditions and the following disclaimer in the documentation
+** and/or other materials provided with the distribution.
+** 3. Neither the name of STMicroelectronics nor the names of its contributors
+** may be used to endorse or promote products derived from this software
+** without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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.
+**
+*****************************************************************************
+*/
+
+/* Entry Point */
+ENTRY(Reset_Handler)
+
+/* Highest address of the user mode stack */
+_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of RAM */
+/* Generate a link error if heap and stack don't fit into RAM */
+_Min_Heap_Size = 0x200; /* required amount of heap */
+_Min_Stack_Size = 0x400; /* required amount of stack */
+
+/* Specify the memory areas */
+MEMORY
+{
+RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 112K
+FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 256K
+}
+
+/* Define output sections */
+SECTIONS
+{
+ /* The startup code goes first into FLASH */
+ .isr_vector :
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector)) /* Startup code */
+ . = ALIGN(4);
+ } >FLASH
+
+ /* The program code and other data goes into FLASH */
+ .text :
+ {
+ . = ALIGN(4);
+ *(.text) /* .text sections (code) */
+ *(.text*) /* .text* sections (code) */
+ *(.glue_7) /* glue arm to thumb code */
+ *(.glue_7t) /* glue thumb to arm code */
+ *(.eh_frame)
+
+ KEEP (*(.init))
+ KEEP (*(.fini))
+
+ . = ALIGN(4);
+ _etext = .; /* define a global symbols at end of code */
+ } >FLASH
+
+ /* Constant data goes into FLASH */
+ .rodata :
+ {
+ . = ALIGN(4);
+ *(.rodata) /* .rodata sections (constants, strings, etc.) */
+ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
+ . = ALIGN(4);
+ } >FLASH
+
+ .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
+ .ARM : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >FLASH
+
+ .preinit_array :
+ {
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array*))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ } >FLASH
+ .init_array :
+ {
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array*))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ } >FLASH
+ .fini_array :
+ {
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(SORT(.fini_array.*)))
+ KEEP (*(.fini_array*))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ } >FLASH
+
+ /* used by the startup to initialize data */
+ _sidata = LOADADDR(.data);
+
+ /* Initialized data sections goes into RAM, load LMA copy after code */
+ .data :
+ {
+ . = ALIGN(4);
+ _sdata = .; /* create a global symbol at data start */
+ *(.data) /* .data sections */
+ *(.data*) /* .data* sections */
+
+ . = ALIGN(4);
+ _edata = .; /* define a global symbol at data end */
+ } >RAM AT> FLASH
+
+
+ /* Uninitialized data section */
+ . = ALIGN(4);
+ .bss :
+ {
+ /* This is used by the startup in order to initialize the .bss secion */
+ _sbss = .; /* define a global symbol at bss start */
+ __bss_start__ = _sbss;
+ *(.bss)
+ *(.bss*)
+ *(COMMON)
+
+ . = ALIGN(4);
+ _ebss = .; /* define a global symbol at bss end */
+ __bss_end__ = _ebss;
+ } >RAM
+
+ /* User_heap_stack section, used to check that there is enough RAM left */
+ ._user_heap_stack :
+ {
+ . = ALIGN(8);
+ PROVIDE ( end = . );
+ PROVIDE ( _end = . );
+ . = . + _Min_Heap_Size;
+ . = . + _Min_Stack_Size;
+ . = ALIGN(8);
+ } >RAM
+
+
+
+ /* Remove information from the standard libraries */
+ /DISCARD/ :
+ {
+ libc.a ( * )
+ libm.a ( * )
+ libgcc.a ( * )
+ }
+
+ .ARM.attributes 0 : { *(.ARM.attributes) }
+}
+
+
diff --git a/ld/tests/data/max32690_rom.ld b/ld/tests/data/max32690_rom.ld
new file mode 100644
index 00000000..c7be09f9
--- /dev/null
+++ b/ld/tests/data/max32690_rom.ld
@@ -0,0 +1,253 @@
+/*******************************************************************************
+ * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
+ * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Maxim Integrated
+ * Products, Inc. shall not be used except as stated in the Maxim Integrated
+ * Products, Inc. Branding Policy.
+ *
+ * The mere transfer of this software does not imply any licenses
+ * of trade secrets, proprietary technology, copyrights, patents,
+ * trademarks, maskwork rights, or any other form of intellectual
+ * property whatsoever. Maxim Integrated Products, Inc. retains all
+ * ownership rights.
+ *
+ * $Date: 2016-05-02 14:15:59 -0700 (Mon, 02 May 2016) $
+ * $Revision: 22594 $
+ *
+ ******************************************************************************/
+
+MEMORY {
+ ROM (rx) : ORIGIN = 0x00000000, LENGTH = 0x00020000 /* 128kB ROM */
+ FLASH (rx) : ORIGIN = 0x10000000, LENGTH = 0x00300000 /* 3MB flash */
+ /* 152Kx32 total size of RAMS 0-10 (608Kbytes). */
+ /* 38Kx32 total size of RAMs 11-21 for optional ECC (152Kbytes) */
+ /* NOTE 1: The MAX32690 has Error correcting RAM which removes 152KByte of usable RAM from the memory map. */
+ /* NOTE 2: The MAX32690 has ? RAM sizes, ?KByte and ?KByte. */
+ /* NOTE 3: Because of NOTE 1 and NOTE 2, the ROM will only use the lower 608KByte (760KByte-152KByte) */
+ SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00120000 /* 1152kB SRAM */
+}
+
+OUTPUT_FORMAT ("elf32-littlearm")
+ENTRY(Reset_Handler)
+EXTERN(__start_c main __stack __section_end_heap)
+
+SECTIONS {
+
+ .text : ALIGN(0x100)
+ {
+ _text = .;
+ __section_load_nvic = .;
+ KEEP(*(.isr_vector))
+ __section_load_nvic_end = .;
+
+ KEEP(*startup*(.text))
+ *(.text*) /* program code */
+ *(.flashprog*) /* Flash program */
+ KEEP(*(.init))
+ KEEP(*(.fini))
+ *(.rodata*) /* read-only data: "const" */
+ KEEP(*(.elsa_rom_params))
+
+ /* C++ Exception handling */
+ KEEP(*(.eh_frame*))
+ _etext = .;
+ } > ROM
+
+ __section_nvic_size = __section_load_nvic_end - __section_load_nvic;
+ __section_nvic_start = ORIGIN(SRAM);
+ __section_nvic_end = __section_nvic_start + __section_nvic_size;
+
+ /* it's used for C++ exception handling */
+ /* we need to keep this to avoid overlapping */
+ .ARM.exidx :
+ {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } > ROM
+
+ .data __section_nvic_end : ALIGN(0x10)
+ {
+ _data = ALIGN(., 4);
+ *(.data*) /*read-write initialized data: initialized global variable*/
+ *(.spix_config*) /* SPIX configuration functions need to be run from SRAM */
+
+ /* These array sections are used by __libc_init_array to call static C++ constructors */
+ . = ALIGN(4);
+ /* preinit data */
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP(*(.preinit_array))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+
+ . = ALIGN(4);
+ /* init data */
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP(*(SORT(.init_array.*)))
+ KEEP(*(.init_array))
+ PROVIDE_HIDDEN (__init_array_end = .);
+
+ . = ALIGN(4);
+ /* finit data */
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP(*(SORT(.fini_array.*)))
+ KEEP(*(.fini_array))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+
+ _edata = ALIGN(., 4);
+ } > SRAM AT>ROM
+ __load_data = LOADADDR(.data);
+
+ /* ROM CRC */
+ .checksum.rom : ALIGN(0x10)
+ {
+ . += 4;
+ } >ROM
+
+ .bss :
+ {
+ . = ALIGN(4);
+ _bss = .;
+ *(.bss*) /*read-write zero initialized data: uninitialzed global variable*/
+ *(COMMON)
+ _ebss = ALIGN(., 4);
+ } > SRAM
+
+ /* Set stack top to end of RAM, and stack limit move down by
+ * size of stack_dummy section */
+
+ /* .stack_dummy section doesn't contains any symbols. It is only
+ * used for linker to calculate size of stack sections, and assign
+ * values to stack symbols later */
+
+ /* Stack and Heap */
+ .heap (NOLOAD) : ALIGN(0x80)
+ {
+ __section_start_heap = .;
+ *(.heap*)
+ __section_end_heap = .;
+
+ } > SRAM
+
+ __section_start_heap_va = __section_start_heap;
+ __section_end_heap_va = __section_start_heap_va + SIZEOF(.heap);
+
+ .stack __section_end_heap : ALIGN(0x80)
+ {
+ __section_start_stack = .;
+ *(.stack*)
+ _stack = .;
+ __section_end_stack = .;
+
+ } > SRAM
+ __stack_va = __stack;
+
+ PROVIDE(__stack = _stack);
+ __virtual_start_elsa = __section_end_stack;
+
+ /* ======================================================================== */
+ /** RAM for STP and SCP **/
+ __section_protocol_ram_end = (ORIGIN(SRAM) + LENGTH(SRAM));
+ __region_end_ram = (ORIGIN(SRAM) + LENGTH(SRAM));
+
+ /** Cryptography work buffer */
+ .elsa_work.sh __virtual_start_elsa : ALIGN(0x10)
+ {
+ KEEP(*(.elsa_work.sh))
+ } >SRAM=0
+
+ __elsa_work_sh_start = LOADADDR(.elsa_work.sh);
+ __elsa_work_sh_end = LOADADDR(.elsa_work.sh) + SIZEOF(.elsa_work.sh);
+ __elsa_work_sh_size = SIZEOF(.elsa_work.sh);
+
+ /** Configuration Management work buffer */
+ .elsa_work.cm __elsa_work_sh_end : ALIGN(0x10)
+ {
+ KEEP(*(.elsa_work.cm))
+ } >SRAM=0
+
+ __elsa_work_cm_start = LOADADDR(.elsa_work.cm);
+ __elsa_work_cm_end = LOADADDR(.elsa_work.cm) + SIZEOF(.elsa_work.cm);
+ __elsa_work_cm_size = SIZEOF(.elsa_work.cm);
+
+ /** RCE Signature check work buffer */
+ .elsa_work.rce __elsa_work_cm_end : ALIGN(0x10)
+ {
+ KEEP(*(.elsa_work.rce))
+
+ } >SRAM=0
+
+ __elsa_work_rce_start = LOADADDR(.elsa_work.rce);
+ __elsa_work_rce_end = LOADADDR(.elsa_work.rce) + SIZEOF(.elsa_work.rce);
+ __elsa_work_rce_size = SIZEOF(.elsa_work.rce);
+
+ /* ======================================================================== */
+
+ /** STP Application, SCP Applet memory areas */
+ .protocol_ram.stack __elsa_work_rce_end : ALIGN(0x10)
+ {
+ __section_protocol_start = .;
+ /** Stack dedicated to STP/SCP application matter if needed */
+ __section_start_stp_stack = .;
+ KEEP(*(.protocol_ram.stack))
+ /* . += __stack_size_stp;*/
+ __stack_stp = .;
+
+ } >SRAM
+ __section_end_stp_stack = .;
+
+ .protocol_ram.bss __section_end_stp_stack : ALIGN(0x10)
+ {
+ *stp_*(.bss .bss.* .gnu.linkonce.b.*)
+
+ } >SRAM
+
+ __section_start_bss_stp = LOADADDR(.protocol_ram.bss);
+ __section_end_bss_stp = LOADADDR(.protocol_ram.bss) + SIZEOF(.protocol_ram.bss);
+ __section_bss_stp_size = SIZEOF(.protocol_ram.bss);
+
+ .protocol_ram __section_end_bss_stp : ALIGN(0x10)
+ {
+ /** Code part */
+ KEEP(*stp_*(.data .data.* .gnu.linkonce.d.*))
+ KEEP(*(.protocol_ram))
+
+ } >SRAM
+ __section_protocol_end = ALIGN(0x10);
+ __scp_applet_area_size = __section_protocol_ram_end - __section_protocol_end;
+
+ /** Lasting free internal SRAM space */
+ .elsa_scp_applet __section_protocol_end : ALIGN(0x10)
+ {
+ __scp_applet_start = .;
+ . += __scp_applet_area_size;
+ __scp_applet_end = .;
+
+ } >SRAM
+
+ __section_scp_start = LOADADDR(.protocol_ram);
+ __section_scp_stop = LOADADDR(.elsa_scp_applet) + SIZEOF(.elsa_scp_applet);
+
+ __section_bss_size_stp = __section_end_bss_stp - __section_start_bss_stp;
+ __section_stp_size = SIZEOF(.protocol_ram.stack) + SIZEOF(.protocol_ram.bss) + SIZEOF(.protocol_ram);
+
+ /* Check if data + heap + stack exceeds RAM limit */
+ ASSERT(__StackLimit >= _ebss, "region RAM overflowed with stack")
+}
diff --git a/ld/tests/data/rp2040_default.ld b/ld/tests/data/rp2040_default.ld
new file mode 100644
index 00000000..51254012
--- /dev/null
+++ b/ld/tests/data/rp2040_default.ld
@@ -0,0 +1,286 @@
+/* Based on GCC ARM embedded samples.
+ Defines the following symbols for use by code:
+ __exidx_start
+ __exidx_end
+ __etext
+ __data_start__
+ __preinit_array_start
+ __preinit_array_end
+ __init_array_start
+ __init_array_end
+ __fini_array_start
+ __fini_array_end
+ __data_end__
+ __bss_start__
+ __bss_end__
+ __end__
+ end
+ __HeapLimit
+ __StackLimit
+ __StackTop
+ __stack (== StackTop)
+*/
+
+MEMORY
+{
+ INCLUDE "pico_flash_region.ld"
+ RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k
+ SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k
+ SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k
+}
+
+ENTRY(_entry_point)
+
+SECTIONS
+{
+ /* Second stage bootloader is prepended to the image. It must be 256 bytes big
+ and checksummed. It is usually built by the boot_stage2 target
+ in the Raspberry Pi Pico SDK
+ */
+
+ .flash_begin : {
+ __flash_binary_start = .;
+ } > FLASH
+
+ .boot2 : {
+ __boot2_start__ = .;
+ KEEP (*(.boot2))
+ __boot2_end__ = .;
+ } > FLASH
+
+ ASSERT(__boot2_end__ - __boot2_start__ == 256,
+ "ERROR: Pico second stage bootloader must be 256 bytes in size")
+
+ /* The second stage will always enter the image at the start of .text.
+ The debugger will use the ELF entry point, which is the _entry_point
+ symbol if present, otherwise defaults to start of .text.
+ This can be used to transfer control back to the bootrom on debugger
+ launches only, to perform proper flash setup.
+ */
+
+ .text : {
+ __logical_binary_start = .;
+ KEEP (*(.vectors))
+ KEEP (*(.binary_info_header))
+ __binary_info_header_end = .;
+ KEEP (*(.embedded_block))
+ __embedded_block_end = .;
+ KEEP (*(.reset))
+ /* TODO revisit this now memset/memcpy/float in ROM */
+ /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from
+ * FLASH ... we will include any thing excluded here in .data below by default */
+ *(.init)
+ *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*)
+ *(.fini)
+ /* Pull all c'tors into .text */
+ *crtbegin.o(.ctors)
+ *crtbegin?.o(.ctors)
+ *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
+ *(SORT(.ctors.*))
+ *(.ctors)
+ /* Followed by destructors */
+ *crtbegin.o(.dtors)
+ *crtbegin?.o(.dtors)
+ *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
+ *(SORT(.dtors.*))
+ *(.dtors)
+
+ . = ALIGN(4);
+ /* preinit data */
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP(*(SORT(.preinit_array.*)))
+ KEEP(*(.preinit_array))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+
+ . = ALIGN(4);
+ /* init data */
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP(*(SORT(.init_array.*)))
+ KEEP(*(.init_array))
+ PROVIDE_HIDDEN (__init_array_end = .);
+
+ . = ALIGN(4);
+ /* finit data */
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ *(SORT(.fini_array.*))
+ *(.fini_array)
+ PROVIDE_HIDDEN (__fini_array_end = .);
+
+ *(.eh_frame*)
+ . = ALIGN(4);
+ } > FLASH
+
+ .rodata : {
+ *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*)
+ . = ALIGN(4);
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*)))
+ . = ALIGN(4);
+ } > FLASH
+
+ .ARM.extab :
+ {
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ } > FLASH
+
+ __exidx_start = .;
+ .ARM.exidx :
+ {
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ } > FLASH
+ __exidx_end = .;
+
+ /* Machine inspectable binary information */
+ . = ALIGN(4);
+ __binary_info_start = .;
+ .binary_info :
+ {
+ KEEP(*(.binary_info.keep.*))
+ *(.binary_info.*)
+ } > FLASH
+ __binary_info_end = .;
+ . = ALIGN(4);
+
+ .ram_vector_table (NOLOAD): {
+ *(.ram_vector_table)
+ } > RAM
+
+ .uninitialized_data (NOLOAD): {
+ . = ALIGN(4);
+ *(.uninitialized_data*)
+ } > RAM
+
+ .data : {
+ __data_start__ = .;
+ *(vtable)
+
+ *(.time_critical*)
+
+ /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */
+ *(.text*)
+ . = ALIGN(4);
+ *(.rodata*)
+ . = ALIGN(4);
+
+ *(.data*)
+
+ . = ALIGN(4);
+ *(.after_data.*)
+ . = ALIGN(4);
+ /* preinit data */
+ PROVIDE_HIDDEN (__mutex_array_start = .);
+ KEEP(*(SORT(.mutex_array.*)))
+ KEEP(*(.mutex_array))
+ PROVIDE_HIDDEN (__mutex_array_end = .);
+
+ . = ALIGN(4);
+ *(.jcr)
+ . = ALIGN(4);
+ } > RAM AT> FLASH
+
+ .tdata : {
+ . = ALIGN(4);
+ *(.tdata .tdata.* .gnu.linkonce.td.*)
+ /* All data end */
+ __tdata_end = .;
+ } > RAM AT> FLASH
+ PROVIDE(__data_end__ = .);
+
+ /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */
+ __etext = LOADADDR(.data);
+
+ .tbss (NOLOAD) : {
+ . = ALIGN(4);
+ __bss_start__ = .;
+ __tls_base = .;
+ *(.tbss .tbss.* .gnu.linkonce.tb.*)
+ *(.tcommon)
+
+ __tls_end = .;
+ } > RAM
+
+ .bss (NOLOAD) : {
+ . = ALIGN(4);
+ __tbss_end = .;
+
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*)))
+ *(COMMON)
+ . = ALIGN(4);
+ __bss_end__ = .;
+ } > RAM
+
+ .heap (NOLOAD):
+ {
+ __end__ = .;
+ end = __end__;
+ KEEP(*(.heap*))
+ } > RAM
+ /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, however
+ to be more compatible, we now set __HeapLimit explicitly to where the end of the heap is */
+ __HeapLimit = ORIGIN(RAM) + LENGTH(RAM);
+
+ /* Start and end symbols must be word-aligned */
+ .scratch_x : {
+ __scratch_x_start__ = .;
+ *(.scratch_x.*)
+ . = ALIGN(4);
+ __scratch_x_end__ = .;
+ } > SCRATCH_X AT > FLASH
+ __scratch_x_source__ = LOADADDR(.scratch_x);
+
+ .scratch_y : {
+ __scratch_y_start__ = .;
+ *(.scratch_y.*)
+ . = ALIGN(4);
+ __scratch_y_end__ = .;
+ } > SCRATCH_Y AT > FLASH
+ __scratch_y_source__ = LOADADDR(.scratch_y);
+
+ /* .stack*_dummy section doesn't contains any symbols. It is only
+ * used for linker to calculate size of stack sections, and assign
+ * values to stack symbols later
+ *
+ * stack1 section may be empty/missing if platform_launch_core1 is not used */
+
+ /* by default we put core 0 stack at the end of scratch Y, so that if core 1
+ * stack is not used then all of SCRATCH_X is free.
+ */
+ .stack1_dummy (NOLOAD):
+ {
+ *(.stack1*)
+ } > SCRATCH_X
+ .stack_dummy (NOLOAD):
+ {
+ KEEP(*(.stack*))
+ } > SCRATCH_Y
+
+ .flash_end : {
+ KEEP(*(.embedded_end_block*))
+ PROVIDE(__flash_binary_end = .);
+ } > FLASH
+
+ /* stack limit is poorly named, but historically is maximum heap ptr */
+ __StackLimit = ORIGIN(RAM) + LENGTH(RAM);
+ __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X);
+ __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y);
+ __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy);
+ __StackBottom = __StackTop - SIZEOF(.stack_dummy);
+ PROVIDE(__stack = __StackTop);
+
+ /* picolibc and LLVM */
+ PROVIDE (__heap_start = __end__);
+ PROVIDE (__heap_end = __HeapLimit);
+ PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) );
+ PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1));
+ PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) );
+
+ /* llvm-libc */
+ PROVIDE (_end = __end__);
+ PROVIDE (__llvm_libc_heap_limit = __HeapLimit);
+
+ /* Check if data + heap + stack exceeds RAM limit */
+ ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
+
+ ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary")
+ /* todo assert on extra code */
+}
+
diff --git a/ld/tests/data/rp2350_default.ld b/ld/tests/data/rp2350_default.ld
new file mode 100644
index 00000000..bce316d1
--- /dev/null
+++ b/ld/tests/data/rp2350_default.ld
@@ -0,0 +1,302 @@
+/* Based on GCC ARM embedded samples.
+ Defines the following symbols for use by code:
+ __exidx_start
+ __exidx_end
+ __etext
+ __data_start__
+ __preinit_array_start
+ __preinit_array_end
+ __init_array_start
+ __init_array_end
+ __fini_array_start
+ __fini_array_end
+ __data_end__
+ __bss_start__
+ __bss_end__
+ __end__
+ end
+ __HeapLimit
+ __StackLimit
+ __StackTop
+ __stack (== StackTop)
+*/
+
+MEMORY
+{
+ INCLUDE "pico_flash_region.ld"
+ RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 512k
+ SCRATCH_X(rwx) : ORIGIN = 0x20080000, LENGTH = 4k
+ SCRATCH_Y(rwx) : ORIGIN = 0x20081000, LENGTH = 4k
+}
+
+ENTRY(_entry_point)
+
+SECTIONS
+{
+ .flash_begin : {
+ __flash_binary_start = .;
+ } > FLASH
+
+ /* The bootrom will enter the image at the point indicated in your
+ IMAGE_DEF, which is usually the reset handler of your vector table.
+
+ The debugger will use the ELF entry point, which is the _entry_point
+ symbol, and in our case is *different from the bootrom's entry point.*
+ This is used to go back through the bootrom on debugger launches only,
+ to perform the same initial flash setup that would be performed on a
+ cold boot.
+ */
+
+ .text : {
+ __logical_binary_start = .;
+ KEEP (*(.vectors))
+ KEEP (*(.binary_info_header))
+ __binary_info_header_end = .;
+ KEEP (*(.embedded_block))
+ __embedded_block_end = .;
+ KEEP (*(.reset))
+ /* TODO revisit this now memset/memcpy/float in ROM */
+ /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from
+ * FLASH ... we will include any thing excluded here in .data below by default */
+ *(.init)
+ *libgcc.a:cmse_nonsecure_call.o
+ *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*)
+ *(.fini)
+ /* Pull all c'tors into .text */
+ *crtbegin.o(.ctors)
+ *crtbegin?.o(.ctors)
+ *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
+ *(SORT(.ctors.*))
+ *(.ctors)
+ /* Followed by destructors */
+ *crtbegin.o(.dtors)
+ *crtbegin?.o(.dtors)
+ *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
+ *(SORT(.dtors.*))
+ *(.dtors)
+
+ . = ALIGN(4);
+ /* preinit data */
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP(*(SORT(.preinit_array.*)))
+ KEEP(*(.preinit_array))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+
+ . = ALIGN(4);
+ /* init data */
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP(*(SORT(.init_array.*)))
+ KEEP(*(.init_array))
+ PROVIDE_HIDDEN (__init_array_end = .);
+
+ . = ALIGN(4);
+ /* finit data */
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ *(SORT(.fini_array.*))
+ *(.fini_array)
+ PROVIDE_HIDDEN (__fini_array_end = .);
+
+ *(.eh_frame*)
+ . = ALIGN(4);
+ } > FLASH
+
+ /* Note the boot2 section is optional, and should be discarded if there is
+ no reference to it *inside* the binary, as it is not called by the
+ bootrom. (The bootrom performs a simple best-effort XIP setup and
+ leaves it to the binary to do anything more sophisticated.) However
+ there is still a size limit of 256 bytes, to ensure the boot2 can be
+ stored in boot RAM.
+
+ Really this is a "XIP setup function" -- the name boot2 is historic and
+ refers to its dual-purpose on RP2040, where it also handled vectoring
+ from the bootrom into the user image.
+ */
+
+ .boot2 : {
+ __boot2_start__ = .;
+ *(.boot2)
+ __boot2_end__ = .;
+ } > FLASH
+
+ ASSERT(__boot2_end__ - __boot2_start__ <= 256,
+ "ERROR: Pico second stage bootloader must be no more than 256 bytes in size")
+
+ .rodata : {
+ *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*)
+ *(.srodata*)
+ . = ALIGN(4);
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*)))
+ . = ALIGN(4);
+ } > FLASH
+
+ .ARM.extab :
+ {
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ } > FLASH
+
+ __exidx_start = .;
+ .ARM.exidx :
+ {
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ } > FLASH
+ __exidx_end = .;
+
+ /* Machine inspectable binary information */
+ . = ALIGN(4);
+ __binary_info_start = .;
+ .binary_info :
+ {
+ KEEP(*(.binary_info.keep.*))
+ *(.binary_info.*)
+ } > FLASH
+ __binary_info_end = .;
+ . = ALIGN(4);
+
+ .ram_vector_table (NOLOAD): {
+ *(.ram_vector_table)
+ } > RAM
+
+ .uninitialized_data (NOLOAD): {
+ . = ALIGN(4);
+ *(.uninitialized_data*)
+ } > RAM
+
+ .data : {
+ __data_start__ = .;
+ *(vtable)
+
+ *(.time_critical*)
+
+ /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */
+ *(.text*)
+ . = ALIGN(4);
+ *(.rodata*)
+ . = ALIGN(4);
+
+ *(.data*)
+ *(.sdata*)
+
+ . = ALIGN(4);
+ *(.after_data.*)
+ . = ALIGN(4);
+ /* preinit data */
+ PROVIDE_HIDDEN (__mutex_array_start = .);
+ KEEP(*(SORT(.mutex_array.*)))
+ KEEP(*(.mutex_array))
+ PROVIDE_HIDDEN (__mutex_array_end = .);
+
+ *(.jcr)
+ . = ALIGN(4);
+ } > RAM AT> FLASH
+
+ .tdata : {
+ . = ALIGN(4);
+ *(.tdata .tdata.* .gnu.linkonce.td.*)
+ /* All data end */
+ __tdata_end = .;
+ } > RAM AT> FLASH
+ PROVIDE(__data_end__ = .);
+
+ /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */
+ __etext = LOADADDR(.data);
+
+ .tbss (NOLOAD) : {
+ . = ALIGN(4);
+ __bss_start__ = .;
+ __tls_base = .;
+ *(.tbss .tbss.* .gnu.linkonce.tb.*)
+ *(.tcommon)
+
+ __tls_end = .;
+ } > RAM
+
+ .bss (NOLOAD) : {
+ . = ALIGN(4);
+ __tbss_end = .;
+
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*)))
+ *(COMMON)
+ PROVIDE(__global_pointer$ = . + 2K);
+ *(.sbss*)
+ . = ALIGN(4);
+ __bss_end__ = .;
+ } > RAM
+
+ .heap (NOLOAD):
+ {
+ __end__ = .;
+ end = __end__;
+ KEEP(*(.heap*))
+ } > RAM
+ /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, however
+ to be more compatible, we now set __HeapLimit explicitly to where the end of the heap is */
+ __HeapLimit = ORIGIN(RAM) + LENGTH(RAM);
+
+ /* Start and end symbols must be word-aligned */
+ .scratch_x : {
+ __scratch_x_start__ = .;
+ *(.scratch_x.*)
+ . = ALIGN(4);
+ __scratch_x_end__ = .;
+ } > SCRATCH_X AT > FLASH
+ __scratch_x_source__ = LOADADDR(.scratch_x);
+
+ .scratch_y : {
+ __scratch_y_start__ = .;
+ *(.scratch_y.*)
+ . = ALIGN(4);
+ __scratch_y_end__ = .;
+ } > SCRATCH_Y AT > FLASH
+ __scratch_y_source__ = LOADADDR(.scratch_y);
+
+ /* .stack*_dummy section doesn't contains any symbols. It is only
+ * used for linker to calculate size of stack sections, and assign
+ * values to stack symbols later
+ *
+ * stack1 section may be empty/missing if platform_launch_core1 is not used */
+
+ /* by default we put core 0 stack at the end of scratch Y, so that if core 1
+ * stack is not used then all of SCRATCH_X is free.
+ */
+ .stack1_dummy (NOLOAD):
+ {
+ *(.stack1*)
+ } > SCRATCH_X
+ .stack_dummy (NOLOAD):
+ {
+ KEEP(*(.stack*))
+ } > SCRATCH_Y
+
+ .flash_end : {
+ KEEP(*(.embedded_end_block*))
+ PROVIDE(__flash_binary_end = .);
+ } > FLASH =0xaa
+
+ /* stack limit is poorly named, but historically is maximum heap ptr */
+ __StackLimit = ORIGIN(RAM) + LENGTH(RAM);
+ __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X);
+ __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y);
+ __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy);
+ __StackBottom = __StackTop - SIZEOF(.stack_dummy);
+ PROVIDE(__stack = __StackTop);
+
+ /* picolibc and LLVM */
+ PROVIDE (__heap_start = __end__);
+ PROVIDE (__heap_end = __HeapLimit);
+ PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) );
+ PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1));
+ PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) );
+
+ /* llvm-libc */
+ PROVIDE (_end = __end__);
+ PROVIDE (__llvm_libc_heap_limit = __HeapLimit);
+
+ /* Check if data + heap + stack exceeds RAM limit */
+ ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
+
+ ASSERT( __binary_info_header_end - __logical_binary_start <= 1024, "Binary info must be in first 1024 bytes of the binary")
+ ASSERT( __embedded_block_end - __logical_binary_start <= 4096, "Embedded block must be in first 4096 bytes of the binary")
+
+ /* todo assert on extra code */
+}
+
diff --git a/ld/tests/data/stm32h753vihx_flash.ld b/ld/tests/data/stm32h753vihx_flash.ld
new file mode 100644
index 00000000..46b140ff
--- /dev/null
+++ b/ld/tests/data/stm32h753vihx_flash.ld
@@ -0,0 +1,192 @@
+/*
+******************************************************************************
+**
+
+** File : LinkerScript.ld
+**
+** Author : STM32CubeMX
+**
+** Abstract : Linker script for STM32H753VIHx series
+** 2048Kbytes FLASH and 1056Kbytes RAM
+**
+** Set heap size, stack size and stack location according
+** to application requirements.
+**
+** Set memory bank area and size if external memory is used.
+**
+** Target : STMicroelectronics STM32
+**
+** Distribution: The file is distributed “as is,” without any warranty
+** of any kind.
+**
+*****************************************************************************
+** @attention
+**
+** © COPYRIGHT(c) 2019 STMicroelectronics
+**
+** Redistribution and use in source and binary forms, with or without modification,
+** are permitted provided that the following conditions are met:
+** 1. Redistributions of source code must retain the above copyright notice,
+** this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright notice,
+** this list of conditions and the following disclaimer in the documentation
+** and/or other materials provided with the distribution.
+** 3. Neither the name of STMicroelectronics nor the names of its contributors
+** may be used to endorse or promote products derived from this software
+** without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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.
+**
+*****************************************************************************
+*/
+
+/* Entry Point */
+ENTRY(Reset_Handler)
+
+/* Highest address of the user mode stack */
+_estack = ORIGIN(DTCMRAM) + LENGTH(DTCMRAM); /* end of RAM */
+/* Generate a link error if heap and stack don't fit into RAM */
+_Min_Heap_Size = 0x200; /* required amount of heap */
+_Min_Stack_Size = 0x400; /* required amount of stack */
+
+/* Specify the memory areas */
+MEMORY
+{
+DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
+RAM (xrw) : ORIGIN = 0x24000000, LENGTH = 512K
+RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
+RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
+ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
+FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 2048K
+}
+
+/* Define output sections */
+SECTIONS
+{
+ /* The startup code goes first into FLASH */
+ .isr_vector :
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector)) /* Startup code */
+ . = ALIGN(4);
+ } >FLASH
+
+ /* The program code and other data goes into FLASH */
+ .text :
+ {
+ . = ALIGN(4);
+ *(.text) /* .text sections (code) */
+ *(.text*) /* .text* sections (code) */
+ *(.glue_7) /* glue arm to thumb code */
+ *(.glue_7t) /* glue thumb to arm code */
+ *(.eh_frame)
+
+ KEEP (*(.init))
+ KEEP (*(.fini))
+
+ . = ALIGN(4);
+ _etext = .; /* define a global symbols at end of code */
+ } >FLASH
+
+ /* Constant data goes into FLASH */
+ .rodata :
+ {
+ . = ALIGN(4);
+ *(.rodata) /* .rodata sections (constants, strings, etc.) */
+ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
+ . = ALIGN(4);
+ } >FLASH
+
+ .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
+ .ARM : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >FLASH
+
+ .preinit_array :
+ {
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array*))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ } >FLASH
+ .init_array :
+ {
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array*))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ } >FLASH
+ .fini_array :
+ {
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(SORT(.fini_array.*)))
+ KEEP (*(.fini_array*))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ } >FLASH
+
+ /* used by the startup to initialize data */
+ _sidata = LOADADDR(.data);
+
+ /* Initialized data sections goes into RAM, load LMA copy after code */
+ .data :
+ {
+ . = ALIGN(4);
+ _sdata = .; /* create a global symbol at data start */
+ *(.data) /* .data sections */
+ *(.data*) /* .data* sections */
+
+ . = ALIGN(4);
+ _edata = .; /* define a global symbol at data end */
+ } >DTCMRAM AT> FLASH
+
+
+ /* Uninitialized data section */
+ . = ALIGN(4);
+ .bss :
+ {
+ /* This is used by the startup in order to initialize the .bss secion */
+ _sbss = .; /* define a global symbol at bss start */
+ __bss_start__ = _sbss;
+ *(.bss)
+ *(.bss*)
+ *(COMMON)
+
+ . = ALIGN(4);
+ _ebss = .; /* define a global symbol at bss end */
+ __bss_end__ = _ebss;
+ } >DTCMRAM
+
+ /* User_heap_stack section, used to check that there is enough RAM left */
+ ._user_heap_stack :
+ {
+ . = ALIGN(8);
+ PROVIDE ( end = . );
+ PROVIDE ( _end = . );
+ . = . + _Min_Heap_Size;
+ . = . + _Min_Stack_Size;
+ . = ALIGN(8);
+ } >DTCMRAM
+
+ _trace_start = .;
+
+ /* Remove information from the standard libraries */
+ /DISCARD/ :
+ {
+ libc.a ( * )
+ libm.a ( * )
+ libgcc.a ( * )
+ }
+
+}
+
+
diff --git a/ld/tests/genlink-cmsis.sh b/ld/tests/genlink-cmsis.sh
new file mode 100755
index 00000000..7e90517c
--- /dev/null
+++ b/ld/tests/genlink-cmsis.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+function test_fail() {
+ echo "TEST FAILED: $1!"
+ exit 1
+}
+
+function test_pass() {
+ echo "TEST PASSED"
+ return 0
+}
+
+# test_create_includes SOURCE_DIR BINARY_DIR LINKER_FILE
+function test_create_includes() {
+ TMP_DIR=$2/ld/tests/
+ mkdir -p ${TMP_DIR}
+ rm -rf ${TMP_DIR}/*
+ python3 genlink-cmsis.py --create $1/tests/data/$3 ${TMP_DIR}/foo.$3 foo || test_fail "Error while running genlink-cmsis"
+ for SECTION in bss data inst shared text vtable; do
+ grep "INCLUDE gen.foo.${SECTION}.ld" ${TMP_DIR}/foo.$3 > /dev/null || test_fail ".${SECTION} section include directive not present"
+ [ -e ${TMP_DIR}/gen.foo.${SECTION}.ld ] || test_fail ".${SECTION} section include file does not exit"
+ done
+
+}
+
+if [ "$#" -lt "2" ]; then
+ echo "$0: "
+ exit 1
+fi
+
+for LD_FILE in rp2040_default.ld rp2350_default.ld STM32G491CCUx_FLASH.ld stm32h753vihx_flash.ld max32690_rom.ld; do
+ test_create_includes $1 $2 ${LD_FILE}
+ TEST_OUTCOME=$?
+ if [ ${TEST_OUTCOME} != 0 ]; then
+ exit ${TEST_OUTCOME}
+ fi
+done
+
+test_pass
\ No newline at end of file