Build: Enable code sharing between bootloader and SPE

Add CMake functions to allow sharing regions of code between
independently linked binaries.

Signed-off-by: Tamas Ban <tamas.ban@arm.com>
Change-Id: I6a6132d6c1558b242d8da1dedab14f93a852f81a
diff --git a/toolchain_GNUARM.cmake b/toolchain_GNUARM.cmake
index e530bf7..716a2cc 100644
--- a/toolchain_GNUARM.cmake
+++ b/toolchain_GNUARM.cmake
@@ -175,3 +175,96 @@
         DEPENDS ${target}_hex
     )
 endmacro()
+
+# Macro for sharing code among independent binaries. This function extracts
+# some parts of the code based on a symbol template file and creates a text
+# file, which contains the symbols with their absolute addresses, which can be
+# picked up by the linker when linking the other target.
+# INPUTS:
+#     TARGET -                -  Target to extract the symbols/objects from
+#     SHARED_SYMBOL_TEMPLATE  -  Template with names of symbols to share
+macro(compiler_create_shared_code TARGET SHARED_SYMBOL_TEMPLATE)
+    # Create a temporary file, which contains all extracted symbols from 'TARGET'
+    set(ALL_SYMBOLS ${CMAKE_CURRENT_BINARY_DIR}/all_symbols.txt)
+
+    # Find the CMake script doing the symbol filtering.
+    find_file(FILTER_SYMBOLS_SCRIPT "FilterSharedSymbols.cmake" PATHS ${CMAKE_MODULE_PATH} PATH_SUFFIXES Common NO_DEFAULT_PATH)
+    find_file(STRIP_UNSHARED_CODE   "StripUnsharedCode.cmake"   PATHS ${CMAKE_MODULE_PATH} PATH_SUFFIXES Common NO_DEFAULT_PATH)
+
+    find_program(GNUARM_NM arm-none-eabi-nm)
+    if (GNUARM_NM STREQUAL "GNUARM_NM-NOTFOUND")
+        message(FATAL_ERROR "toolchain_GNUARM.cmake: mandatory tool '${GNUARM_NM}' is missing.")
+    endif()
+
+    # Multiple steps are required:
+    #   - Extract all symbols from sharing target
+    #   - Filter the unwanted symbols from all_symbols.txt
+    #   - Create a stripped shared_code.axf file which contains only the symbols which are meant to be shared
+    add_custom_command(TARGET ${TARGET}
+                        POST_BUILD
+
+                        COMMAND ${GNUARM_NM}
+                        ARGS
+                            ${CMAKE_BINARY_DIR}/bin/${TARGET}.axf > ${ALL_SYMBOLS}
+                        COMMENT "Dumping all symbols"
+
+                        COMMAND ${CMAKE_COMMAND}
+                            -DSHARED_SYMBOL_TEMPLATE=${SHARED_SYMBOL_TEMPLATE}
+                            -DALL_SYMBOLS=${ALL_SYMBOLS}
+                            -P ${FILTER_SYMBOLS_SCRIPT}
+                        BYPRODUCTS
+                            ${CMAKE_CURRENT_BINARY_DIR}/shared_symbols_name.txt
+                            ${CMAKE_CURRENT_BINARY_DIR}/shared_symbols_addr.txt
+                        COMMENT "Filtering shared symbols"
+
+                        COMMAND ${CMAKE_COMMAND}
+                            -E copy ${CMAKE_BINARY_DIR}/bin/${TARGET}.axf ${CMAKE_CURRENT_BINARY_DIR}/shared_code.axf
+                        COMMENT "Copy and rename ${TARGET} to strip"
+
+                        COMMAND ${CMAKE_COMMAND}
+                            -DSHARED_SYMBOLS_FILE=${CMAKE_CURRENT_BINARY_DIR}/shared_symbols_name.txt
+                            -DEXECUTABLE_TO_STRIP=${CMAKE_CURRENT_BINARY_DIR}/shared_code.axf
+                            -P ${STRIP_UNSHARED_CODE}
+                        COMMENT "Stripping unshared code from ${CMAKE_CURRENT_BINARY_DIR}/shared_code.axf"
+    )
+endmacro()
+
+macro(compiler_weaken_symbols TARGET SHARED_CODE_PATH ORIG_TARGET LIB_LIST)
+    # Find the CMake scripts
+    find_file(WEAKEN_SYMBOLS_SCRIPT "WeakenSymbols.cmake" PATHS ${CMAKE_MODULE_PATH} PATH_SUFFIXES Common NO_DEFAULT_PATH)
+
+    add_custom_command(TARGET ${TARGET}
+                        PRE_LINK
+
+                        COMMAND ${CMAKE_COMMAND}
+                            -DLIB_LIST='${LIB_LIST}'
+                            -DSHARED_CODE_PATH=${SHARED_CODE_PATH}
+                            -P ${WEAKEN_SYMBOLS_SCRIPT}
+                        COMMENT "Set conflicting symbols to be weak in the original libraries to avoid collision")
+
+    # If sharing target is defined by TF-M build then setup dependency
+    if(NOT ${ORIG_TARGET} STREQUAL "EXTERNAL_TARGET")
+        add_dependencies(${TARGET} ${ORIG_TARGET})
+    endif()
+endmacro()
+
+# Macro for linking shared code to given target. Location of shared code could
+# be outside of the TF-M project. Its location can be defined with the CMake
+# command line argument "SHARED_CODE_PATH". The file containing the shared objects
+# must be named "shared_symbols_addr.txt".
+# INPUTS:
+#     TARGET            Target to link the shared code to
+#     SHARED_CODE_PATH  Shared code located in this folder
+#     ORIG_TARGET       Target that shared code was extraced from <TARGET | "EXTERNAL_TARGET">
+#     LIB_LIST          List of libraries which are linked to top level target
+macro(compiler_link_shared_code TARGET SHARED_CODE_PATH ORIG_TARGET LIB_LIST)
+    # GNUARM requires to link a stripped version (only containing the shared symbols) of the
+    # original executable to the executable which want to rely on the shared symbols.
+    target_link_options(${TARGET} PRIVATE -Wl,-R${SHARED_CODE_PATH}/shared_code.axf)
+
+    compiler_weaken_symbols(${TARGET}
+                            ${SHARED_CODE_PATH}
+                            ${ORIG_TARGET}
+                            "${LIB_LIST}"
+    )
+endmacro()
\ No newline at end of file