# ************************************************************************************************
# Environment

INFO_TITLE ?= Trusted Application Build
$(info ******************************************)
$(info $(INFO_TITLE))
$(info ******************************************)

# PLATFORM : ARM_V8A_AARCH64
ifeq ($(PLATFORM),)
$(info - PLATFORM  is  not  set,  default  is : ARM_V8A_AARCH64)
PLATFORM := ARM_V8A_AARCH64
endif

# MODE : Debug, Release
ifeq ($(MODE),)
$(info - MODE  is  not  set,  default  is : Debug)
MODE := Debug
endif

# TOOLCHAIN : GNU, CLANG
ifeq ($(TOOLCHAIN),)
$(info - TOOLCHAIN is not set, default is : GNU)
TOOLCHAIN := GNU
endif

# GP ENTRY : tlMain, GP Entrypoints
ifeq ($(GP_ENTRYPOINTS),)
$(info - GP_ENTRYPOINTS is not set, default is : N)
GP_ENTRYPOINTS := N
endif

# TA_INTERFACE_VERSION : major.minor
ifeq ($(TA_INTERFACE_VERSION),)
$(info - TA_INTERFACE_VERSION  is  not  set,  default  is : 0.0)
TA_INTERFACE_VERSION := 0.0
endif

# TBASE_API_LEVEL
TBASE_API_LEVEL_TOP := 11
ifeq ($(TBASE_API_LEVEL),)
$(info - TBASE_API_LEVEL  is  not  set,  default  is : $(TBASE_API_LEVEL_TOP))
TBASE_API_LEVEL := $(TBASE_API_LEVEL_TOP)
endif

# HW_FLOATING_POINT
ifeq ($(HW_FLOATING_POINT),)
$(info - HW_FLOATING_POINT  is  not  set,  default  is : N)
HW_FLOATING_POINT := N
endif

# TA_ROLLBACK_PROTECTED
ifeq ($(TA_ROLLBACK_PROTECTED),)
$(info - TA_ROLLBACK_PROTECTED  is  not  set,  default  is : N)
TA_ROLLBACK_PROTECTED := N
endif

# TA_SERVICE_TYPE
TA_SERVICE_TYPE ?= $(TRUSTLET_SERVICE_TYPE)
ifeq ($(TA_SERVICE_TYPE),)
TA_SERVICE_TYPE := SYS
endif

# Minimal TBASE_API_LEVEL supported is 5
ifeq ($(shell test $(TBASE_API_LEVEL) -lt 5; echo $$?),0)
$(info - TBASE_API_LEVEL is set to $(TBASE_API_LEVEL))
$(error - TBASE_API_LEVEL lower than 5 is not supported anymore)
endif

# TA_PIE
TA_PIE ?= PIE

GP_LIBRARY ?= Standard

$(info ******************************************)
$(info MODE                 : $(MODE))
$(info TOOLCHAIN            : $(TOOLCHAIN))
$(info PLATFORM             : $(PLATFORM))
$(info INTERFACE_VERSION    : $(TA_INTERFACE_VERSION))
$(info TBASE_API_LEVEL      : $(TBASE_API_LEVEL))
$(info HW_FLOATING_POINT    : $(HW_FLOATING_POINT))
$(info ROLLBACK_PROTECTED   : $(TA_ROLLBACK_PROTECTED))
$(info GP-ENTRIES           : $(GP_ENTRYPOINTS))
$(info GP_LIBRARY           : $(GP_LIBRARY))
$(info TA_SERVICE_TYPE      : $(TA_SERVICE_TYPE))
$(info ******************************************)

# Check if variables are correctly set
ifneq ($(MODE),Debug)
   ifneq ($(MODE),Release)
      $(error ERROR : MODE value is not correct : $(MODE))
   endif
endif
ifeq ($(filter $(TOOLCHAIN),GNU CLANG),)
$(error ERROR : TOOLCHAIN value is not correct : $(TOOLCHAIN))
endif
ifneq ($(GP_ENTRYPOINTS),N)
   ifneq ($(GP_ENTRYPOINTS),Y)
      $(error ERROR : GP_ENTRYPOINTS value is not correct : $(GP))
   endif
endif
define N


endef

ifneq ($(TBASE_API_LEVEL),$(TBASE_API_LEVEL_TOP))
   $(warning $(N)\
   $(N)\
   ******************************************$(N)\
   WARNING : makefile sets TBASE_API_LEVEL to $(TBASE_API_LEVEL) which is lower than $(TBASE_API_LEVEL_TOP)$(N)\
   Trustonic recommends to not define this variable and use the default value for maximum security$(N)\
   ******************************************$(N))
endif
ifneq ($(HW_FLOATING_POINT),N)
   ifneq ($(HW_FLOATING_POINT),Y)
      $(error ERROR : HW_FLOATING_POINT value is not correct : $(HW_FLOATING_POINT))
   endif
endif
ifneq ($(TA_ROLLBACK_PROTECTED),N)
   ifneq ($(TA_ROLLBACK_PROTECTED),Y)
      $(error ERROR : TA_ROLLBACK_PROTECTED value is not correct : $(TA_ROLLBACK_PROTECTED))
   endif
endif


# Accept old variable names
TRUSTED_APP_DIR ?= $(TRUSTLET_DIR)

TA_UUID ?= $(TRUSTLET_UUID)
#ExySp
ifeq ($(TA_UUID_LOWER_CASE),Y)
TA_UUID := $(shell echo $(TA_UUID) | tr A-Z a-z)
endif
ifneq ($(TA_UUID_LOWER_CASE),Y)
TA_UUID := $(shell echo $(TA_UUID) | tr a-z A-Z)
endif
TA_MEMTYPE ?= $(TRUSTLET_MEMTYPE)
TA_KEYFILE ?= $(TRUSTLET_KEYFILE)
TA_FLAGS ?= $(TRUSTLET_FLAGS)

# Default values for mostly irrelevant properties
ifeq ($(TA_MEMTYPE),)
TA_MEMTYPE := 2  # 0: internal memory prefered; 1: internal memory used; 2: external memory used
endif

# Convenience values for SERVICE_TYPE
ifneq ($(strip $(TA_SERVICE_TYPE)),1)
	ifneq ($(strip $(TA_SERVICE_TYPE)),3)
		ifneq ($(strip $(TA_SERVICE_TYPE)),4)
			ifneq ($(strip $(TA_SERVICE_TYPE)),SYS)
				$(error ERROR : TA_SERVICE_TYPE value is not correct : -$(TA_SERVICE_TYPE)-)
        	endif
        endif
	endif
endif

ifeq ($(strip $(TA_SERVICE_TYPE)),SYS)
TA_SERVICE_TYPE := 3
endif

# Default values for mostly irrelevant properties
ifeq ($(TA_FLAGS),)
TA_FLAGS := 0 # 0: no flag; 1: permanent; 2: service has no WSM control interface; 4: debuggable
endif
ifeq ($(TA_DEBUGGABLE),Y)
TA_FLAGS := $$(($(TA_FLAGS)|4))
endif

DOWNGRADE_PROTECTED :=
ifeq ($(TA_ROLLBACK_PROTECTED),Y)
   DOWNGRADE_PROTECTED := --downgrade-protected
endif

# Extended memory layout is always enabled
TA_HEAP_SIZE_INIT_PARAM :=
TA_HEAP_SIZE_MAX_PARAM :=
TA_FLAGS := $$(($(TA_FLAGS)|8))
ifneq ($(HEAP_SIZE_INIT),)
    TA_HEAP_SIZE_INIT_PARAM :=  -initheapsize $(HEAP_SIZE_INIT)
    ifeq ($(HEAP_SIZE_MAX),)
        TA_HEAP_SIZE_MAX_PARAM :=  -maxheapsize $(HEAP_SIZE_INIT)
    else
        TA_HEAP_SIZE_MAX_PARAM :=  -maxheapsize $(HEAP_SIZE_MAX)
    endif
endif

# Default values for mostly irrelevant properties
TA_INSTANCES ?= $(TRUSTLET_INSTANCES)
ifeq ($(TA_INSTANCES),)
TA_INSTANCES := 16 # min: 1; max: 16
endif

TA_ADD_FLAGS ?= $(TRUSTLET_ADD_FLAGS)

TA_OPTS ?= $(TRUSTLET_OPTS)

TASDK_DIR ?= $(TLSDK_DIR)
TASDK_DIR_SRC ?= $(TLSDK_DIR_SRC)

GPENTRY_LIB :=
GP_LEVEL :=

ifeq ($(GP_LIBRARY),Standard)
    GPAPI_LIB = $(TASDK_DIR_SRC)/Bin/$(SDK_PLATFORM)/GpApi/$(TA_PIE)/GpApi.lib
else ifeq ($(GP_LIBRARY),GpTRIC)
    ifeq ($(PLATFORM),ARM_V8A_AARCH64)
        $(error aarch64 build with GpTric is not supported)
    endif
    GPAPI_LIB = $(TASDK_DIR_SRC)/../libraries/GpTRIC/Bin/ARM_V7A_STD/GpTRIC.lib
else
    $(error ERROR : GP_LIBRARY value not recognized. Currently : $(GP_LIBRARY))
endif

ifeq ($(GP_ENTRYPOINTS),Y)
    GPENTRY_LIB = $(TASDK_DIR_SRC)/Bin/$(SDK_PLATFORM)/GpEntry/$(TA_PIE)/GpEntry.lib
    GP_LEVEL := -gp_level GP
    GP_UUID  := $(TA_UUID)
    $(info GP_UUID              : $(GP_UUID))
endif


# OUTPUT_ROOT used to clean build, keep it defined
OUTPUT_ROOT := $(TRUSTED_APP_DIR)/../../Out/Bin

#ExySp
OUTPUT_PATH ?= $(OUTPUT_ROOT)/$(MODE)

OUTPUT_OBJ_PATH=$(OUTPUT_PATH)/obj-local

# ************************************************************************************************
# Trusted application being built
TA_AXF := $(OUTPUT_PATH)/$(OUTPUT_NAME).axf
TA_LST2 := $(OUTPUT_PATH)/$(OUTPUT_NAME).lst2
#ExySp
#TA_LIB := $(OUTPUT_PATH_INDEPENDENT)/$(OUTPUT_NAME).lib
TA_LIB := $(OUTPUT_PATH)/$(OUTPUT_NAME).lib
ifeq ($(GP_ENTRYPOINTS),Y)
TA_BIN := $(OUTPUT_PATH)/$(TA_UUID).tabin
GP_BIN := $(OUTPUT_PATH)/$(GP_UUID).tabin
TA_LOG_FILE_NAME=$(OUTPUT_PATH)/$(OUTPUT_NAME)_$(GP_UUID).tabin.log
ENCRYPTED_TA_LOG_FILE_NAME=$(OUTPUT_PATH)/$(OUTPUT_NAME)_$(GP_UUID).tabin.log.encrypted
else
TA_BIN := $(OUTPUT_PATH)/$(TA_UUID).tlbin
TA_LOG_FILE_NAME=$(OUTPUT_PATH)/$(OUTPUT_NAME)_$(TA_UUID).tlbin.log
ENCRYPTED_TA_LOG_FILE_NAME=$(OUTPUT_PATH)/$(OUTPUT_NAME)_$(TA_UUID).tlbin.log.encrypted
endif
UUID_H := $(OUTPUT_ROOT)/../Public/$(OUTPUT_NAME)_uuid.h

ifeq ($(GP_ENTRYPOINTS),Y)
	GP_TA_CONFIG_FILE ?=
ifneq ($(GP_TA_CONFIG_FILE),)
	GP_TA_PROP_PARAM := --gp_prop write $(TA_AXF) $(GP_TA_CONFIG_FILE)
endif
endif

# ************************************************************************************************
# TASDK
TASDK_SRC_C :=
TASDK_SRC_ASM :=
TASDK_DIR_INC := \
    $(TASDK_DIR_SRC)/Public \
    $(TASDK_DIR_SRC)/Public/MobiCore/inc \
    $(TASDK_DIR_SRC)/Public/GPD_TEE_Internal_API
TLAPI_LIB = $(TASDK_DIR_SRC)/Bin/$(SDK_PLATFORM)/TlApi/$(TA_PIE)/TlApi.lib
TLENTRY_LIB = $(TASDK_DIR_SRC)/Bin/$(SDK_PLATFORM)/TlEntry/$(TA_PIE)/TlEntry.lib

# ************************************************************************************************
# ************************************************************************************************
# ************************************************************************************************
# Architecture specifics
ifeq ($(PLATFORM_MAKEFILES),)
    ifeq ($(PLATFORM),ARM_V8A_AARCH64)
        ARM_ARCH := AARCH64
        ARM_CHIP := ARMV8_A
        ARM_SHAPE := STD
        ARM_CPU := generic-armv8-a
    else
        ARM_ARCH := ARMv7
        ARM_CHIP := ARMV7_A
        ARM_SHAPE := STD
        ARM_CPU := generic-armv7-a
        ARM_FPU := vfp
        ARM_FLOAT_ABI := soft
    endif
else
   include $(PLATFORM_MAKEFILES)
endif

ifeq ($(ARM_ARCH),AARCH64)
    SDK_PLATFORM := ARM_V8A_AARCH64
else
    SDK_PLATFORM := ARM_V7A_STD
endif

# Toolchain set up
ifeq ($(TOOLCHAIN),GNU)
   LINKER_SCRIPT=$(TASDK_DIR_SRC)/trusted_application.ld
    ifeq ($(ARM_ARCH),AARCH64)
        ifeq ($(CROSS_GCC64_PATH),)
            $(error GCC64 toolchain error: CROSS_GCC64_PATH is not set, please configure it)
        endif
        CROSS_GCC_PATH_BIN = $(CROSS_GCC64_PATH_BIN)
    else
        ifeq ($(CROSS_GCC_PATH),)
            $(error GCC toolchain error: CROSS_GCC_PATH is not set, please configure it)
        endif
    endif
   CC=$(CROSS_GCC_PATH_BIN)gcc
    $(info GCC toolchain compiler: $(CC))
    ifneq ($(shell test -x $(CC); echo $$?),0)
        ifeq ($(ARM_ARCH),AARCH64)
            $(error GCC64 toolchain error: $(CC) points to an invalid compiler)
        else
            $(error GCC toolchain error: $(CC) points to an invalid compiler)
        endif
    endif
   LINKER=$(CC)
   READELF=$(CROSS_GCC_PATH_BIN)readelf
   OBJDUMP=$(CROSS_GCC_PATH_BIN)objdump
   #ASM=$(CROSS_GCC_PATH_BIN)as
   #We use gcc as preprocessor for GNU asm
   ASM=$(CROSS_GCC_PATH_BIN)gcc
   ARCH=$(CROSS_GCC_PATH_BIN)ar
else ifeq ($(TOOLCHAIN),CLANG)
   LINKER_SCRIPT=$(TASDK_DIR_SRC)/trusted_application.ld
    ifeq ($(ARM_ARCH),AARCH64)
        TA_PIE := NON_PIE
        $(warning "WARNING : disabling PIE for CLANG AARCH64")
    endif
    ifeq ($(COMP_PATH_CLANG),)
        $(error Clang toolchain error: COMP_PATH_CLANG is not set, please configure it)
    endif

   CLANG_BIN := $(COMP_PATH_CLANG)/bin/clang
    ifeq ($(ARM_ARCH),AARCH64)
        ifeq ($(CROSS_GCC64_PATH),)
            $(error GCC64 toolchain error: CROSS_GCC64_PATH is not set, please configure it)
        endif
        CC=$(CLANG_BIN) -I$(CROSS_GCC64_PATH)/aarch64-elf/include
        LINKER=$(CLANG_BIN) -v -L$(CROSS_GCC64_PATH)/aarch64-elf/lib -L$(CROSS_GCC64_PATH)/lib/gcc/aarch64-elf/8.3.0
    else
        ifeq ($(CROSS_GCC_PATH),)
            $(error Clang toolchain error: CROSS_GCC_PATH is not set, please configure it)
        endif
        CC=$(CLANG_BIN) -I$(CROSS_GCC_PATH)/arm-eabi/include
        LINKER=$(CLANG_BIN) -v -L$(CROSS_GCC_PATH)/arm-eabi/lib -L$(CROSS_GCC_PATH)/lib/gcc/arm-eabi/8.3.0
    endif
   $(info Clang toolchain compiler: $(CLANG_BIN))
   ifneq ($(shell test -x $(CLANG_BIN); echo $$?),0)
      $(error Clang toolchain error: $(CLANG_BIN) points to an invalid compiler)
   endif
   READELF=$(COMP_PATH_CLANG)/bin/llvm-readelf
   OBJDUMP=$(COMP_PATH_CLANG)/bin/llvm-objdump
   #ASM=llvm-as
   #We use clang as preprocessor for CLANG asm
   ASM=$(CC)
   ARCH=$(COMP_PATH_CLANG)/bin/llvm-ar
endif

ARM_PLAT := $(ARM_CHIP)_$(ARM_SHAPE)

# Toolchain options
STD_LIBS ?=
ARM_OPT_CC :=
TARGET :=
TARGET_LIB :=
ifeq ($(ARM_ARCH),AARCH64)
TRIPLE := aarch64-elf
else
TRIPLE := thumbv7a-none-eabi
endif

ifeq ($(TOOLCHAIN),CLANG)
	TARGET += --target=$(TRIPLE)
endif
ifeq ($(ARM_CPU),generic-armv7-a)
	TARGET += -march=armv7-a
    else ifeq ($(ARM_CPU),generic-armv8-a)
        TARGET += -march=armv8-a
else
	TARGET += -mcpu=$(ARM_CPU)
endif

ifneq ($(ARM_ARCH),AARCH64)
    ifeq ($(HW_FLOATING_POINT),Y)
        TARGET += -mfpu=neon-vfpv4
        TARGET += -mfloat-abi=softfp
    else
        TARGET += -mfpu=$(ARM_FPU)
        TARGET += -mfloat-abi=$(ARM_FLOAT_ABI)
    endif
endif

ifeq ($(TOOLCHAIN),CLANG)
	TARGET_LIB += --target=$(TRIPLE)
else
    ifeq ($(ARM_ARCH),AARCH64)
        TARGET_LIB += -march=armv8-a
    else
        TARGET_LIB += -march=armv7-a
    endif
endif

STD_LIBS += -lc -lgcc

#ExySp
#ARM_OPT_CC += -Werror
ARM_OPT_CC += -Wall
ARM_OPT_CC += -Wextra
#ARM_OPT_CC += -U__INT32_TYPE__ -U__UINT32_TYPE__  -D__INT32_TYPE__="int"

ARM_OPT_CC += -DPLAT=$(ARM_PLAT)
ARM_OPT_CC += -DARM_ARCH=$(ARM_ARCH) -D__$(ARM_ARCH)__
ARM_OPT_CC += -D__$(ARM_CHIP)__
ARM_OPT_CC += -D__$(ARM_PLAT)__
ARM_OPT_CC += $(TA_OPTS)
ARM_OPT_CC += -DTBASE_API_LEVEL=$(TBASE_API_LEVEL)

# ExySp
# ARM_OPT_CC += -U__INT32_TYPE__ -U__UINT32_TYPE__  -D__INT32_TYPE__="int"
ARM_OPT_CC += -U__INT32_TYPE__ -U__UINT32_TYPE__  -D__INT32_TYPE__="int" -D__UINT32_TYPE__="unsigned int"

# setup SSP (Stack Smashing Protection)
ifeq ($(TOOLCHAIN),GNU)
    # enable Stack Smashing Protection in GCC
    # starting from GCC 4.9 a new flag fstack-protector-strong was introduced
    # that we need to use it applies the protection to a wider range of
    # function than "-fstack-protector" and will cover some corner cases
    SSP_TYPE := -fstack-protector
    GNU_VER_4_9 := 40900
    GNU_CUR_VER := $(shell $(CC) -dumpversion | sed -e 's/\./0/g')
    USE_SSP_STRONG := $(shell [ $(GNU_CUR_VER) -ge $(GNU_VER_4_9) ] && echo true )
    ifeq ($(USE_SSP_STRONG),true)
        SSP_TYPE := -fstack-protector-strong
    endif
    ARM_OPT_CC += $(SSP_TYPE)
else ifeq ($(TOOLCHAIN),CLANG)
    ARM_OPT_CC += -fstack-protector-strong
endif

# ASM options
ARM_OPT_ASM := $(TARGET)
ARM_OPT_ASM += -DPLAT=$(ARM_PLAT)
ARM_OPT_ASM += -DARM_ARCH=$(ARM_ARCH) -D__$(ARM_ARCH)__
ARM_OPT_ASM += -D__$(ARM_CHIP)__
ARM_OPT_ASM += -D__$(ARM_PLAT)__

ifeq ($(TA_PIE),PIE)
    ARM_OPT_CC += -fpie
    GNU_OPT_LINK := -Xlinker -pie
endif

# ************************************************************************************************
# Debug options

ifeq ($(MODE),Debug)
   CC_DBG_OPTS := -DDEBUG --debug

   ifeq ($(TOOLCHAIN),GNU)
        ASM_DBG_OPTS :=  -Wa,-g,--keep-locals
   endif
endif

# ************************************************************************************************
# ************************************************************************************************
# ************************************************************************************************
# Standard options
TA_NO_OF_THREADS ?= 1
TA_PARAM += -servicetype $(TA_SERVICE_TYPE) \
            -numberofthreads $(TA_NO_OF_THREADS) \
            -numberofinstances $(TA_INSTANCES) \
            -memtype $(TA_MEMTYPE) \
            -flags $(TA_FLAGS) \
            -bin $(TA_AXF) \
            -output $(TA_BIN) \
            $(GP_LEVEL) \
            -interfaceversion $(TA_INTERFACE_VERSION) \
            $(DOWNGRADE_PROTECTED) \
            $(TA_HEAP_SIZE_INIT_PARAM) \
            $(TA_HEAP_SIZE_MAX_PARAM) \
            $(TA_ADD_FLAGS)

ifeq ($(TA_KEYFILE),)
TA_PARAM += --nosign
    ifneq ($(ENCRYPT_SERVICE_KEY),)
        $(error ERROR : Can only encrypt signed services.)
    endif
else
    TA_PARAM += -keyfile $(TA_KEYFILE)
endif

ifneq ($(ENCRYPT_SERVICE_KEY),)
# fill in the argument for MobiConvert to encrypt the Service signed blob
# TODO: HSM part is not covered.
SERVICE_ENCRYPT_PARAMS := -encrypt \
                          -signedbin $(TA_BIN) \
                          -output $(TA_BIN) \
                          -keyfile $(ENCRYPT_SERVICE_KEY)
endif

ifeq ($(TA_TYPE_OPTS),)
    ifeq ($(GP_ENTRYPOINTS),Y)
        TA_TYPE_OPTS := -DTRUSTEDAPP
    else
        TA_TYPE_OPTS := -DTRUSTLET
    endif
endif

TA_CC_OPTS ?=
TA_CC_OPTS += $(TA_TYPE_OPTS)
ifneq ($(ARM_ARCH),AARCH64)
TARGET += -mthumb
endif
ifeq ($(TOOLCHAIN),GNU)
ifneq ($(ARM_ARCH),AARCH64)
CC_OPTS += -mthumb-interwork
endif
CC_OPTS += -fstack-usage
endif
CC_OPTS += -O3
CC_OPTS += -fdata-sections
CC_OPTS += -ffunction-sections
CC_OPTS += -fno-short-enums
CC_OPTS += -nostdlib
CC_OPTS += $(TA_CC_OPTS)
CC_OPTS += $(ARM_OPT_CC)
CC_OPTS += $(CC_DBG_OPTS)
CC_OPTS += $(ARMCC_COMPILATION_FLAGS)

# NOTE: The TA-TDriver library should be compiled without floating-point,
#       if no (float) in the interface, otherwise the compiler complains
#       when compiling the TA, if the TA does not use FP itself.
#       Here the driver developer can define its own cpu settings for the lib.
CC_OPTS_LIB := \
	$(CC_OPTS) \
	$(TARGET_LIB) \
	$(CC_OPTS_LIB_SPECIFIC)

# Now that lib is sure to be "no neon" add fpu config to generic OPTS
CC_OPTS += $(TARGET)

TA_LINK_OPTS ?=
ASM_OPTS := $(ARM_OPT_ASM) \
            ${ARMCC_COMPILATION_FLAGS} \
            $(ASM_DBG_OPTS) \
            -c
ifeq ($(TOOLCHAIN),GNU)
    ifneq ($(ARM_ARCH),AARCH64)
        ASM_OPTS += -mthumb-interwork
    endif
endif

ifeq ($(TOOLCHAIN),CLANG)
ifeq ($(ARM_ARCH),AARCH64)
# w/o this trick, clang is not calling ld.lld
LINK_OPTS := --target=armv8a-none-eabi -march=armv8-a
else
LINK_OPTS := $(TARGET)
endif
# Do not report the following error:
# can't create dynamic relocation R_ARM_ABS32 against local symbol in readonly segment; recompile object files with -fPIC
LINK_OPTS += -Xlinker -znotext
endif
LINK_OPTS += -nostdlib
# allow multiple definitions of __stack_chk_fail
LINK_OPTS += -Xlinker --allow-multiple-definition
LINK_OPTS += -Xlinker --gc-sections
LINK_OPTS += -Xlinker --fatal-warnings
ifeq ($(TOOLCHAIN),GNU)
LINK_OPTS += -Xlinker --no-wchar-size-warning
LINK_OPTS += -Xlinker --no-enum-size-warning
LINK_OPTS += -Xlinker --build-id=none
endif
LINK_OPTS += -T $(LINKER_SCRIPT)
LINK_OPTS += $(GNU_OPT_LINK)
LINK_OPTS += -o $(TA_AXF)
LINK_OPTS += $(TA_LINK_OPTS)

ARCHIVER_OPTS := -rcs

# ************************************************************************************************
# Actual sets of files to work on
SRC := $(SRC_C) $(SRC_CPP) $(SRC_ASM)
TASDK_SRC := $(TASDK_SRC_C) $(TASDK_SRC_ASM)

SRC_OBJ = $(addprefix $(OUTPUT_OBJ_PATH)/,$(join $(dir $(SRC)), $(addsuffix .o,$(notdir $(basename $(SRC))))))
TASDK_OBJ = $(addprefix $(OUTPUT_OBJ_PATH)/,$(addsuffix .o,$(notdir $(basename $(TASDK_SRC)))))
OBJ := $(SRC_OBJ) $(TASDK_OBJ)

ifneq ($(strip $(SRC_LIB_C)),)
TA_LIB_OBJ = $(addprefix $(OUTPUT_OBJ_PATH)/,$(addsuffix .ol,$(notdir $(basename $(SRC_LIB_C)))))
endif

INC := $(INCLUDE_DIRS:%=-I%) $(TASDK_DIR_INC:%=-I%)
INC_ASM := $(INCLUDE_DIRS:%=-Wa,-I%) $(TASDK_DIR_INC:%=-Wa,-I%)

LIBS := $(TLENTRY_LIB) $(TLAPI_LIB) $(GPAPI_LIB)
ifeq ($(GP_ENTRYPOINTS),Y)
LIBS += $(GPENTRY_LIB)
endif
LIBS += $(EXTRA_LIBS) ${CUSTOMER_DRIVER_LIBS}

ifeq ($(TOOLCHAIN),GNU)
   READ_OPT=-a $(TA_AXF) > $(TA_LST2); $(OBJDUMP) -D $(TA_AXF) >> $(TA_LST2)
   READ_OPT_LIB=-a $(TA_LIB) > $(TA_LIB).lst2; $(OBJDUMP) -D $(TA_LIB) >> $(TA_LIB).lst2
   C99=-std=c99
   CPP=-cpp
else ifeq ($(TOOLCHAIN),CLANG)
   READ_OPT=--file-headers --program-headers --sections --symbols --relocations --notes --version-info -elf-section-groups $(TA_AXF) > $(TA_LST2); $(OBJDUMP) -D -triple=$(TRIPLE) $(TA_AXF) >> $(TA_LST2)
   READ_OPT_LIB=-a $(TA_LIB) > $(TA_LIB).lst2; $(OBJDUMP) -D $(TA_LIB) >> $(TA_LIB).lst2
   C99=-std=c99
   CPP=-cpp
endif

# ************************************************************************************************
# Rules

ifeq ($(TA_LIB_OBJ),)
   OBJDIRS := $(sort $(dir $(OBJ)))
   OBJDIRS += $(sort $(dir $(LIBS)))
else
   OBJDIRS := $(sort $(dir $(TA_LIB_OBJ)))
   OBJDIRS += $(sort $(dir $(OBJ)))
endif

ifeq ($(GP_ENTRYPOINTS),Y)
all : $(UUID_H) $(GP_BIN)
else
ifdef TA_LIB_OBJ
all : $(TA_BIN) $(TA_LIB)
else
all : $(TA_BIN)
endif
endif

$(OBJDIRS):
	@mkdir -p $@

$(TA_AXF) : $(OBJDIRS) $(OBJ) $(LIBS)
	$(info ******************************************)
	$(info ** LINKER ********************************)
	$(info ******************************************)
	$(LINKER) $(LINK_OPTS) $(OBJ) $(LIBS) $(STD_LIBS)
ifeq ($(TOOLCHAIN),GNU)
ifneq ("$(wildcard $(COMP_PATH_Scripts)/perl/avstack.pl)","")
	$(COMP_PATH_Scripts)/perl/avstack.pl $(OBJ) > $(TA_AXF).txt
endif
endif

$(TA_BIN) : $(TA_AXF)
	$(info ******************************************)
	$(info ** READELF & MobiConvert *****************)
	$(info ******************************************)
	$(READELF) $(READ_OPT)
ifeq ($(SIGNING_TYPE),samsung_mobile)
# For Samsung Device (New Signinig)
	java -jar $(TASDK_DIR_SRC)/Bin/MobiConvert/signclient.jar -model $(MODEL) -runtype $(RUNTYPE) -input $(TA_AXF) -output $(TA_BIN) -conf_str $(TRUSTLET_SIGN_CONF) | size $(TA_AXF) > $(TOPDIR)/trustedapps_temp
else
ifneq ($(GP_TA_PROP_PARAM),)
	java -jar $(TASDK_DIR_SRC)/Bin/MobiConvert/MobiConvert.jar $(GP_TA_PROP_PARAM)
endif
	java -jar $(TASDK_DIR_SRC)/Bin/MobiConvert/MobiConvert.jar $(TA_PARAM) >$(TA_LOG_FILE_NAME)
ifeq ($(TA_KEYFILE),)
	mv $(TA_BIN).raw $(TA_BIN)
endif
endif

ifdef ADDITIONAL_BIN_EXT
	cp $(TA_BIN) $(OUTPUT_PATH)/$(TA_UUID).$(ADDITIONAL_BIN_EXT)
endif

# encrypt the service
ifneq ($(ENCRYPT_SERVICE_KEY),)
	$(info ******************************************)
	$(info ** Encrypting Service using MobiConvert **)
	$(info ******************************************)
	java -jar $(TASDK_DIR_SRC)/Bin/MobiConvert/MobiConvert.jar $(SERVICE_ENCRYPT_PARAMS) >$(ENCRYPTED_TA_LOG_FILE_NAME)
endif

$(UUID_H) :
	$(info ******************************************)
	$(info ** UUID header file creation    **********)
	$(info ******************************************)
	@mkdir -p "$(dir $(UUID_H))"
	$(TASDK_DIR_SRC)/uuid2header.sh $(OUTPUT_NAME) $(GP_UUID) $(UUID_H)

$(TA_LIB) : $(TA_LIB_OBJ)
	$(ARCH) $(ARCHIVER_OPTS) $(TA_LIB) $(TA_LIB_OBJ)
	$(READELF) $(READ_OPT_LIB)

.PHONY: clean clean_all clean_obj

clean :
	-rm -rf $(OUTPUT_PATH)/*

clean_all :
	-rm -rf $(OUTPUT_ROOT)/*/*

clean_obj :
	-rm -rf $(OUTPUT_OBJ_PATH)

$(OUTPUT_OBJ_PATH)/%.o : %.c $(OBJDIRS)
	$(CC) $(C99) $(CC_OPTS) $(CC_OPTS2) $(INC) -c -o $@ $<

$(OUTPUT_OBJ_PATH)/%.o : %.cpp $(OBJDIRS)
	$(CC) $(CPP) $(CC_OPTS) $(INC) -c -o $@ $<

$(OUTPUT_OBJ_PATH)/%.ol : $(TALIB_DIR)/%.c $(OBJDIRS)
	$(CC) $(C99) $(CC_OPTS_LIB) $(INC) -c -o $@ $<

$(OUTPUT_OBJ_PATH)/%.o : %.s $(OBJDIRS)
	$(ASM) $(ASM_OPTS) $(INC_ASM) -o $@ $<

$(OUTPUT_OBJ_PATH)/%.o : %.S $(OBJDIRS)
	$(ASM) $(ASM_OPTS) $(INC_ASM) -o $@ $<
# ************************************************************************************************
