build: Add IAR support to Corstone-315

Signed-off-by: Dávid Házi <david.hazi@arm.com>
Change-Id: Id0cc1e1c3a485567e50140968e9c6553f6bbb446
diff --git a/bl1/bl1_1/shared_lib/CMakeLists.txt b/bl1/bl1_1/shared_lib/CMakeLists.txt
index ff1d99e..1e4cda4 100644
--- a/bl1/bl1_1/shared_lib/CMakeLists.txt
+++ b/bl1/bl1_1/shared_lib/CMakeLists.txt
@@ -47,7 +47,8 @@
 target_compile_options(bl1_1_shared_lib_interface
     INTERFACE
         #Prevents warnings caused by C99 static assert workaround
-        -Wno-unused-local-typedefs
+        $<$<C_COMPILER_ID:GNU>:-Wno-unused-local-typedefs>
+        $<$<C_COMPILER_ID:ARMClang>:-Wno-unused-local-typedefs>
 )
 
 target_compile_definitions(bl1_1_shared_lib_interface
diff --git a/platform/ext/common/boot_hal_bl1_1.c b/platform/ext/common/boot_hal_bl1_1.c
index 5f5c738..8bc5273 100644
--- a/platform/ext/common/boot_hal_bl1_1.c
+++ b/platform/ext/common/boot_hal_bl1_1.c
@@ -36,11 +36,6 @@
 #endif /* defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__) \
        || defined(__ARM_ARCH_8_1M_MAIN__) */
 
-REGION_DECLARE(Image$$, BL1_1_ER_DATA_START, $$Base)[];
-REGION_DECLARE(Image$$, BL1_1_ER_DATA_LIMIT, $$Base)[];
-REGION_DECLARE(Image$$, BL1_2_ER_DATA_START, $$Base)[];
-REGION_DECLARE(Image$$, BL1_2_ER_DATA_LIMIT, $$Base)[];
-
 /*!
  * \brief Chain-loading the next image in the boot sequence.
  *
@@ -53,9 +48,6 @@
  *  - There are secrets in the memory: KDF parameter, symmetric key,
  *    manufacturer sensitive code/data, etc.
  */
-#if defined(__ICCARM__)
-#pragma required = boot_clear_ram_area
-#endif
 
 __WEAK __attribute__((naked)) void boot_jump_to_next_image(uint32_t reset_handler_addr)
 {
diff --git a/platform/ext/common/boot_hal_bl1_2.c b/platform/ext/common/boot_hal_bl1_2.c
index d8d022f..f237cd2 100644
--- a/platform/ext/common/boot_hal_bl1_2.c
+++ b/platform/ext/common/boot_hal_bl1_2.c
@@ -35,11 +35,17 @@
 #endif /* defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__) \
        || defined(__ARM_ARCH_8_1M_MAIN__) */
 
+#if defined(__ICCARM__)
+REGION_DECLARE(Image$$, BL1_1_ER_DATA, $$Base)[];
+REGION_DECLARE(Image$$, BL1_1_ER_DATA, $$Limit)[];
+REGION_DECLARE(Image$$, BL1_2_ER_DATA, $$Base)[];
+REGION_DECLARE(Image$$, BL1_2_ER_DATA, $$Limit)[];
+#else
 REGION_DECLARE(Image$$, BL1_1_ER_DATA_START, $$Base)[];
 REGION_DECLARE(Image$$, BL1_1_ER_DATA_LIMIT, $$Base)[];
 REGION_DECLARE(Image$$, BL1_2_ER_DATA_START, $$Base)[];
 REGION_DECLARE(Image$$, BL1_2_ER_DATA_LIMIT, $$Base)[];
-
+#endif
 /* Erase both BL1 data sections at the end of BL1_2
  * At the point this function is called, the SP has been set to the next image's
  * initial SP and this function itself will wipe the executing image's data
@@ -54,8 +60,13 @@
 #endif
         /* Clear the entire BL1_1 data section */
         "movs    r0, #0                                \n"
+#if defined(__ICCARM__)
+        "ldr     r1, =BL1_1_ER_DATA$$Base \n"
+        "ldr     r2, =BL1_1_ER_DATA$$Limit \n"
+#else
         "ldr     r1, =Image$$BL1_1_ER_DATA_START$$Base \n"
         "ldr     r2, =Image$$BL1_1_ER_DATA_LIMIT$$Base \n"
+#endif
         "subs    r2, r2, r1                            \n"
         "Loop_1:                                       \n"
         "subs    r2, #4                                \n"
@@ -65,8 +76,13 @@
         "Clear_done_1:                                 \n"
         /* Clear the entire BL1_2 data section */
         "movs    r0, #0                                \n"
+#if defined(__ICCARM__)
+        "ldr     r1, =BL1_2_ER_DATA$$Base \n"
+        "ldr     r2, =BL1_2_ER_DATA$$Limit \n"
+#else
         "ldr     r1, =Image$$BL1_2_ER_DATA_START$$Base \n"
         "ldr     r2, =Image$$BL1_2_ER_DATA_LIMIT$$Base \n"
+#endif
         "subs    r2, r2, r1                            \n"
         "Loop_2:                                       \n"
         "subs    r2, #4                                \n"
diff --git a/platform/ext/target/arm/mps4/corstone315/CMakeLists.txt b/platform/ext/target/arm/mps4/corstone315/CMakeLists.txt
index 481ec50..7a9f807 100644
--- a/platform/ext/target/arm/mps4/corstone315/CMakeLists.txt
+++ b/platform/ext/target/arm/mps4/corstone315/CMakeLists.txt
@@ -339,13 +339,13 @@
 target_add_scatter_file(bl1_1
     $<$<C_COMPILER_ID:ARMClang>:${CMAKE_CURRENT_SOURCE_DIR}/device/source/armclang/corstone315_bl1_1.sct>
     $<$<C_COMPILER_ID:GNU>:${CMAKE_CURRENT_SOURCE_DIR}/device/source/gcc/corstone315_bl1_1.ld>
+    $<$<C_COMPILER_ID:IAR>:${CMAKE_CURRENT_SOURCE_DIR}/device/source/iar/corstone315_bl1_1.icf>
 )
 
 target_sources(platform_bl1_1
     PRIVATE
         nv_counters.c
         otp_lcm.c
-        bl1/boot_hal_bl1_1.c
         cmsis_drivers/Driver_USART.c
         device/source/system_core_init.c
         device/source/startup_corstone315.c
@@ -365,22 +365,36 @@
         cmsis_includes_bl1
 )
 
+# If this is not added to the bl1_1 it will not correctly override the weak
+# functions and will instead be discarded as they are not in use.
+target_sources(bl1_1
+    PUBLIC
+        bl1/boot_hal_bl1_1.c
+)
+
 #========================= Platform BL1_2 =====================================#
 
 target_add_scatter_file(bl1_2
     $<$<C_COMPILER_ID:ARMClang>:${CMAKE_CURRENT_SOURCE_DIR}/device/source/armclang/corstone315_bl1_2.sct>
     $<$<C_COMPILER_ID:GNU>:${CMAKE_CURRENT_SOURCE_DIR}/device/source/gcc/corstone315_bl1_2.ld>
+    $<$<C_COMPILER_ID:IAR>:${CMAKE_CURRENT_SOURCE_DIR}/device/source/iar/corstone315_bl1_2.icf>
 )
 
 target_sources(platform_bl1_2
     PUBLIC
         device/source/startup_corstone315.c
     PRIVATE
-        bl1/boot_hal_bl1_2.c
         ${PLATFORM_DIR}/ext/target/arm/drivers/mpu/armv8m/mpu_armv8m_drv.c
 
 )
 
+# If this is not added to the bl1_2 it will not correctly override the weak
+# functions and will instead be discarded as they are not in use.
+target_sources(bl1_2
+    PRIVATE
+        bl1/boot_hal_bl1_2.c
+)
+
 target_compile_definitions(platform_bl1_2
     PUBLIC
         $<$<AND:$<BOOL:${CONFIG_TFM_BOOT_STORE_MEASUREMENTS}>,$<BOOL:${TFM_PARTITION_MEASURED_BOOT}>>:MEASURED_BOOT_API>
diff --git a/platform/ext/target/arm/mps4/corstone315/device/source/iar/corstone315_bl1_1.icf b/platform/ext/target/arm/mps4/corstone315/device/source/iar/corstone315_bl1_1.icf
new file mode 100644
index 0000000..2d424c1
--- /dev/null
+++ b/platform/ext/target/arm/mps4/corstone315/device/source/iar/corstone315_bl1_1.icf
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/* Linker script to configure memory regions. */
+/* This file will be run trough the pre-processor. */
+
+#include "region_defs.h"
+
+do not initialize  { section .noinit };
+initialize by copy { readwrite };
+
+define block ER_CODE            with fixed order, alignment = 8, size = BL1_1_CODE_SIZE {
+       section .intvec,
+       readonly
+};
+define block LR_CODE with fixed order {block ER_CODE};
+place at address BL1_1_CODE_START {block LR_CODE};
+
+define block TFM_SHARED_DATA        with alignment = 32, size = BOOT_TFM_SHARED_DATA_SIZE { };
+define block ER_DATA                with alignment = 32 {readwrite};
+define block CSTACK                 with alignment = 32, size = BL1_1_MSP_STACK_SIZE { };
+define block ARM_LIB_STACK          with alignment = 32, size = BL1_1_MSP_STACK_SIZE { };
+define block HEAP                   with alignment = 8, size = BL1_1_HEAP_SIZE { };
+define block ARM_LIB_HEAP           with alignment = 8, size = BL1_1_HEAP_SIZE { };
+define block SRAM_WATERMARK         with size = 0 { };
+define overlay HEAP_OVL             {block HEAP};
+define overlay HEAP_OVL             {block ARM_LIB_HEAP};
+define overlay STACK_OVL            {block CSTACK};
+define overlay STACK_OVL            {block ARM_LIB_STACK};
+keep {block TFM_SHARED_DATA,
+      block CSTACK,
+      block ARM_LIB_STACK,
+      block HEAP,
+      block ARM_LIB_HEAP,
+      block SRAM_WATERMARK,
+};
+
+if (isdefinedsymbol(__USE_DLIB_PERTHREAD))
+{
+  // Required in a multi-threaded application
+  initialize by copy with packing = none { section __DLIB_PERTHREAD };
+}
+
+define block BL1_1_ER_DATA with fixed order, maximum size = BL1_1_DATA_SIZE  {
+        block TFM_SHARED_DATA,
+        block ER_DATA,
+        overlay STACK_OVL,
+        overlay HEAP_OVL,
+        block SRAM_WATERMARK,
+};
+place at address BL1_1_DATA_START {block BL1_1_ER_DATA};
+
+define block BL1_2_ER_DATA with fixed order, size = BL1_2_DATA_SIZE  {
+};
+place at address BL1_2_DATA_START {block BL1_2_ER_DATA};
+keep {block BL1_2_ER_DATA,
+};
diff --git a/platform/ext/target/arm/mps4/corstone315/device/source/iar/corstone315_bl1_2.icf b/platform/ext/target/arm/mps4/corstone315/device/source/iar/corstone315_bl1_2.icf
new file mode 100644
index 0000000..f2a86a7
--- /dev/null
+++ b/platform/ext/target/arm/mps4/corstone315/device/source/iar/corstone315_bl1_2.icf
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/* Linker script to configure memory regions. */
+/* This file will be run trough the pre-processor. */
+
+#include "region_defs.h"
+
+do not initialize  { section .noinit };
+initialize by copy { readwrite };
+
+define block ER_CODE            with fixed order, alignment = 8, size = BL1_2_CODE_SIZE {
+       section .intvec,
+       readonly
+};
+define block LR_CODE with fixed order {block ER_CODE};
+place at address BL1_2_CODE_START {block LR_CODE};
+
+define block TFM_SHARED_DATA        with alignment = 32, size = BOOT_TFM_SHARED_DATA_SIZE { };
+define block ER_DATA                with alignment = 32 {readwrite};
+define block CSTACK                 with alignment = 32, size = BL1_2_MSP_STACK_SIZE { };
+define block ARM_LIB_STACK          with alignment = 32, size = BL1_2_MSP_STACK_SIZE { };
+define block HEAP                   with alignment = 8, size = BL1_2_HEAP_SIZE { };
+define block ARM_LIB_HEAP           with alignment = 8, size = BL1_2_HEAP_SIZE { };
+define block SRAM_WATERMARK         with size = 0 { };
+define overlay HEAP_OVL             {block HEAP};
+define overlay HEAP_OVL             {block ARM_LIB_HEAP};
+define overlay STACK_OVL            {block CSTACK};
+define overlay STACK_OVL            {block ARM_LIB_STACK};
+keep {block TFM_SHARED_DATA,
+      block CSTACK,
+      block ARM_LIB_STACK,
+      block HEAP,
+      block ARM_LIB_HEAP,
+      block SRAM_WATERMARK,
+};
+
+if (isdefinedsymbol(__USE_DLIB_PERTHREAD))
+{
+  // Required in a multi-threaded application
+  initialize by copy with packing = none { section __DLIB_PERTHREAD };
+}
+
+define block BL1_2_ER_DATA with fixed order, maximum size = BL1_2_DATA_SIZE  {
+        block TFM_SHARED_DATA,
+        block ER_DATA,
+        overlay STACK_OVL,
+        overlay HEAP_OVL,
+        block SRAM_WATERMARK,
+};
+place at address BL1_2_DATA_START {block BL1_2_ER_DATA};
+
+define block BL1_1_ER_DATA with fixed order, size = BL1_1_DATA_SIZE  {
+};
+place at address BL1_1_DATA_START {block BL1_1_ER_DATA};
+keep {block BL1_1_ER_DATA,
+};
diff --git a/platform/ext/target/arm/mps4/corstone315/provisioning/bundle_cm/CMakeLists.txt b/platform/ext/target/arm/mps4/corstone315/provisioning/bundle_cm/CMakeLists.txt
index 5217c78..2861449 100644
--- a/platform/ext/target/arm/mps4/corstone315/provisioning/bundle_cm/CMakeLists.txt
+++ b/platform/ext/target/arm/mps4/corstone315/provisioning/bundle_cm/CMakeLists.txt
@@ -30,6 +30,7 @@
 target_add_scatter_file(cm_provisioning_bundle
     $<$<C_COMPILER_ID:ARMClang>:${CMAKE_CURRENT_SOURCE_DIR}/../bundle_common/provisioning_bundle.sct>
     $<$<C_COMPILER_ID:GNU>:${CMAKE_CURRENT_SOURCE_DIR}/../bundle_common/provisioning_bundle.ld>
+    $<$<C_COMPILER_ID:IAR>:${CMAKE_CURRENT_SOURCE_DIR}/../bundle_common/provisioning_bundle.icf>
 )
 
 target_link_options(cm_provisioning_bundle
@@ -95,13 +96,8 @@
     DEPENDS $<TARGET_FILE_DIR:bl2>/bl2_signed_hash.bin
     DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../create_provisioning_bundle.py
     COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE_DIR:cm_provisioning_bundle>/cm_provisioning_bundle.axf cm_provisioning_bundle.axf
-    COMMAND ${CMAKE_OBJCOPY} $<TARGET_FILE_DIR:cm_provisioning_bundle>/cm_provisioning_bundle.axf
-                    --dump-section CODE=cm_provisioning_code.bin
-    COMMAND ${CMAKE_OBJCOPY} $<TARGET_FILE_DIR:cm_provisioning_bundle>/cm_provisioning_bundle.axf
-                    --dump-section VALUES=cm_provisioning_values.bin
     COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../create_provisioning_bundle.py
-                    --provisioning_code cm_provisioning_code.bin
-                    --provisioning_values cm_provisioning_values.bin
+                    --provisioning_bundle_axf $<TARGET_FILE_DIR:cm_provisioning_bundle>/cm_provisioning_bundle.axf
                     --bl1_2_padded_hash_input_file $<TARGET_FILE_DIR:bl1_2>/bl1_2_padded_hash.bin
                     --bl1_2_input_file $<TARGET_FILE_DIR:bl1_2>/bl1_2_padded.bin
                     --bl2_signed_hash_input_file $<TARGET_FILE_DIR:bl2>/bl2_signed_hash.bin
diff --git a/platform/ext/target/arm/mps4/corstone315/provisioning/bundle_common/provisioning_bundle.icf b/platform/ext/target/arm/mps4/corstone315/provisioning/bundle_common/provisioning_bundle.icf
new file mode 100644
index 0000000..6e061a0
--- /dev/null
+++ b/platform/ext/target/arm/mps4/corstone315/provisioning/bundle_common/provisioning_bundle.icf
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "region_defs.h"
+
+do not initialize { section .noinit };
+do not initialize { readwrite };
+
+define block VALUES with fixed order, maximum size = PROVISIONING_BUNDLE_VALUES_SIZE {
+       ro object *provisioning_data.o
+};
+"VALUES": place at address PROVISIONING_BUNDLE_VALUES_START { block VALUES };
+
+define ram region DATA = [from PROVISIONING_BUNDLE_DATA_START size PROVISIONING_BUNDLE_DATA_SIZE];
+
+define block RW_DATA {
+    rw data
+};
+"RW_DATA": place at start of DATA { block RW_DATA };
+
+define block RO_DATA {
+    ro data
+} except  {
+    ro object *provisioning_data.o
+};
+"RO_DATA": place in DATA { block RO_DATA };
+
+define block BSS_DATA {
+    zi section .bss
+};
+"BSS_DATA": place in DATA { block BSS_DATA };
+
+define block CODE with fixed order, alignment = 4, maximum size = PROVISIONING_BUNDLE_CODE_SIZE {
+    ro section DO_PROVISION,
+    ro code,
+};
+"CODE": place at address PROVISIONING_BUNDLE_CODE_START { block CODE };
diff --git a/platform/ext/target/arm/mps4/corstone315/provisioning/bundle_dm/CMakeLists.txt b/platform/ext/target/arm/mps4/corstone315/provisioning/bundle_dm/CMakeLists.txt
index 43219ae..4dcf152 100644
--- a/platform/ext/target/arm/mps4/corstone315/provisioning/bundle_dm/CMakeLists.txt
+++ b/platform/ext/target/arm/mps4/corstone315/provisioning/bundle_dm/CMakeLists.txt
@@ -33,6 +33,7 @@
 target_add_scatter_file(dm_provisioning_bundle
     $<$<C_COMPILER_ID:ARMClang>:${CMAKE_CURRENT_SOURCE_DIR}/../bundle_common/provisioning_bundle.sct>
     $<$<C_COMPILER_ID:GNU>:${CMAKE_CURRENT_SOURCE_DIR}/../bundle_common/provisioning_bundle.ld>
+    $<$<C_COMPILER_ID:IAR>:${CMAKE_CURRENT_SOURCE_DIR}/../bundle_common/provisioning_bundle.icf>
 )
 
 target_link_options(dm_provisioning_bundle
@@ -108,13 +109,8 @@
     DEPENDS $<TARGET_FILE_DIR:bl1_2>/bl1_2_padded.bin
     bl1_2_padded_bin bl2_signed_bin dm_provisioning_bundle
     DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../create_provisioning_bundle.py
-    COMMAND ${CMAKE_OBJCOPY} $<TARGET_FILE_DIR:dm_provisioning_bundle>/dm_provisioning_bundle.axf
-                    --dump-section CODE=dm_provisioning_code.bin
-    COMMAND ${CMAKE_OBJCOPY} $<TARGET_FILE_DIR:dm_provisioning_bundle>/dm_provisioning_bundle.axf
-                    --dump-section VALUES=dm_provisioning_values.bin
     COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../create_provisioning_bundle.py
-                    --provisioning_code dm_provisioning_code.bin
-                    --provisioning_values dm_provisioning_values.bin
+                    --provisioning_bundle_axf $<TARGET_FILE_DIR:dm_provisioning_bundle>/dm_provisioning_bundle.axf
                     --bundle_output_file dm_provisioning_bundle.bin
                     --magic "0xBEEFFEED"
                     --tp_mode ${TP_MODE}
diff --git a/platform/ext/target/arm/mps4/corstone315/provisioning/create_provisioning_bundle.py b/platform/ext/target/arm/mps4/corstone315/provisioning/create_provisioning_bundle.py
index f6efad1..01aa5e2 100755
--- a/platform/ext/target/arm/mps4/corstone315/provisioning/create_provisioning_bundle.py
+++ b/platform/ext/target/arm/mps4/corstone315/provisioning/create_provisioning_bundle.py
@@ -8,6 +8,7 @@
 import argparse
 import struct
 import secrets
+from elftools.elf.elffile import ELFFile
 
 def struct_pack(objects, pad_to=0):
     defstring = "<"
@@ -24,10 +25,7 @@
     return (bytes(struct.pack(defstring, *objects)))
 
 parser = argparse.ArgumentParser()
-parser.add_argument("--provisioning_code", help="the input provisioning code", required=True)
-parser.add_argument("--provisioning_rwdata", help="the input provisioning rwdata", required=False)
-parser.add_argument("--provisioning_rodata", help="the input provisioning rodata", required=False)
-parser.add_argument("--provisioning_values", help="the input provisioning values", required=True)
+parser.add_argument("--provisioning_bundle_axf", help="the input provisioning bundle elf/axf", required=True)
 parser.add_argument("--magic", help="the magic constant to insert at the start and end", required=True)
 parser.add_argument("--bl1_2_padded_hash_input_file", help="the hash of the final bl1_2 image", required=False)
 parser.add_argument("--bl2_signed_hash_input_file", help="the hash of the final bl2 image", required=False)
@@ -43,23 +41,34 @@
 
 args = parser.parse_args()
 
-with open(args.provisioning_code, "rb") as in_file:
-    code = in_file.read()
+elffile = ELFFile(open(args.provisioning_bundle_axf, 'rb'))
 
-if args.provisioning_rwdata:
-    with open(args.provisioning_rwdata, "rb") as in_file:
-        rwdata = in_file.read()
+values_section = elffile.get_section_by_name("VALUES")
+rodata_section = elffile.get_section_by_name("RO_DATA")
+rwdata_section = elffile.get_section_by_name("RW_DATA")
+code_section = elffile.get_section_by_name("CODE")
+
+if code_section is not None:
+    code = code_section.data()
+else:
+    print("provisioning_bundle's code sections is mandatory")
+    exit(1)
+
+if rwdata_section is not None:
+    rwdata = rwdata_section.data()
 else:
     rwdata = bytes(0)
 
-if args.provisioning_rodata:
-    with open(args.provisioning_rodata, "rb") as in_file:
-        rodata = in_file.read()
+if rodata_section is not None:
+    rodata = rodata_section.data()
 else:
     rodata = bytes(0)
 
-with open(args.provisioning_values, "rb") as in_file:
-    values = in_file.read()
+if values_section is not None:
+    values = values_section.data()
+else:
+    print("provisioning_bundle's values sections is mandatory")
+    exit(1)
 
 with open(args.key_file, "rb") as in_file:
     input_key = in_file.read()
diff --git a/toolchain_IARARM.cmake b/toolchain_IARARM.cmake
index 46e8556..949b737 100644
--- a/toolchain_IARARM.cmake
+++ b/toolchain_IARARM.cmake
@@ -1,6 +1,6 @@
 #-------------------------------------------------------------------------------
 # Copyright (c) 2020, IAR Systems AB. All rights reserved.
-# Copyright (c) 2020-2023, Arm Limited. All rights reserved.
+# Copyright (c) 2020-2024, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -58,7 +58,7 @@
       --silent
       --semihosting
       --redirect __write=__write_buffered
-      --diag_suppress=lp005
+      --diag_suppress=lp005,Lp023
       "SHELL:--fpu none"
     )
 endmacro()
@@ -200,6 +200,58 @@
     )
 endmacro()
 
+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(IAR_STEERING_FILE ${KEEP_SYMBOL_LIST})
+
+    list(TRANSFORM IAR_STEERING_FILE PREPEND "show ")
+    list(TRANSFORM IAR_STEERING_FILE APPEND " \n")
+    list(INSERT IAR_STEERING_FILE 0 "hide *\n")
+    string(REPLACE ";" "" IAR_STEERING_FILE ${IAR_STEERING_FILE})
+    file( GENERATE OUTPUT "$<TARGET_FILE_DIR:${target}>/iar_steering_file" CONTENT "${IAR_STEERING_FILE}")
+
+    add_custom_command(
+        TARGET ${target}
+        POST_BUILD
+        COMMAND ${CMAKE_IAR_SYMEXPORT}
+        ARGS --edit $<TARGET_FILE_DIR:${target}>/iar_steering_file $<TARGET_FILE:${target}> $<TARGET_FILE_DIR:${target}>/${target}${CODE_SHARING_OUTPUT_FILE_SUFFIX}
+    )
+
+    # Force the target to not remove the symbols if they're unused.
+    list(TRANSFORM KEEP_SYMBOL_LIST PREPEND --keep=)
+    target_link_options(${target}
+        PRIVATE
+            ${KEEP_SYMBOL_LIST}
+    )
+endmacro()
+
+macro(target_link_shared_code target)
+    get_target_property(TARGET_SOURCE_DIR ${target} SOURCE_DIR)
+
+    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()
+
+        add_dependencies(${target} ${symbol_provider})
+        target_link_options(${target} PRIVATE LINKER:$<TARGET_FILE_DIR:${symbol_provider}>/${symbol_provider}${CODE_SHARING_INPUT_FILE_SUFFIX})
+    endforeach()
+endmacro()
+
 macro(compiler_create_shared_code TARGET SHARED_SYMBOL_TEMPLATE)
     message(FATAL_ERROR "Code sharing support is not implemented by IAR.")
 endmacro()