Build: Add LLVM toolchain support for an521 only.

Support for other platforms will follow.

Signed-off-by: Anton Komlev <anton.komlev@arm.com>
Change-Id: Id036ecd78bf8e8909af30f78b2bfe5262b78c6b9
diff --git a/bl2/CMakeLists.txt b/bl2/CMakeLists.txt
index 63e6364..5e38af8 100644
--- a/bl2/CMakeLists.txt
+++ b/bl2/CMakeLists.txt
@@ -118,6 +118,7 @@
 
 add_executable(bl2
     src/flash_map.c
+    $<$<C_COMPILER_ID:Clang>:src/crt_exit.c>
     $<$<BOOL:${DEFAULT_MCUBOOT_SECURITY_COUNTERS}>:src/security_cnt.c>
     $<$<BOOL:${DEFAULT_MCUBOOT_FLASH_MAP}>:src/default_flash_map.c>
     $<$<BOOL:${MCUBOOT_DATA_SHARING}>:src/shared_data.c>
@@ -158,6 +159,7 @@
         $<$<C_COMPILER_ID:GNU>:-Wl,-Map=${CMAKE_BINARY_DIR}/bin/bl2.map>
         $<$<C_COMPILER_ID:ARMClang>:--map>
         $<$<C_COMPILER_ID:IAR>:--map\;${CMAKE_BINARY_DIR}/bin/bl2.map>
+        $<$<C_COMPILER_ID:Clang>:-lcrt0 -Wl,-Map=${CMAKE_BINARY_DIR}/bin/bl2.map>
         ${BL2_LINKER_CP_OPTION}
 )
 
diff --git a/bl2/ext/mcuboot/CMakeLists.txt b/bl2/ext/mcuboot/CMakeLists.txt
index 425212c..4f05fce 100644
--- a/bl2/ext/mcuboot/CMakeLists.txt
+++ b/bl2/ext/mcuboot/CMakeLists.txt
@@ -169,6 +169,7 @@
             $<$<C_COMPILER_ID:GNU>:-E\;-xc>
             $<$<C_COMPILER_ID:ARMClang>:-E\;-xc>
             $<$<C_COMPILER_ID:IAR>:--preprocess=ns\;$<TARGET_OBJECTS:signing_layout_s>>
+            $<$<C_COMPILER_ID:Clang>:-E\;-xc>
     )
     target_compile_definitions(signing_layout_s
         PRIVATE
@@ -185,7 +186,6 @@
         SOURCES tfm_s_signed.bin
     )
     add_custom_command(OUTPUT tfm_s_signed.bin
-        DEPENDS $<TARGET_FILE_DIR:tfm_s>/tfm_s.bin
         DEPENDS tfm_s_bin signing_layout_s
         DEPENDS $<IF:$<BOOL:${MCUBOOT_GENERATE_SIGNING_KEYPAIR}>,generated_private_key,>
         WORKING_DIRECTORY ${MCUBOOT_PATH}/scripts
@@ -222,6 +222,7 @@
             $<$<C_COMPILER_ID:GNU>:-E\;-xc>
             $<$<C_COMPILER_ID:ARMClang>:-E\;-xc>
             $<$<C_COMPILER_ID:IAR>:--preprocess=ns\;$<TARGET_OBJECTS:signing_layout_ns>>
+            $<$<C_COMPILER_ID:Clang>:-E\;-xc>
     )
     target_compile_definitions(signing_layout_ns
         PRIVATE
diff --git a/bl2/src/crt_exit.c b/bl2/src/crt_exit.c
new file mode 100644
index 0000000..39e742f
--- /dev/null
+++ b/bl2/src/crt_exit.c
@@ -0,0 +1,10 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ */
+
+void _exit(void)
+{
+    while (1)
+        ;
+}
diff --git a/cmake/install.cmake b/cmake/install.cmake
index d98bef1..b2e2d69 100644
--- a/cmake/install.cmake
+++ b/cmake/install.cmake
@@ -263,6 +263,7 @@
 install(FILES       ${PLATFORM_DIR}/ns/toolchain_ns_GNUARM.cmake
                     ${PLATFORM_DIR}/ns/toolchain_ns_ARMCLANG.cmake
                     ${PLATFORM_DIR}/ns/toolchain_ns_IARARM.cmake
+                    ${PLATFORM_DIR}/ns/toolchain_ns_LLVM.cmake
         DESTINATION ${INSTALL_CMAKE_DIR})
 
 install(FILES
diff --git a/cmake/spe-CMakeLists.cmake b/cmake/spe-CMakeLists.cmake
index 2c5323b..dab6115 100644
--- a/cmake/spe-CMakeLists.cmake
+++ b/cmake/spe-CMakeLists.cmake
@@ -169,7 +169,8 @@
             SOURCES ${CMAKE_BINARY_DIR}/bin/${NS_TARGET_NAME}_signed.bin
         )
         add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/bin/${NS_TARGET_NAME}_signed.bin
-            DEPENDS ${NS_TARGET_NAME}_bin $<TARGET_FILE_DIR:${NS_TARGET_NAME}>/${NS_TARGET_NAME}.bin
+            DEPENDS ${NS_TARGET_NAME}_bin
+            DEPENDS $<TARGET_FILE_DIR:${NS_TARGET_NAME}>/${NS_TARGET_NAME}.bin
             DEPENDS $<IF:$<BOOL:${MCUBOOT_GENERATE_SIGNING_KEYPAIR}>,generated_private_key,>
             DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/image_signing/layout_files/signing_layout_ns.o
             WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/image_signing/scripts
@@ -201,7 +202,7 @@
         # support
         add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/tfm_s_ns_signed.bin
             DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bin/tfm_s_signed.bin
-            DEPENDS ${NS_TARGET_NAME}_signed_bin ${CMAKE_BINARY_DIR}/bin/${NS_TARGET_NAME}_signed.bin
+            DEPENDS ${CMAKE_BINARY_DIR}/bin/${NS_TARGET_NAME}_signed.bin
             DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/image_signing/layout_files/signing_layout_s.o
             WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/image_signing/scripts
 
diff --git a/platform/CMakeLists.txt b/platform/CMakeLists.txt
index c6c7de3..4cc2b83 100644
--- a/platform/CMakeLists.txt
+++ b/platform/CMakeLists.txt
@@ -46,6 +46,7 @@
     INTERFACE
         "$<$<C_COMPILER_ID:GNU>:SHELL:-include ${CMSIS_OVERRIDE_HEADER}>"
         "$<$<AND:$<OR:$<COMPILE_LANGUAGE:C>,$<COMPILE_LANGUAGE:CXX>>,$<C_COMPILER_ID:IAR>>:SHELL:--preinclude ${CMSIS_OVERRIDE_HEADER}>"
+        "$<$<C_COMPILER_ID:Clang>:SHELL:-include ${CMSIS_OVERRIDE_HEADER}>"
 )
 
 #========================= Platform Common interface ==========================#
diff --git a/platform/ext/common/generated_file_list.yaml b/platform/ext/common/generated_file_list.yaml
index eaafe30..0986c6a 100644
--- a/platform/ext/common/generated_file_list.yaml
+++ b/platform/ext/common/generated_file_list.yaml
@@ -47,5 +47,10 @@
         "template": "platform/ext/common/iar/tfm_isolation_s.icf.template",
         "output": "platform/ext/common/iar/tfm_isolation_s.icf"
     },
+    {
+        "description": "isolation l1-l3 linker script",
+        "template": "platform/ext/common/llvm/tfm_isolation_s.ld.template",
+        "output": "platform/ext/common/llvm/tfm_isolation_s.ld"
+    }
   ]
 }
diff --git a/platform/ext/common/llvm/tfm_common_bl2.ld b/platform/ext/common/llvm/tfm_common_bl2.ld
new file mode 100644
index 0000000..96f9695
--- /dev/null
+++ b/platform/ext/common/llvm/tfm_common_bl2.ld
@@ -0,0 +1,125 @@
+;/*
+; * Copyright (c) 2022-2024 Arm Limited. All rights reserved.
+; *
+; * Licensed under the Apache License, Version 2.0 (the "License");
+; * you may not use this file except in compliance with the License.
+; * You may obtain a copy of the License at
+; *
+; *     http://www.apache.org/licenses/LICENSE-2.0
+; *
+; * Unless required by applicable law or agreed to in writing, software
+; * distributed under the License is distributed on an "AS IS" BASIS,
+; * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; * See the License for the specific language governing permissions and
+; * limitations under the License.
+; *
+; *
+; * This file is derivative of CMSIS V5.00 gcc_arm.ld
+; */
+
+/* Linker script to configure memory regions. */
+/* This file will be run trough the pre-processor. */
+
+#include "region_defs.h"
+
+MEMORY
+{
+    FLASH (rx)  : ORIGIN = BL2_CODE_START, LENGTH = BL2_CODE_SIZE
+    RAM   (rwx) : ORIGIN = BL2_DATA_START, LENGTH = BL2_DATA_SIZE
+}
+
+ENTRY(Reset_Handler)
+
+SECTIONS
+{
+    .text :
+    {
+        __vectors_start = .;
+        KEEP(*(.vectors))
+        __vectors_end = .;
+
+        *(.text*)
+        *(.rodata*)
+    } > FLASH
+
+#ifdef CODE_SHARING
+    /* The code sharing between bootloader and runtime firmware requires to
+     * share the global variables. Section size must be equal with
+     * SHARED_SYMBOL_AREA_SIZE defined in region_defs.h
+     */
+    .tfm_shared_symbols (NOLOAD) : ALIGN(4)
+    {
+        *(.data.mbedtls_calloc_func)
+        *(.data.mbedtls_free_func)
+        *(.data.mbedtls_exit)
+        *(.data.memset_func)
+        . = ALIGN(SHARED_SYMBOL_AREA_SIZE);
+    } > RAM AT > FLASH
+
+    ASSERT(SHARED_SYMBOL_AREA_SIZE % 4 == 0, "SHARED_SYMBOL_AREA_SIZE must be divisible by 4")
+#endif
+
+    .tfm_bl2_shared_data (NOLOAD) : ALIGN(32)
+    {
+        . += BOOT_TFM_SHARED_DATA_SIZE;
+    } > RAM
+    Image$$SHARED_DATA$$RW$$Base = ADDR(.tfm_bl2_shared_data);
+    Image$$SHARED_DATA$$RW$$Limit = ADDR(.tfm_bl2_shared_data) + SIZEOF(.tfm_bl2_shared_data);
+    /*
+    * Bootoader will clear region [Image$$ER_DATA$$Base - Image$$ARM_LIB_HEAP$$ZI$$Limit]
+    * It's important to keep .tfm_bl2_shared_data out of that region
+    */
+    .data : ALIGN(4)
+    {
+        *(.data*)
+    } > RAM AT > FLASH
+
+    .bss (NOLOAD) : ALIGN(4)
+    {
+        *(.bss*)
+        *(COMMON)
+        . = ALIGN(4);
+    } > RAM
+    __bss_start = ADDR(.bss);
+    __bss_end = ADDR(.bss) + SIZEOF(.bss);
+    __bss_size = SIZEOF(.bss);
+
+    .msp_stack (NOLOAD) : ALIGN(32)
+    {
+        . += BL2_MSP_STACK_SIZE;
+    } > RAM
+    Image$$ARM_LIB_STACK$$ZI$$Base = ADDR(.msp_stack);
+#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
+    Image$$ARM_LIB_STACK$$ZI$$Limit = ADDR(.msp_stack) + SIZEOF(.msp_stack) - 0x8;
+    __stack_seal = Image$$ARM_LIB_STACK$$ZI$$Limit;
+#else
+    Image$$ARM_LIB_STACK$$ZI$$Limit = ADDR(.msp_stack) + SIZEOF(.msp_stack);
+#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */
+    __stack = Image$$ARM_LIB_STACK$$ZI$$Limit;
+
+    .heap (NOLOAD): ALIGN(8)
+    {
+        . += BL2_HEAP_SIZE;
+        __tls_base = .;                /* dummy. for picolib crt0 only */
+        __arm32_tls_tcb_offset = .;    /* dummy. for picolib crt0 only */
+    } > RAM
+    __heap_start = ADDR(.heap);
+    __heap_end = ADDR(.heap) + SIZEOF(.heap);
+    __heap_size = SIZEOF(.heap);
+
+    /* Those 2 symbols defines the region for clearing on boot completion */
+    Image$$ER_DATA$$Base = ADDR(.data);
+    Image$$ARM_LIB_HEAP$$ZI$$Limit = ADDR(.heap) + SIZEOF(.heap);
+
+#ifdef CODE_SHARING
+    __data_start  = ADDR(.tfm_shared_symbols);
+    __data_source = LOADADDR(.tfm_shared_symbols);
+    __data_size   = SIZEOF(tfm_shared_symbols) + SIZEOF(tfm_bl2_shared_data) + SIZEOF(.data);
+#else /* CODE_SHARING */
+    __data_start  = ADDR(.data);
+    __data_source = LOADADDR(.data);
+    __data_size   = SIZEOF(.data);
+#endif /* CODE_SHARING */
+
+/*    PROVIDE(__stack = Image$$ARM_LIB_STACK$$ZI$$Limit); */
+}
diff --git a/platform/ext/common/llvm/tfm_common_ns.ldc b/platform/ext/common/llvm/tfm_common_ns.ldc
new file mode 100644
index 0000000..83c341e
--- /dev/null
+++ b/platform/ext/common/llvm/tfm_common_ns.ldc
@@ -0,0 +1,131 @@
+;/*
+; * Copyright (c) 2021-2024 Arm Limited. All rights reserved.
+; *
+; * Licensed under the Apache License, Version 2.0 (the "License");
+; * you may not use this file except in compliance with the License.
+; * You may obtain a copy of the License at
+; *
+; *     http://www.apache.org/licenses/LICENSE-2.0
+; *
+; * Unless required by applicable law or agreed to in writing, software
+; * distributed under the License is distributed on an "AS IS" BASIS,
+; * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; * See the License for the specific language governing permissions and
+; * limitations under the License.
+; *
+; *
+; * This file is derivative of CMSIS V5.00 gcc_arm.ld
+; */
+
+/* Linker script to configure memory regions. */
+/* This file will be run trough the pre-processor. */
+
+#include "region_defs.h"
+
+MEMORY
+{
+    FLASH (rx)  : ORIGIN = NS_CODE_START, LENGTH = NS_CODE_SIZE
+    RAM   (rwx) : ORIGIN = NS_DATA_START, LENGTH = NS_DATA_SIZE
+}
+
+ENTRY(Reset_Handler)
+
+SECTIONS
+{
+    .text :
+    {
+        __vectors_start = .;
+        KEEP(*(.vectors))
+        __vectors_end = .;
+
+        *(.text*)
+        . = 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 = .);
+
+        KEEP(*(.init))
+        KEEP(*(.fini))
+
+        /* .ctors */
+        *crtbegin.o(.ctors)
+        *crtbegin?.o(.ctors)
+        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
+        *(SORT(.ctors.*))
+        *(.ctors)
+
+        /* .dtors */
+         *crtbegin.o(.dtors)
+         *crtbegin?.o(.dtors)
+         *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
+         *(SORT(.dtors.*))
+         *(.dtors)
+
+        *(.rodata*)
+
+        KEEP(*(.eh_frame*))
+    } > FLASH
+
+    .ARM.extab :
+    {
+        *(.ARM.extab* .gnu.linkonce.armextab.*)
+    } > FLASH
+
+    __exidx_start = .;
+    .ARM.exidx :
+    {
+        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+    } > FLASH
+    __exidx_end = .;
+
+    .data :
+    {
+       *(vtable)
+       *(.data*)
+        KEEP(*(.jcr*))
+    } > RAM AT > FLASH
+    __data_start = ADDR(.data);
+    __data_source = LOADADDR(.data);
+    __data_size = SIZEOF(.data);
+
+    .bss (NOLOAD): ALIGN(4)
+    {
+        *(.bss*)
+        *(COMMON)
+        . = ALIGN(4);
+        __tls_base = . ;                /* to satisfy crt0 */
+;        __arm32_tls_tcb_offset = . ;   /* to satisfy crt0 */
+    } > RAM
+    __bss_start = ADDR(.bss);
+    __bss_size = SIZEOF(.bss);
+
+    .stack (NOLOAD): ALIGN(32)
+    {
+        . += NS_STACK_SIZE;
+    } > RAM
+    __stack_limit = ADDR(.stack);
+    __stack = ADDR(.stack) + SIZEOF(.stack);
+
+    .heap (NOLOAD): ALIGN(8)
+    {
+        . += NS_HEAP_SIZE;
+    } > RAM
+    __heap_start = ADDR(.heap);
+    __heap_end = ADDR(.heap) + SIZEOF(.heap);
+    __heap_size = SIZEOF(.heap);
+}
diff --git a/platform/ext/common/llvm/tfm_isolation_s.ld.template b/platform/ext/common/llvm/tfm_isolation_s.ld.template
new file mode 100644
index 0000000..dd34129
--- /dev/null
+++ b/platform/ext/common/llvm/tfm_isolation_s.ld.template
@@ -0,0 +1,574 @@
+;/*
+; * Copyright (c) 2009-2024 Arm Limited
+; * Copyright (c) 2022-2024 Cypress Semiconductor Corporation (an Infineon company)
+; * or an affiliate of Cypress Semiconductor Corporation. All rights reserved.
+; *
+; * Licensed under the Apache License, Version 2.0 (the "License");
+; * you may not use this file except in compliance with the License.
+; * You may obtain a copy of the License at
+; *
+; *     http://www.apache.org/licenses/LICENSE-2.0
+; *
+; * Unless required by applicable law or agreed to in writing, software
+; * distributed under the License is distributed on an "AS IS" BASIS,
+; * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; * See the License for the specific language governing permissions and
+; * limitations under the License.
+; *
+; *
+; * This file is derivative of CMSIS V5.00 gcc_arm.ld
+; */
+
+/***********{{utilities.donotedit_warning}}***********/
+
+/* Linker script to configure memory regions. */
+/* This file will be run through the pre-processor. */
+
+#include "region_defs.h"
+
+/* Include file with definitions for section alignments.
+ * Note: it should be included after region_defs.h to let platform define
+ * default values if needed. */
+#include "tfm_s_linker_alignments.h"
+
+MEMORY
+{
+    FLASH    (rx)  : ORIGIN = S_CODE_START, LENGTH = S_CODE_SIZE
+    RAM      (rw)  : ORIGIN = S_DATA_START, LENGTH = S_DATA_SIZE
+#ifdef S_RAM_CODE_START
+    CODE_RAM (rwx) : ORIGIN = S_RAM_CODE_START, LENGTH = S_RAM_CODE_SIZE
+#endif
+}
+
+#ifndef TFM_LINKER_VENEERS_START
+#define TFM_LINKER_VENEERS_START ALIGN(TFM_LINKER_VENEERS_ALIGNMENT)
+#endif
+
+#ifndef TFM_LINKER_VENEERS_END
+#define TFM_LINKER_VENEERS_END ALIGN(TFM_LINKER_VENEERS_ALIGNMENT)
+#endif
+
+#define VENEERS() \
+/* \
+ * Place the CMSE Veneers (containing the SG instruction) after the code, in \
+ * a separate at least 32 bytes aligned region so that the SAU can \
+ * programmed to just set this region as Non-Secure Callable. \
+ */ \
+.gnu.sgstubs TFM_LINKER_VENEERS_START : \
+{ \
+    *(.gnu.sgstubs*) \
+} > FLASH \
+/* GCC always places veneers at the end of .gnu.sgstubs section, so the only \
+ * way to align the end of .gnu.sgstubs section is to align start of the \
+ * next section */ \
+.sgstubs_end : TFM_LINKER_VENEERS_END \
+{ \
+} > FLASH
+
+ENTRY(Reset_Handler)
+
+SECTIONS
+{
+    /* Position tag: Start of code + RO-data */
+    Image$$PT_RO_START$$Base = ADDR(.TFM_VECTORS);
+
+    .TFM_VECTORS : ALIGN(4)
+    {
+        __vectors_start = .;
+        KEEP(*(.vectors))
+        __vectors_end = .;
+    } > FLASH
+
+    ASSERT(__vectors_start != __vectors_end, ".vectors should not be empty")
+
+#ifdef S_CODE_VECTOR_TABLE_SIZE
+    ASSERT(. <= ADDR(.TFM_VECTORS) + S_CODE_VECTOR_TABLE_SIZE, ".TFM_VECTORS section size overflow.")
+    . = ADDR(.TFM_VECTORS) + S_CODE_VECTOR_TABLE_SIZE;
+#endif
+
+#if defined(CONFIG_TFM_USE_TRUSTZONE) && !defined(TFM_LINKER_VENEERS_LOCATION_END)
+    VENEERS()
+#endif
+    /* Position tag: Start of unprivileged code (shared, not PXN) */
+
+    .ER_UNPRIV_CODE : ALIGN(TFM_LINKER_PT_UNPRIV_CODE_ALIGNMENT)
+    {
+        Image$$PT_UNPRIV_CODE_START$$Base = .;
+        /* Shared library code */
+        *builtins*:*(SORT_BY_ALIGNMENT(.text*))
+        *libtfm_sprt*:*(SORT_BY_ALIGNMENT(.text*))
+        *libtfm_sp_log*:*(SORT_BY_ALIGNMENT(.text*))
+        *libqcbor*:*(SORT_BY_ALIGNMENT(.text*))
+        *libtfm_t_cose_s*:*(SORT_BY_ALIGNMENT(.text*))
+
+        KEEP(*(.init))
+        KEEP(*(.fini))
+
+        /* .ctors */
+        *crtbegin.o(.ctors)
+        *crtbegin?.o(.ctors)
+        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
+        *(SORT(.ctors.*))
+        *(.ctors)
+
+        /* .dtors */
+        *crtbegin.o(.dtors)
+        *crtbegin?.o(.dtors)
+        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
+        *(SORT(.dtors.*))
+        *(.dtors)
+
+        KEEP(*(.eh_frame*))
+    } > FLASH
+
+    /* Position tag: End of unprivileged code (shared, not PXN) */
+    . = ALIGN(TFM_LINKER_PT_UNPRIV_CODE_ALIGNMENT);
+    Image$$PT_UNPRIV_CODE_END$$Base = .;
+
+
+    .ER_APP_ROT_CODE : ALIGN(TFM_LINKER_PT_APP_ROT_CODE_ALIGNMENT)
+    {
+        /* Position tag: Start of Application RoT code (unprivileged, PXN) */
+        Image$$PT_APP_ROT_CODE_START$$Base = .;
+        *tfm_app_rot_partition*:*(SORT_BY_ALIGNMENT(.text*))
+        *(TFM_*_APP-ROT_ATTR_FN)
+{% for partition in partitions %}
+    {% if partition.manifest.type == 'APPLICATION-ROT' %}
+    {% if partition.attr.linker_pattern.library_list %}
+        {% for pattern in partition.attr.linker_pattern.library_list %}
+        {{pattern}}:*(SORT_BY_ALIGNMENT(.text*))
+        {% endfor %}
+    {% endif %}
+    {% if partition.attr.linker_pattern.object_list %}
+        {% for pattern in partition.attr.linker_pattern.object_list %}
+        {{pattern}}(SORT_BY_ALIGNMENT(.text*))
+        {% endfor %}
+    {% endif %}
+        *({{partition.manifest.name}}_APP-ROT_ATTR_FN)
+    {% endif %}
+{% endfor %}
+    } > FLASH
+
+    /* Position tag: End of Application RoT code (unprivileged, PXN) */
+    . = ALIGN(TFM_LINKER_PT_APP_ROT_CODE_ALIGNMENT);
+    Image$$PT_APP_ROT_CODE_END$$Base = .;
+
+    .ER_PSA_ROT_CODE : ALIGN(TFM_LINKER_PT_PSA_ROT_CODE_ALIGNMENT)
+    {
+        /* Position tag: Start of PSA RoT code (privileged) */
+        Image$$PT_PSA_ROT_CODE_START$$Base = .;
+        *tfm_psa_rot_partition*:*(SORT_BY_ALIGNMENT(.text*))
+        *(TFM_*_PSA-ROT_ATTR_FN)
+{% for partition in partitions %}
+    {% if partition.manifest.type == 'PSA-ROT' %}
+    {% if partition.attr.linker_pattern.library_list %}
+        {% for pattern in partition.attr.linker_pattern.library_list %}
+        {{pattern}}:*(SORT_BY_ALIGNMENT(.text*))
+        {% endfor %}
+    {% endif %}
+    {% if partition.attr.linker_pattern.object_list %}
+        {% for pattern in partition.attr.linker_pattern.object_list %}
+        {{pattern}}(SORT_BY_ALIGNMENT(.text*))
+        {% endfor %}
+    {% endif %}
+        *({{partition.manifest.name}}_PSA-ROT_ATTR_FN)
+    {% endif %}
+{% endfor %}
+    } > FLASH
+
+    .ARM.extab :
+    {
+        *(.ARM.extab* .gnu.linkonce.armextab.*)
+    } > FLASH
+
+    __exidx_start = .;
+    .ARM.exidx :
+    {
+        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+    } > FLASH
+    __exidx_end = .;
+
+    .ER_TFM_CODE 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 = .);
+
+        /* .copy.table */
+        . = ALIGN(4);
+        __copy_table_start__ = .;
+#ifdef RAM_VECTORS_SUPPORT
+        /* Copy interrupt vectors from flash to RAM */
+        LONG (__vectors_start__)                            /* From */
+        LONG (__ram_vectors_start__)                        /* To   */
+        LONG ((__vectors_end__ - __vectors_start__) / 4)    /* Size */
+#endif
+        LONG (LOADADDR(.TFM_DATA))
+        LONG (ADDR(.TFM_DATA))
+        LONG (SIZEOF(.TFM_DATA) / 4)
+
+{% for partition in partitions %}
+        LONG (LOADADDR(.ER_{{partition.manifest.name}}_DATA))
+        LONG (ADDR(.ER_{{partition.manifest.name}}_DATA))
+        LONG (SIZEOF(.ER_{{partition.manifest.name}}_DATA) / 4)
+{% endfor %}
+
+#ifdef S_RAM_CODE_START
+        LONG (LOADADDR(.ER_CODE_SRAM))
+        LONG (ADDR(.ER_CODE_SRAM))
+        LONG (SIZEOF(.ER_CODE_SRAM) / 4)
+#endif
+        __copy_table_end__ = .;
+
+        /* .zero.table */
+        . = ALIGN(4);
+        __zero_table_start__ = .;
+        LONG (ADDR(.TFM_BSS))
+        LONG (SIZEOF(.TFM_BSS) / 4)
+{% for partition in partitions %}
+        LONG (ADDR(.ER_{{partition.manifest.name}}_BSS))
+        LONG (SIZEOF(.ER_{{partition.manifest.name}}_BSS) / 4)
+{% endfor %}
+
+#ifdef CONFIG_TFM_PARTITION_META
+        LONG (ADDR(.TFM_SP_META_PTR))
+        LONG (SIZEOF(.TFM_SP_META_PTR) / 4)
+#endif
+        __zero_table_end__ = .;
+
+        /* Capture all remaining code (except RAM code) in the privileged TF-M
+         * code region.
+         */
+        EXCLUDE_FILE (*libflash_drivers*:) *(SORT_BY_ALIGNMENT(.text*))
+    } > FLASH
+
+    /* Collect all RO-data into a single unprivileged region */
+    .ER_RO_DATA ALIGN(TFM_LINKER_PT_RO_DATA_ALIGNMENT) :
+    {
+        Image$$PT_PSA_ROT_CODE_END$$Base = .;
+        Image$$PT_RO_DATA_START$$Base = .;
+    /* Position tag: Start of RO-data (unprivileged, execute-never) */
+        EXCLUDE_FILE (*libflash_drivers*:) *(SORT_BY_ALIGNMENT(.rodata*))
+    } > FLASH
+
+    /**** Section for holding partition RO load data */
+    /*
+     * Sort the partition info by priority to guarantee the initing order.
+     * The first loaded partition will be inited at last in SFN model.
+     */
+    .TFM_SP_LOAD_LIST ALIGN(4) :
+    {
+        KEEP(*(.part_load_priority_00))
+        KEEP(*(.part_load_priority_01))
+        KEEP(*(.part_load_priority_02))
+        KEEP(*(.part_load_priority_03))
+    } > FLASH
+    Image$$TFM_SP_LOAD_LIST$$RO$$Base = ADDR(.TFM_SP_LOAD_LIST);
+    Image$$TFM_SP_LOAD_LIST$$RO$$Limit = ADDR(.TFM_SP_LOAD_LIST) + SIZEOF(.TFM_SP_LOAD_LIST);
+
+    /* Position tag: End of RO-data (unprivileged, execute-never) */
+    . = ALIGN(TFM_LINKER_PT_RO_DATA_ALIGNMENT);
+    Image$$PT_RO_DATA_END$$Base = .;
+
+#if defined(CONFIG_TFM_USE_TRUSTZONE) && defined(TFM_LINKER_VENEERS_LOCATION_END)
+    VENEERS()
+#endif
+
+    /* Position tag: End of code + RO-data */
+    . = ALIGN(TFM_LINKER_PT_RO_ALIGNMENT);
+    Image$$PT_RO_END$$Base = .;
+
+#ifdef S_RAM_CODE_START
+    /* Flash drivers code that gets copied from Flash */
+    .ER_CODE_SRAM ALIGN(S_RAM_CODE_START, 4) :
+    {
+        *libflash_drivers*:*(SORT_BY_ALIGNMENT(.text*))
+        *libflash_drivers*:*(SORT_BY_ALIGNMENT(.rodata*))
+        KEEP(*(.ramfunc))
+        . = ALIGN(4); /* This alignment is needed to make the section size 4 bytes aligned */
+    } > CODE_RAM AT > FLASH
+
+    ASSERT(S_RAM_CODE_START % 4 == 0, "S_RAM_CODE_START must be divisible by 4")
+
+    Image$$ER_CODE_SRAM$$RO$$Base = ADDR(.ER_CODE_SRAM);
+    Image$$ER_CODE_SRAM$$RO$$Limit = ADDR(.ER_CODE_SRAM) + SIZEOF(.ER_CODE_SRAM);
+    Image$$ER_CODE_SRAM$$Base = ADDR(.ER_CODE_SRAM);
+    Image$$ER_CODE_SRAM$$Limit = ADDR(.ER_CODE_SRAM) + SIZEOF(.ER_CODE_SRAM);
+#endif
+
+    /**** Base address of secure data area */
+    .tfm_secure_data_start :
+    {
+        /* Relocate current position to RAM */
+        . = ALIGN(4);
+    } > RAM
+
+    /*
+     * MPU on Armv6-M/v7-M core in multi-core topology may require more strict
+     * alignment that MPU region base address must align with the MPU region
+     * size.
+     * As a result, on Armv6-M/v7-M cores, to save memory resource and MPU
+     * regions, unprivileged data sections and privileged data sections can be
+     * separated and gathered in unprivileged/privileged data area respectively
+     * by defining S_DATA_PRIV_START. If so, the BL2 shared data area is moved
+     * to the beginning of the privileged data area, otherwise it is kept at the
+     * beginning of the secure data area.
+     */
+#ifndef S_DATA_PRIV_START
+#ifdef CODE_SHARING
+    /* The code sharing between bootloader and runtime requires to share the
+     * global variables.
+     */
+    .TFM_SHARED_SYMBOLS ALIGN(TFM_LINKER_SHARED_SYMBOLS_ALIGNMENT) :
+    {
+        . += SHARED_SYMBOL_AREA_SIZE;
+    } > RAM
+#endif
+
+    /* Shared area between BL2 and runtime to exchange data */
+    .tfm_bl2_shared_data ALIGN(TFM_LINKER_BL2_SHARED_DATA_ALIGNMENT) (NOLOAD) :
+    {
+        . += BOOT_TFM_SHARED_DATA_SIZE;
+    } > RAM
+#endif /* !S_DATA_PRIV_START */
+
+    /* Position tag: Start of Application RoT data (unprivileged) */
+    . = ALIGN(TFM_LINKER_PT_APP_ROT_DATA_ALIGNMENT);
+    Image$$PT_APP_ROT_DATA_START$$Base = .;
+
+#ifdef CONFIG_TFM_PARTITION_META
+    .TFM_SP_META_PTR ALIGN(TFM_LINKER_SP_META_PTR_ALIGNMENT) (NOLOAD) :
+    {
+        *(.bss.SP_META_PTR_SPRTL_INST)
+        . = ALIGN(TFM_LINKER_SP_META_PTR_ALIGNMENT);
+    } > RAM
+    Image$$TFM_SP_META_PTR$$ZI$$Base = ADDR(.TFM_SP_META_PTR);
+    Image$$TFM_SP_META_PTR$$ZI$$Limit = ADDR(.TFM_SP_META_PTR) + SIZEOF(.TFM_SP_META_PTR);
+    /* This is needed for the uniform configuration of MPU region. */
+    Image$$TFM_SP_META_PTR_END$$ZI$$Limit = Image$$TFM_SP_META_PTR$$ZI$$Limit;
+#endif
+
+{% for partition in partitions %}
+    {% if partition.manifest.type == 'APPLICATION-ROT' %}
+
+
+    .ER_{{partition.manifest.name}}_DATA : ALIGN(TFM_LINKER_PT_AROT_PART_PRIVATE_DATA_ALIGNMENT)
+    {
+        /* Position tag: Start of Application RoT partition's private data */
+        Image$$PT_{{partition.manifest.name}}_PRIVATE_DATA_START$$Base = .;
+    {% if partition.attr.linker_pattern.library_list %}
+        {% for pattern in partition.attr.linker_pattern.library_list %}
+        {{pattern}}:*(SORT_BY_ALIGNMENT(.data*))
+        {% endfor %}
+    {% endif %}
+    {% if partition.attr.linker_pattern.object_list %}
+        {% for pattern in partition.attr.linker_pattern.object_list %}
+        {{pattern}}(SORT_BY_ALIGNMENT(.data*))
+        {% endfor %}
+    {% endif %}
+        *({{partition.manifest.name}}_APP-ROT_ATTR_RW)
+        . = ALIGN(4);
+    } > RAM AT > FLASH
+
+    .ER_{{partition.manifest.name}}_BSS ALIGN(8) (NOLOAD) :
+    {
+        start_of_{{partition.manifest.name}}_bss = .;
+    {% if partition.attr.linker_pattern.library_list %}
+        {% for pattern in partition.attr.linker_pattern.library_list %}
+        {{pattern}}:*(SORT_BY_ALIGNMENT(.bss*))
+        {{pattern}}:*(COMMON)
+        {% endfor %}
+    {% endif %}
+    {% if partition.attr.linker_pattern.object_list %}
+        {% for pattern in partition.attr.linker_pattern.object_list %}
+        {{pattern}}(SORT_BY_ALIGNMENT(.bss*))
+        {{pattern}}(COMMON)
+        {% endfor %}
+    {% endif %}
+        *({{partition.manifest.name}}_APP-ROT_ATTR_ZI)
+        . += (. - start_of_{{partition.manifest.name}}_bss) ? 0 : 4;
+    } > RAM
+
+    /* Position tag: End of Application RoT partition's private data */
+    . = ALIGN(TFM_LINKER_PT_AROT_PART_PRIVATE_DATA_ALIGNMENT);
+    Image$$PT_{{partition.manifest.name}}_PRIVATE_DATA_END$$Base = .;
+
+    {% endif %}
+{% endfor %}
+
+    /* Position tag: End of Application RoT data (unprivileged) */
+    . = ALIGN(TFM_LINKER_PT_APP_ROT_DATA_ALIGNMENT);
+    Image$$PT_APP_ROT_DATA_END$$Base = .;
+
+#ifdef S_DATA_PRIV_START
+    /**** Privileged data area base address specified by Armv6-M/v7-M platform */
+    .tfm_secure_priv_data_boundary :
+    {
+        . = ABSOLUTE(S_DATA_PRIV_START) ;
+    } > RAM
+
+    /*
+     * Move BL2 shared area to the beginning of privileged data area on
+     * Armv6-M/v7-M platforms.
+     */
+    /* Shared area between BL2 and runtime to exchange data */
+    .tfm_bl2_shared_data ALIGN(TFM_LINKER_BL2_SHARED_DATA_ALIGNMENT) :
+    {
+        . += BOOT_TFM_SHARED_DATA_SIZE;
+    } > RAM
+#endif /* S_DATA_PRIV_START */
+
+    /* Position tag: Start of PSA RoT data (privileged) */
+    . = ALIGN(TFM_LINKER_PT_PSA_ROT_DATA_ALIGNMENT);
+    Image$$PT_PSA_ROT_DATA_START$$Base = .;
+
+    .msp_stack ALIGN(TFM_LINKER_MSP_STACK_ALIGNMENT) (NOLOAD) :
+    {
+        . += S_MSP_STACK_SIZE;
+    } > RAM
+    Image$$ARM_LIB_STACK$$ZI$$Base = ADDR(.msp_stack);
+
+#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__) || \
+    defined(__ARM_ARCH_8_1M_MAIN__)
+    Image$$ARM_LIB_STACK$$ZI$$Limit = ADDR(.msp_stack) + SIZEOF(.msp_stack) - 0x8;
+    __stack_seal = Image$$ARM_LIB_STACK$$ZI$$Limit;
+#else
+    Image$$ARM_LIB_STACK$$ZI$$Limit = ADDR(.msp_stack) + SIZEOF(.msp_stack);
+#endif
+    __stack = Image$$ARM_LIB_STACK$$ZI$$Limit;
+
+#ifdef ENABLE_HEAP
+    .heap (NOLOAD) : ALIGN(8)
+    {
+        . += S_HEAP_SIZE;
+    } > RAM
+    __heap_start = ADDR(.heap);
+    __heap_end = ADDR(.heap) + SIZEOF(.heap);
+    __heap_size = SIZEOF(.heap);
+#endif
+
+{% for partition in partitions %}
+    {% if partition.manifest.type == 'PSA-ROT' %}
+
+    .ER_{{partition.manifest.name}}_DATA : ALIGN(TFM_LINKER_PT_PROT_PART_PRIVATE_DATA_ALIGNMENT)
+    {
+        /* Position tag: Start of PSA RoT partition's private data */
+        Image$$PT_{{partition.manifest.name}}_PRIVATE_DATA_START$$Base = .;
+    {% if partition.attr.linker_pattern.library_list %}
+        {% for pattern in partition.attr.linker_pattern.library_list %}
+        {{pattern}}:*(SORT_BY_ALIGNMENT(.data*))
+        {% endfor %}
+    {% endif %}
+    {% if partition.attr.linker_pattern.object_list %}
+        {% for pattern in partition.attr.linker_pattern.object_list %}
+        {{pattern}}(SORT_BY_ALIGNMENT(.data*))
+        {% endfor %}
+    {% endif %}
+        *({{partition.manifest.name}}_PSA-ROT_ATTR_RW)
+        . = ALIGN(4);
+    } > RAM AT > FLASH
+
+    .ER_{{partition.manifest.name}}_BSS ALIGN(8) (NOLOAD) :
+    {
+        start_of_{{partition.manifest.name}}_bss = .;
+    {% if partition.attr.linker_pattern.library_list %}
+        {% for pattern in partition.attr.linker_pattern.library_list %}
+        {{pattern}}:*(SORT_BY_ALIGNMENT(.bss*))
+        {{pattern}}:*(COMMON)
+        {% endfor %}
+    {% endif %}
+    {% if partition.attr.linker_pattern.object_list %}
+        {% for pattern in partition.attr.linker_pattern.object_list %}
+        {{pattern}}(SORT_BY_ALIGNMENT(.bss*))
+        {{pattern}}(COMMON)
+        {% endfor %}
+    {% endif %}
+        *({{partition.manifest.name}}_PSA-ROT_ATTR_ZI)
+        . += (. - start_of_{{partition.manifest.name}}_bss) ? 0 : 4;
+    } > RAM
+
+    /* Position tag: End of PSA RoT partition's private data */
+    . = ALIGN(TFM_LINKER_PT_PROT_PART_PRIVATE_DATA_ALIGNMENT);
+    Image$$PT_{{partition.manifest.name}}_PRIVATE_DATA_END$$Base = .;
+
+    {% endif %}
+{% endfor %}
+
+    .TFM_DATA ALIGN(4) :
+    {
+        *(SORT_BY_ALIGNMENT(.data*))
+
+        KEEP(*(.jcr*))
+        . = ALIGN(4);
+    } > RAM AT > FLASH
+
+    .TFM_BSS ALIGN(TFM_LINKER_DEFAULT_ALIGNMENT) (NOLOAD) :
+    {
+        /* The runtime partition placed order is same as load partition */
+        __partition_runtime_start__ = .;
+        KEEP(*(.bss.part_runtime_priority_00))
+        KEEP(*(.bss.part_runtime_priority_01))
+        KEEP(*(.bss.part_runtime_priority_02))
+        KEEP(*(.bss.part_runtime_priority_03))
+        __partition_runtime_end__ = .;
+        . = ALIGN(4);
+
+        /* The runtime service placed order is same as load partition */
+        __service_runtime_start__ = .;
+        KEEP(*(.bss.serv_runtime_priority_00))
+        KEEP(*(.bss.serv_runtime_priority_01))
+        KEEP(*(.bss.serv_runtime_priority_02))
+        KEEP(*(.bss.serv_runtime_priority_03))
+        __service_runtime_end__ = .;
+        *(SORT_BY_ALIGNMENT(.bss*))
+        *(COMMON)
+        . = ALIGN(4);
+    } > RAM
+    Image$$ER_PART_RT_POOL$$ZI$$Base = __partition_runtime_start__;
+    Image$$ER_PART_RT_POOL$$ZI$$Limit = __partition_runtime_end__;
+    Image$$ER_SERV_RT_POOL$$ZI$$Base = __service_runtime_start__;
+    Image$$ER_SERV_RT_POOL$$ZI$$Limit = __service_runtime_end__;
+
+    /* Position tag: End of PSA RoT data (privileged) */
+    . = ALIGN(TFM_LINKER_PT_PSA_ROT_DATA_ALIGNMENT);
+    Image$$PT_PSA_ROT_DATA_END$$Base = .;
+
+#ifdef RAM_VECTORS_SUPPORT
+    .ramVectors ALIGN(TFM_LINKER_RAM_VECTORS_ALIGNMENT) (NOLOAD) :
+    {
+        __ram_vectors_start__ = .;
+        KEEP(*(.ram_vectors))
+        __ram_vectors_end__   = .;
+    } > RAM
+#endif
+
+#ifdef CONFIG_TFM_USE_TRUSTZONE
+    Image$$ER_VENEER$$Base = ADDR(.gnu.sgstubs);
+    Image$$VENEER_ALIGN$$Limit = ADDR(.sgstubs_end);
+
+#ifdef TFM_LINKER_VENEERS_SIZE
+    ASSERT ((Image$$VENEER_ALIGN$$Limit - Image$$ER_VENEER$$Base) <= TFM_LINKER_VENEERS_SIZE, "Veneer region overflowed")
+#endif
+#endif
+
+    Load$$LR$$LR_NS_PARTITION$$Base = NS_PARTITION_START;
+
+#ifdef BL2
+    Load$$LR$$LR_SECONDARY_PARTITION$$Base = SECONDARY_PARTITION_START;
+#endif /* BL2 */
+}
diff --git a/platform/ext/common/uart_stdout.c b/platform/ext/common/uart_stdout.c
index 6e9277f..fec035a 100644
--- a/platform/ext/common/uart_stdout.c
+++ b/platform/ext/common/uart_stdout.c
@@ -81,6 +81,28 @@
     /* Return character written */
     return ch;
 }
+
+/* Redirect sdtio for PicoLib in LLVM toolchain
+   as per https://github.com/picolibc/picolibc/blob/main/doc/os.md
+   'fputch()' named intentionally different from 'fputc()' from picolib */
+#elif defined(__clang_major__)
+
+int fputch(char ch, struct __file *f)
+{
+    (void)f;
+
+    /* Send byte to USART */
+    (void)stdio_output_string((const char *)&ch, 1);
+
+    /* Return character written */
+    return ch;
+}
+
+static FILE __stdio = FDEV_SETUP_STREAM(fputch, NULL, NULL, _FDEV_SETUP_WRITE);
+FILE *const stdin = &__stdio;
+__strong_reference(stdin, stdout);
+__strong_reference(stdin, stderr);
+
 #elif defined(__GNUC__)
 /* Redirects printf to STDIO_DRIVER in case of GNUARM */
 int _write(int fd, char *str, int len)
diff --git a/platform/ext/target/arm/mps2/an521/CMakeLists.txt b/platform/ext/target/arm/mps2/an521/CMakeLists.txt
index ed98be0..d327576 100644
--- a/platform/ext/target/arm/mps2/an521/CMakeLists.txt
+++ b/platform/ext/target/arm/mps2/an521/CMakeLists.txt
@@ -33,6 +33,7 @@
     $<$<C_COMPILER_ID:ARMClang>:${CMAKE_BINARY_DIR}/generated/platform/ext/common/armclang/tfm_isolation_s.sct>
     $<$<C_COMPILER_ID:GNU>:${CMAKE_BINARY_DIR}/generated/platform/ext/common/gcc/tfm_isolation_s.ld>
     $<$<C_COMPILER_ID:IAR>:${CMAKE_BINARY_DIR}/generated/platform/ext/common/iar/tfm_isolation_s.icf>
+    $<$<C_COMPILER_ID:Clang>:${CMAKE_BINARY_DIR}/generated/platform/ext/common/llvm/tfm_isolation_s.ld>
 )
 
 if(BL2)
@@ -44,6 +45,7 @@
             $<$<C_COMPILER_ID:ARMClang>:${PLATFORM_DIR}/ext/common/armclang/tfm_common_bl2.sct>
             $<$<C_COMPILER_ID:GNU>:${PLATFORM_DIR}/ext/common/gcc/tfm_common_bl2.ld>
             $<$<C_COMPILER_ID:IAR>:${PLATFORM_DIR}/ext/common/iar/tfm_common_bl2.icf>
+            $<$<C_COMPILER_ID:Clang>:${PLATFORM_DIR}/ext/common/llvm/tfm_common_bl2.ld>
     )
 endif()
 
@@ -171,6 +173,7 @@
 install(FILES       ${PLATFORM_DIR}/ext/common/gcc/tfm_common_ns.ld
                     ${PLATFORM_DIR}/ext/common/armclang/tfm_common_ns.sct
                     ${PLATFORM_DIR}/ext/common/iar/tfm_common_ns.icf
+                    ${PLATFORM_DIR}/ext/common/llvm/tfm_common_ns.ldc
         DESTINATION ${INSTALL_PLATFORM_NS_DIR}/linker_scripts)
 
 # copy all files from active platform directory
diff --git a/platform/ns/toolchain_ns_LLVM.cmake b/platform/ns/toolchain_ns_LLVM.cmake
new file mode 100644
index 0000000..9d066bd
--- /dev/null
+++ b/platform/ns/toolchain_ns_LLVM.cmake
@@ -0,0 +1,212 @@
+#-------------------------------------------------------------------------------
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+#-------------------------------------------------------------------------------
+
+set(CMAKE_SYSTEM_NAME Generic)
+
+# Specify the cross compiler
+set(CMAKE_C_COMPILER clang)
+set(CMAKE_ASM_COMPILER clang)
+set(CMAKE_C_COMPILER_FORCED TRUE)
+set(CMAKE_ASM_COMPILER_FORCED TRUE)
+
+if(NOT DEFINED CROSS_COMPILE)
+    set(CROSS_COMPILE    arm-none-eabi CACHE STRING "Cross-compiler prefix")
+endif()
+set(CMAKE_C_COMPILER_TARGET ${CROSS_COMPILE})
+set(CMAKE_ASM_COMPILER_TARGET ${CROSS_COMPILE})
+
+set(CMAKE_USER_MAKE_RULES_OVERRIDE ${CMAKE_CURRENT_LIST_DIR}/set_extensions.cmake)
+
+# CMAKE_C_COMPILER_VERSION is not guaranteed to be defined.
+EXECUTE_PROCESS( COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE LLVM_VERSION )
+if (LLVM_VERSION VERSION_LESS 18.1.3)
+    message(FATAL_ERROR "Please use newer LLVM compiler version starting from 18.1.3")
+endif()
+
+# ===================== Set toolchain CPU and Arch =============================
+# -mcpu gives better optimisation than -march so -mcpu shall be in preference
+
+if (TFM_SYSTEM_PROCESSOR)
+    if(TFM_SYSTEM_DSP)
+        string(APPEND TFM_SYSTEM_PROCESSOR "+dsp")
+    else()
+        string(APPEND TFM_SYSTEM_PROCESSOR "+nodsp")
+    endif()
+    if(CONFIG_TFM_ENABLE_FP)
+        string(APPEND TFM_SYSTEM_PROCESSOR "+fp")
+    else()
+        string(APPEND TFM_SYSTEM_PROCESSOR "+nofp")
+    endif()
+
+    set(CMAKE_C_FLAGS        "-mcpu=${TFM_SYSTEM_PROCESSOR}")
+    set(CMAKE_ASM_FLAGS      "-mcpu=${TFM_SYSTEM_PROCESSOR}")
+else()
+    if(CONFIG_TFM_ENABLE_FP)
+        string(APPEND TFM_SYSTEM_ARCHITECTURE "+fp")
+    endif()
+    if(TFM_SYSTEM_DSP)
+        string(APPEND TFM_SYSTEM_ARCHITECTURE "+dsp")
+    endif()
+    set(CMAKE_C_FLAGS        "-march=${TFM_SYSTEM_ARCHITECTURE}")
+    set(CMAKE_ASM_FLAGS      "-march=${TFM_SYSTEM_ARCHITECTURE}")
+    set(CMAKE_ASM_CPU_FLAG  ${TFM_SYSTEM_ARCHITECTURE})
+endif()
+
+if (CONFIG_TFM_FLOAT_ABI STREQUAL "hard")
+    set(COMPILER_CP_FLAG -mfloat-abi=hard)
+    set(LINKER_CP_OPTION -mfloat-abi=hard)
+    if (CONFIG_TFM_ENABLE_FP OR CONFIG_TFM_ENABLE_MVE_FP)
+        set(COMPILER_CP_FLAG -mfloat-abi=hard -mfpu=${CONFIG_TFM_FP_ARCH})
+        set(LINKER_CP_OPTION -mfloat-abi=hard -mfpu=${CONFIG_TFM_FP_ARCH})
+    endif()
+else()
+    set(COMPILER_CP_FLAG -mfloat-abi=soft)
+    set(LINKER_CP_OPTION -mfloat-abi=soft)
+endif()
+
+set(BL1_COMPILER_CP_FLAG -mfloat-abi=soft)
+set(BL1_LINKER_CP_OPTION -mfloat-abi=soft)
+
+set(BL2_COMPILER_CP_FLAG -mfloat-abi=soft)
+set(BL2_LINKER_CP_OPTION -mfloat-abi=soft)
+
+add_compile_options(
+     -Wno-ignored-optimization-argument
+     -Wno-unused-command-line-argument
+     -Wall
+     -Wno-error=cpp
+     -c
+     -fdata-sections
+     -ffunction-sections
+     -fno-builtin
+     -fshort-enums
+     -fshort-wchar
+     -funsigned-char
+     -std=c99
+)
+
+# Pointer Authentication Code and Branch Target Identification (PACBTI) Options
+# Not currently supported for LLVM.
+if(NOT ${CONFIG_TFM_BRANCH_PROTECTION_FEAT} STREQUAL BRANCH_PROTECTION_DISABLED)
+    message(FATAL_ERROR "BRANCH_PROTECTION NOT supported for LLVM")
+endif()
+
+add_link_options(
+    LINKER:-check-sections
+    LINKER:-fatal-warnings
+    LINKER:--gc-sections
+    LINKER:--print-memory-usage
+    LINKER:-lcrt0 -ldummyhost
+    LINKER:--Map=bin/tfm_ns.map
+)
+
+#add_compile_definitions($<$<STREQUAL:${TFM_SYSTEM_ARCHITECTURE},armv8.1-m.main>:__ARM_ARCH_8_1M_MAIN__=1>)
+
+# Specify the scatter file used to link `target`.
+# Behaviour for handling scatter files is so wildly divergent between compilers
+# that this macro is required.
+#
+# Vendor platform can set a scatter file as property INTERFACE_LINK_DEPENDS of platform_ns.
+# `target` can fetch the scatter file from platform_ns.
+#
+# Alternatively, NS build can call target_add_scatter_file() with the install directory of
+# scatter files.
+#     target_add_scatter_file(target, install_dir)
+#
+# target_add_scatter_file() fetch a scatter file from the install directory.
+macro(target_add_scatter_file target)
+
+    # Try if scatter_file is passed from platform_ns
+    get_target_property(scatter_file
+                        platform_ns
+                        INTERFACE_LINK_DEPENDS
+    )
+
+    # If scatter_file is not passed from platform_ns
+    # Try if any scatter file is exported in install directory
+    # The intall directory is passed as an optinal argument
+    if(${scatter_file} STREQUAL "scatter_file-NOTFOUND")
+        set(install_dir ${ARGN})
+        list(LENGTH install_dir nr_install_dir)
+
+        # If nr_install_dir == 1, search for sct file under install dir
+        if(${nr_install_dir} EQUAL 1)
+            file(GLOB scatter_file "${install_dir}/*.ldc")
+        endif()
+    endif()
+
+    if(NOT EXISTS ${scatter_file})
+        message(FATAL_ERROR "Unable to find NS scatter file ${scatter_file}")
+    endif()
+
+    add_library(${target}_scatter OBJECT)
+    target_sources(${target}_scatter
+        PRIVATE
+            ${scatter_file}
+    )
+
+    # Cmake cannot use generator expressions in the
+    # set_source_file_properties command, so instead we just parse the regex
+    # for the filename and set the property on all files, regardless of if
+    # the generator expression would evaluate to true or not.
+    string(REGEX REPLACE ".*>:(.*)>$" "\\1" SCATTER_FILE_PATH "${scatter_file}")
+    set_source_files_properties(${SCATTER_FILE_PATH}
+        PROPERTIES
+        LANGUAGE C
+        KEEP_EXTENSION True # Avoid *.o extension for the preprocessed file
+    )
+
+    target_link_libraries(${target}_scatter PRIVATE platform_region_defs)
+
+    target_compile_options(${target}_scatter PRIVATE -E -xc)
+
+    target_link_options(${target} PRIVATE -T $<TARGET_OBJECTS:${target}_scatter>)
+
+    add_dependencies(${target} ${target}_scatter)
+    set_target_properties(${target} PROPERTIES LINK_DEPENDS $<TARGET_OBJECTS:${target}_scatter>)
+
+endmacro()
+
+# Macro for converting the output *.axf file to finary files: bin, elf, hex
+macro(add_convert_to_bin_target target)
+    get_target_property(bin_dir ${target} RUNTIME_OUTPUT_DIRECTORY)
+
+    add_custom_target(${target}_bin
+        SOURCES ${bin_dir}/${target}.bin
+    )
+    add_custom_command(OUTPUT ${bin_dir}/${target}.bin
+        DEPENDS ${target}
+        COMMAND ${CMAKE_OBJCOPY}
+            -O binary $<TARGET_FILE:${target}>
+            ${bin_dir}/${target}.bin
+    )
+
+    add_custom_target(${target}_elf
+        SOURCES ${bin_dir}/${target}.elf
+    )
+    add_custom_command(OUTPUT ${bin_dir}/${target}.elf
+        DEPENDS ${target}
+        COMMAND ${CMAKE_OBJCOPY}
+            -O elf32-littlearm $<TARGET_FILE:${target}>
+            ${bin_dir}/${target}.elf
+    )
+
+    add_custom_target(${target}_hex
+        SOURCES ${bin_dir}/${target}.hex
+    )
+    add_custom_command(OUTPUT ${bin_dir}/${target}.hex
+        DEPENDS ${target}
+        COMMAND ${CMAKE_OBJCOPY}
+            -O ihex $<TARGET_FILE:${target}>
+            ${bin_dir}/${target}.hex
+    )
+
+    add_custom_target(${target}_binaries
+        ALL
+        DEPENDS ${target}_bin
+        DEPENDS ${target}_elf
+        DEPENDS ${target}_hex
+    )
+endmacro()
diff --git a/secure_fw/CMakeLists.txt b/secure_fw/CMakeLists.txt
index 87b7943..de39ad4 100644
--- a/secure_fw/CMakeLists.txt
+++ b/secure_fw/CMakeLists.txt
@@ -76,10 +76,10 @@
 
 target_link_options(tfm_s
     PRIVATE
-        --entry=Reset_Handler
         $<$<C_COMPILER_ID:GNU>:-Wl,-Map=${CMAKE_BINARY_DIR}/bin/tfm_s.map>
         $<$<C_COMPILER_ID:ARMClang>:--map>
         $<$<C_COMPILER_ID:IAR>:--map\;${CMAKE_BINARY_DIR}/bin/tfm_s.map>
+        $<$<C_COMPILER_ID:Clang>:-Wl,-Map=${CMAKE_BINARY_DIR}/bin/tfm_s.map -nostdlib>
     PUBLIC
         ${LINKER_CP_OPTION}
 )
diff --git a/secure_fw/include/security_defs.h b/secure_fw/include/security_defs.h
index a048356..a5929d4 100644
--- a/secure_fw/include/security_defs.h
+++ b/secure_fw/include/security_defs.h
@@ -21,6 +21,12 @@
 /* Attributes for psa api secure gateway functions */
 #if defined(__GNUC__) && !defined(__ARMCC_VERSION)
 /*
+ * LLVM offers 'noduplicate' attribute as 'noclone' equivalent in GNUARM
+ */
+#if defined(__clang__)
+#define noclone noduplicate
+#endif /* __clang__ */
+/*
  * GNUARM requires noclone attribute to protect gateway function symbol from
  * being renamed and cloned
  */
diff --git a/secure_fw/partitions/crypto/CMakeLists.txt b/secure_fw/partitions/crypto/CMakeLists.txt
index 38545fb..ddd16f2 100644
--- a/secure_fw/partitions/crypto/CMakeLists.txt
+++ b/secure_fw/partitions/crypto/CMakeLists.txt
@@ -203,6 +203,7 @@
         $<$<C_COMPILER_ID:GNU>:-Wno-unused-parameter>
         $<$<C_COMPILER_ID:ARMClang>:-Wno-unused-const-variable>
         $<$<C_COMPILER_ID:ARMClang>:-Wno-unused-parameter>
+        $<$<C_COMPILER_ID:Clang>:-Wno-unused-parameter>
 )
 
 if(MBEDTLS_P256M_ENABLED)
diff --git a/secure_fw/partitions/lib/runtime/CMakeLists.txt b/secure_fw/partitions/lib/runtime/CMakeLists.txt
index 1fdad7a..12e3116 100644
--- a/secure_fw/partitions/lib/runtime/CMakeLists.txt
+++ b/secure_fw/partitions/lib/runtime/CMakeLists.txt
@@ -20,10 +20,13 @@
     PUBLIC
         $<$<BOOL:${CONFIG_GNU_SYSCALL_STUB_ENABLED}>:${CMAKE_SOURCE_DIR}/platform/ext/common/syscalls_stub.c>
     PRIVATE
-        ./crt_memcmp.c
-        ./crt_memmove.c
-        ./crt_strnlen.c
-        ./service_api.c
+        crt_memcmp.c
+        crt_memmove.c
+        crt_strnlen.c
+        $<$<C_COMPILER_ID:Clang>:crt_start.c>
+        $<$<C_COMPILER_ID:Clang>:crt_exit.c>
+        $<$<C_COMPILER_ID:Clang>:crt_strlen.c>
+        service_api.c
         ${CMAKE_SOURCE_DIR}/secure_fw/shared/crt_memcpy.c
         ${CMAKE_SOURCE_DIR}/secure_fw/shared/crt_memset.c
         $<$<BOOL:${CONFIG_TFM_PARTITION_META}>:./sprt_partition_metadata_indicator.c>
diff --git a/secure_fw/partitions/lib/runtime/crt_exit.c b/secure_fw/partitions/lib/runtime/crt_exit.c
new file mode 100644
index 0000000..1c80e66
--- /dev/null
+++ b/secure_fw/partitions/lib/runtime/crt_exit.c
@@ -0,0 +1,10 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ */
+
+void exit(void)
+{
+    while (1)
+        ;
+}
diff --git a/secure_fw/partitions/lib/runtime/crt_start.c b/secure_fw/partitions/lib/runtime/crt_start.c
new file mode 100644
index 0000000..5833072
--- /dev/null
+++ b/secure_fw/partitions/lib/runtime/crt_start.c
@@ -0,0 +1,52 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ */
+
+#include "utilities.h"
+
+#if defined(__clang_major__) && defined(__GNUC__)
+
+/*
+ * We can not use CMSIS support for LLVM toolchain because it's incompatible
+ * with it. That's why we manunally implement the startup routine below.
+ */
+
+typedef struct __copy_table {
+    uint32_t const *src;
+    uint32_t *dest;
+    uint32_t wlen;
+} __copy_table_t;
+
+typedef struct __zero_table {
+    uint32_t *dest;
+    uint32_t wlen;
+} __zero_table_t;
+
+extern const __copy_table_t __copy_table_start__;
+extern const __copy_table_t __copy_table_end__;
+extern const __zero_table_t __zero_table_start__;
+extern const __zero_table_t __zero_table_end__;
+
+extern int main(int argc, char **argv);
+
+void _start(void)
+{
+    for (__copy_table_t const *pTable = &__copy_table_start__; pTable < &__copy_table_end__; ++pTable) {
+        for (uint32_t i = 0u; i < pTable->wlen; ++i) {
+            pTable->dest[i] = pTable->src[i];
+        }
+    }
+
+    for (__zero_table_t const *pTable = &__zero_table_start__; pTable < &__zero_table_end__; ++pTable) {
+        for (uint32_t i = 0u; i < pTable->wlen; ++i) {
+            pTable->dest[i] = 0u;
+        }
+    }
+    main(0, NULL);
+    while (1)
+        ;
+}
+#else
+#error This startup file shall be used in LLVM toolchain only.
+#endif
diff --git a/secure_fw/partitions/lib/runtime/crt_strlen.c b/secure_fw/partitions/lib/runtime/crt_strlen.c
new file mode 100644
index 0000000..7213cb0
--- /dev/null
+++ b/secure_fw/partitions/lib/runtime/crt_strlen.c
@@ -0,0 +1,17 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#include <stddef.h>
+
+size_t strlen(const char *s)
+{
+    size_t idx = 0;
+
+    while (s[idx] != '\0') {
+        idx++;
+    }
+    return idx;
+}
diff --git a/toolchain_LLVM.cmake b/toolchain_LLVM.cmake
new file mode 100644
index 0000000..d0f88f7
--- /dev/null
+++ b/toolchain_LLVM.cmake
@@ -0,0 +1,257 @@
+#-------------------------------------------------------------------------------
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+#-------------------------------------------------------------------------------
+
+set(CMAKE_SYSTEM_NAME Generic)
+
+# Specify the cross compiler
+set(CMAKE_C_COMPILER clang)
+set(CMAKE_C_COMPILER_TARGET ${CROSS_COMPILE})
+
+set(CMAKE_ASM_COMPILER clang)
+set(CMAKE_ASM_COMPILER_TARGET ${CROSS_COMPILE})
+
+set(LINKER_VENEER_OUTPUT_FLAG -Wl,--cmse-implib,--out-implib=)
+set(COMPILER_CMSE_FLAG -mcmse -mfix-cmse-cve-2021-35465)
+
+set(CMAKE_USER_MAKE_RULES_OVERRIDE ${CMAKE_CURRENT_LIST_DIR}/cmake/set_extensions.cmake)
+
+# CMAKE_C_COMPILER_VERSION is not guaranteed to be defined.
+EXECUTE_PROCESS( COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE LLVM_VERSION )
+if (LLVM_VERSION VERSION_LESS 18.1.3)
+    message(FATAL_ERROR "Please use newer LLVM compiler version starting from 18.1.3")
+endif()
+
+# ===================== Set toolchain CPU and Arch =============================
+# -mcpu gives better optimisation than -march so -mcpu shall be in preference
+
+if (TFM_SYSTEM_PROCESSOR)
+    if(TFM_SYSTEM_DSP)
+        string(APPEND TFM_SYSTEM_PROCESSOR "+dsp")
+    else()
+        string(APPEND TFM_SYSTEM_PROCESSOR "+nodsp")
+    endif()
+    if(CONFIG_TFM_ENABLE_FP)
+        string(APPEND TFM_SYSTEM_PROCESSOR "+fp")
+    else()
+        string(APPEND TFM_SYSTEM_PROCESSOR "+nofp")
+    endif()
+
+    set(CMAKE_C_FLAGS        "-mcpu=${TFM_SYSTEM_PROCESSOR}")
+    set(CMAKE_ASM_FLAGS      "-mcpu=${TFM_SYSTEM_PROCESSOR}")
+else()
+    if(CONFIG_TFM_ENABLE_FP)
+        string(APPEND TFM_SYSTEM_ARCHITECTURE "+fp")
+    endif()
+    if(NOT TFM_SYSTEM_DSP)
+        string(APPEND TFM_SYSTEM_ARCHITECTURE "+nodsp")
+    endif()
+    set(CMAKE_C_FLAGS        "-march=${TFM_SYSTEM_ARCHITECTURE}")
+    set(CMAKE_CXX_FLAGS      "-march=${TFM_SYSTEM_ARCHITECTURE}")
+    set(CMAKE_ASM_FLAGS      "-march=${TFM_SYSTEM_ARCHITECTURE}")
+    set(CMAKE_ASM_CPU_FLAG  ${TFM_SYSTEM_ARCHITECTURE})
+endif()
+
+if (CONFIG_TFM_FLOAT_ABI STREQUAL "hard")
+    set(COMPILER_CP_FLAG -mfloat-abi=hard)
+    set(LINKER_CP_OPTION -mfloat-abi=hard)
+    if (CONFIG_TFM_ENABLE_FP OR CONFIG_TFM_ENABLE_MVE_FP)
+        set(COMPILER_CP_FLAG -mfloat-abi=hard -mfpu=${CONFIG_TFM_FP_ARCH})
+        set(LINKER_CP_OPTION -mfloat-abi=hard -mfpu=${CONFIG_TFM_FP_ARCH})
+    endif()
+else()
+    set(COMPILER_CP_FLAG -mfloat-abi=soft)
+    set(LINKER_CP_OPTION -mfloat-abi=soft)
+endif()
+
+set(BL1_COMPILER_CP_FLAG -mfloat-abi=soft)
+set(BL1_LINKER_CP_OPTION -mfloat-abi=soft)
+
+set(BL2_COMPILER_CP_FLAG -mfloat-abi=soft)
+set(BL2_LINKER_CP_OPTION -mfloat-abi=soft)
+
+add_compile_options(
+     -Wno-ignored-optimization-argument
+     -Wno-unused-command-line-argument
+     -Wall
+     -Wno-error=cpp
+     -c
+     -fdata-sections
+     -ffunction-sections
+     -fno-builtin
+     -fshort-enums
+     -fshort-wchar
+     -funsigned-char
+     -std=c99
+)
+
+# Pointer Authentication Code and Branch Target Identification (PACBTI) Options
+# Not currently supported for LLVM.
+if(NOT ${CONFIG_TFM_BRANCH_PROTECTION_FEAT} STREQUAL BRANCH_PROTECTION_DISABLED)
+    message(FATAL_ERROR "BRANCH_PROTECTION NOT supported for LLVM")
+endif()
+
+add_link_options(
+    -lclang_rt.builtins   # needed for  __aeabi_memclr4(), __aeabi_memclr8(), __aeabi_memcpy4()
+    LINKER:-check-sections
+    LINKER:-fatal-warnings
+    LINKER:--gc-sections
+)
+
+if(NOT CONFIG_TFM_MEMORY_USAGE_QUIET)
+    add_link_options(LINKER:--print-memory-usage)
+endif()
+
+# Macro for adding scatter files. Supports multiple files
+macro(target_add_scatter_file target)
+    target_link_options(${target} PRIVATE -T $<TARGET_OBJECTS:${target}_scatter>)
+
+    add_library(${target}_scatter OBJECT)
+    foreach(scatter_file ${ARGN})
+        target_sources(${target}_scatter
+            PRIVATE
+                ${scatter_file}
+        )
+        # Cmake cannot use generator expressions in the
+        # set_source_file_properties command, so instead we just parse the regex
+        # for the filename and set the property on all files, regardless of if
+        # the generator expression would evaluate to true or not.
+        string(REGEX REPLACE ".*>:(.*)>$" "\\1" SCATTER_FILE_PATH "${scatter_file}")
+        set_source_files_properties(${SCATTER_FILE_PATH}
+            PROPERTIES
+            LANGUAGE C
+            KEEP_EXTENSION True # Don't use .o extension for the preprocessed file
+        )
+    endforeach()
+
+    add_dependencies(${target} ${target}_scatter)
+
+    set_property(TARGET ${target} APPEND PROPERTY LINK_DEPENDS $<TARGET_OBJECTS:${target}_scatter>)
+
+    target_link_libraries(${target}_scatter
+        platform_region_defs
+        psa_interface
+        tfm_config
+    )
+
+    target_compile_options(${target}_scatter PRIVATE -E -P -xc)
+endmacro()
+
+# Macro for converting the output *.axf file to finary files: bin, elf, hex
+macro(add_convert_to_bin_target target)
+    get_target_property(bin_dir ${target} RUNTIME_OUTPUT_DIRECTORY)
+    add_custom_target(${target}_bin
+        ALL DEPENDS ${target}
+        COMMAND ${CMAKE_OBJCOPY} -O binary $<TARGET_FILE:${target}> ${bin_dir}/${target}.bin
+        COMMAND ${CMAKE_OBJCOPY} -O elf32-littlearm $<TARGET_FILE:${target}> ${bin_dir}/${target}.elf
+        COMMAND ${CMAKE_OBJCOPY} -O ihex $<TARGET_FILE:${target}> ${bin_dir}/${target}.hex
+    )
+endmacro()
+
+# Set of macrots for sharing code between BL2 and RunTime, targeted for sharing MbedTLS library
+macro(target_share_symbols target)
+    get_target_property(TARGET_TYPE ${target} TYPE)
+    if (NOT TARGET_TYPE STREQUAL "EXECUTABLE")
+        message(FATAL_ERROR "${target} is not an executable. Symbols cannot be shared from libraries.")
+    endif()
+
+    foreach(symbol_file ${ARGN})
+        FILE(STRINGS ${symbol_file} SYMBOLS
+            LENGTH_MINIMUM 1
+        )
+        list(APPEND KEEP_SYMBOL_LIST ${SYMBOLS})
+    endforeach()
+
+    set(STRIP_SYMBOL_KEEP_LIST ${KEEP_SYMBOL_LIST})
+
+    # Force the target to not remove the symbols if they're unused.
+    list(TRANSFORM KEEP_SYMBOL_LIST PREPEND "-Wl,--undefined=")
+    target_link_options(${target}
+        PRIVATE
+            ${KEEP_SYMBOL_LIST}
+    )
+
+    list(TRANSFORM STRIP_SYMBOL_KEEP_LIST PREPEND  --keep-symbol=)
+    # strip all the symbols except those proveded as arguments
+    add_custom_target(${target}_shared_symbols
+        COMMAND ${CMAKE_OBJCOPY}
+            $<TARGET_FILE:${target}>
+            --wildcard ${STRIP_SYMBOL_KEEP_LIST}
+            --strip-all
+            $<TARGET_FILE_DIR:${target}>/${target}${CODE_SHARING_OUTPUT_FILE_SUFFIX}
+    )
+
+    # Ensure ${target} is built before $<TARGET_FILE:${target}> is used to generate ${target}_shared_symbols
+    add_dependencies(${target}_shared_symbols ${target})
+    # Allow the global clean target to rm the ${target}_shared_symbols created
+    set_target_properties(${target}_shared_symbols PROPERTIES
+        ADDITIONAL_CLEAN_FILES $<TARGET_FILE_DIR:${target}>/${target}${CODE_SHARING_OUTPUT_FILE_SUFFIX}
+    )
+endmacro()
+
+macro(target_link_shared_code target)
+    foreach(symbol_provider ${ARGN})
+        if (TARGET ${symbol_provider})
+            get_target_property(SYMBOL_PROVIDER_TYPE ${symbol_provider} TYPE)
+            if (NOT SYMBOL_PROVIDER_TYPE STREQUAL "EXECUTABLE")
+                message(FATAL_ERROR "${symbol_provider} is not an executable. Symbols cannot be shared from libraries.")
+            endif()
+        endif()
+
+        # Ensure ${symbol_provider}_shared_symbols is built before ${target}
+        add_dependencies(${target} ${symbol_provider}_shared_symbols)
+        # ${symbol_provider}_shared_symbols - a custom target is always considered out-of-date
+        # To only link when necessary, depend on ${symbol_provider} instead
+        set_property(TARGET ${target} APPEND PROPERTY LINK_DEPENDS $<TARGET_OBJECTS:${symbol_provider}>)
+        target_link_options(${target} PRIVATE LINKER:-R$<TARGET_FILE_DIR:${symbol_provider}>/${symbol_provider}${CODE_SHARING_INPUT_FILE_SUFFIX})
+    endforeach()
+endmacro()
+
+macro(target_strip_symbols target)
+    set(SYMBOL_LIST "${ARGN}")
+    list(TRANSFORM SYMBOL_LIST PREPEND  --strip-symbol=)
+
+    add_custom_command(
+        TARGET ${target}
+        POST_BUILD
+        COMMAND ${CMAKE_OBJCOPY}
+        ARGS $<TARGET_FILE:${target}> --wildcard ${SYMBOL_LIST} $<TARGET_FILE:${target}>
+    )
+endmacro()
+
+macro(target_strip_symbols_from_dependency target dependency)
+    set(SYMBOL_LIST "${ARGN}")
+    list(TRANSFORM SYMBOL_LIST PREPEND  --strip-symbol=)
+
+    add_custom_command(
+        TARGET ${target}
+        PRE_LINK
+        COMMAND ${CMAKE_OBJCOPY}
+        ARGS $<TARGET_FILE:${dependency}> --wildcard ${SYMBOL_LIST} $<TARGET_FILE:${dependency}>
+    )
+endmacro()
+
+macro(target_weaken_symbols target)
+    set(SYMBOL_LIST "${ARGN}")
+    list(TRANSFORM SYMBOL_LIST PREPEND  --weaken-symbol=)
+
+    add_custom_command(
+        TARGET ${target}
+        POST_BUILD
+        COMMAND ${CMAKE_OBJCOPY}
+        ARGS $<TARGET_FILE:${target}> --wildcard ${SYMBOL_LIST} $<TARGET_FILE:${target}>
+    )
+endmacro()
+
+macro(target_weaken_symbols_from_dependency target dependency)
+    set(SYMBOL_LIST "${ARGN}")
+    list(TRANSFORM SYMBOL_LIST PREPEND  --weaken-symbol=)
+
+    add_custom_command(
+        TARGET ${target}
+        PRE_LINK
+        COMMAND ${CMAKE_OBJCOPY}
+        ARGS $<TARGET_FILE:${dependency}> --wildcard ${SYMBOL_LIST} $<TARGET_FILE:${dependency}>
+    )
+endmacro()