From 6925d20c5567048c94e9dae63d9567882472e09f Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 4 Nov 2026 15:36:12 +0100 Subject: [PATCH 1/4] make: let user-provided options win over target defaults Target-specific assignments in arch.mk/options.mk/board.mk used hard '=', silently clobbering values the user set via command line, environment, or a sourced .config (e.g. LSCRIPT_IN from PR #958 was defeated on every target with a dedicated script). Convert the target-default assignments to '?=' (first-set wins) and, for LSCRIPT_IN, capture the user value before the target files are parsed so the last-resort default (hal/$(TARGET).ld) and the ARMClang .sct default only apply when the user provided nothing. CMake: WOLFBOOT_LSCRIPT_TEMPLATE had the same flaw (plain set() over a user -D value); guard it with NOT DEFINED and let test-app use an absolute user template as-is. Document LSCRIPT_IN as a user option in docs/compile.md. The x86 FSP TGL boards (kontron_vx3060_s2, nai_68int6) share hal/x86_fsp_tgl_stage1.ld; arch.mk selects it via 'LSCRIPT_IN ?=', but the hard default here ran first, so the stage1 build of those boards looked for a non-existent hal/kontron_vx3060_s2_stage1.ld (CI: 'kontron_vx3060_s2 build test', red on master). --- CMakeLists.txt | 12 ++-- Makefile | 14 +++- arch.mk | 88 ++++++++++++++----------- docs/compile.md | 25 +++++++ hal/boards/stm32wb_nucleo/board.mk | 2 +- hal/boards/stm32wba55cg_nucleo/board.mk | 2 +- options.mk | 6 +- stage1/Makefile | 11 +++- test-app/CMakeLists.txt | 15 +++-- tools/config.mk | 2 +- 10 files changed, 123 insertions(+), 54 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bd8dfa743c..a4a0a3c180 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1439,11 +1439,13 @@ set(KEYGEN_TOOL ${KEYGEN_TOOL} CACHE INTERNAL "") list(APPEND WOLFBOOT_INCLUDE_DIRS ${WOLFBOOT_ROOT} ${WOLFBOOT_ROOT}/include) -# set default linker script -set(WOLFBOOT_LSCRIPT_TEMPLATE hal/${WOLFBOOT_TARGET}.ld) -# Partition trailers in sectors 1-2, see hal/stm32f4.c -if(WOLFBOOT_TARGET STREQUAL "stm32f4" AND CUSTOM_PARTITION_TRAILER) - set(WOLFBOOT_LSCRIPT_TEMPLATE hal/stm32f4-trailer.ld) +# set default linker script; a user-provided WOLFBOOT_LSCRIPT_TEMPLATE wins +if(NOT DEFINED WOLFBOOT_LSCRIPT_TEMPLATE) + set(WOLFBOOT_LSCRIPT_TEMPLATE hal/${WOLFBOOT_TARGET}.ld) + # Partition trailers in sectors 1-2, see hal/stm32f4.c + if(WOLFBOOT_TARGET STREQUAL "stm32f4" AND CUSTOM_PARTITION_TRAILER) + set(WOLFBOOT_LSCRIPT_TEMPLATE hal/stm32f4-trailer.ld) + endif() endif() #--------------------------------------------------------------------------------------------- diff --git a/Makefile b/Makefile index a30e229575..b7b19de912 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,10 @@ LDFLAGS:= SECURE_LDFLAGS:= LD_START_GROUP:=-Wl,--start-group LD_END_GROUP:=-Wl,--end-group -LSCRIPT_IN?=hal/$(TARGET).ld +# Linker script: capture the user value (command line, environment, .config) +# here; target defaults in arch.mk/options.mk/board.mk use ?= so a user +# value wins. Last-resort default is applied after options.mk below. +LSCRIPT_IN_USER:=$(LSCRIPT_IN) L2SRAM_ADDR?=0xF8F00000 V?=0 DEBUG?=0 @@ -272,6 +275,10 @@ WOLFBOOT_TARGET_BUILD=1 # Parse config options include options.mk +# Last-resort linker script for targets without a dedicated default in +# arch.mk/options.mk/board.mk; a user-provided LSCRIPT_IN wins over both. +LSCRIPT_IN?=hal/$(TARGET).ld + OBJS+=$(WOLFCRYPT_OBJS) OBJS+=$(PUBLIC_KEY_OBJS) OBJS+=$(WOLFHSM_OBJS) @@ -350,7 +357,10 @@ ifeq ($(USE_ARMCLANG),1) LDFLAGS:=$(ARMCLANG_LDFLAGS) --map --list=wolfboot.map LDFLAGS+=$(LDFLAGS_EXTRA) LSCRIPT:=config/target.sct - LSCRIPT_IN:=hal/$(TARGET).sct + # ARMClang needs a .sct scatter file; a user-provided LSCRIPT_IN wins. + ifeq ($(LSCRIPT_IN_USER),) + LSCRIPT_IN:=hal/$(TARGET).sct + endif LSCRIPT_FLAGS:=--scatter=$(LSCRIPT) LD_START_GROUP:= LD_END_GROUP:= diff --git a/arch.mk b/arch.mk index 0da7cdd03f..05f9585346 100644 --- a/arch.mk +++ b/arch.mk @@ -109,7 +109,7 @@ ifeq ($(ARCH),AARCH64) ZYNQMP_PSU_INIT_DIR?=hal/board/zynqmp CFLAGS+=-DWOLFBOOT_ZYNQMP_FSBL CFLAGS+=-Ihal/zynqmp -I$(ZYNQMP_PSU_INIT_DIR) - LSCRIPT_IN=hal/zynqmp_ocm.ld + LSCRIPT_IN?=hal/zynqmp_ocm.ld OBJS+=hal/zynqmp_psu_shim.o OBJS+=hal/zynqmp_atf.o OBJS+=$(ZYNQMP_PSU_INIT_DIR)/psu_init_gpl.o @@ -510,7 +510,7 @@ ifeq ($(ARCH),ARM) SPI_TARGET=stm32 # Partition trailers in sectors 1-2, see hal/stm32f4.c ifeq ($(CUSTOM_PARTITION_TRAILER),1) - LSCRIPT_IN=hal/stm32f4-trailer.ld + LSCRIPT_IN?=hal/stm32f4-trailer.ld endif endif @@ -682,7 +682,7 @@ ifeq ($(ARCH),ARM) WOLFBOOT_ORIGIN=0x0C000000 else WOLFBOOT_ORIGIN=0x08000000 - LSCRIPT_IN=hal/$(TARGET)-ns.ld + LSCRIPT_IN?=hal/$(TARGET)-ns.ld endif endif @@ -694,7 +694,7 @@ ifeq ($(ARCH),ARM) WOLFBOOT_ORIGIN=0x0C000000 else WOLFBOOT_ORIGIN=0x08000000 - LSCRIPT_IN=hal/$(TARGET)-ns.ld + LSCRIPT_IN?=hal/$(TARGET)-ns.ld endif SPI_TARGET=stm32 endif @@ -704,7 +704,7 @@ ifeq ($(ARCH),ARM) CFLAGS+=-Ihal ARCH_FLASH_OFFSET=0x08000000 WOLFBOOT_ORIGIN=0x08000000 - LSCRIPT_IN=hal/$(TARGET).ld + LSCRIPT_IN?=hal/$(TARGET).ld SPI_TARGET=stm32 endif @@ -713,7 +713,7 @@ ifeq ($(ARCH),ARM) CFLAGS+=-Ihal ARCH_FLASH_OFFSET=0x08000000 WOLFBOOT_ORIGIN=0x08000000 - LSCRIPT_IN=hal/$(TARGET).ld + LSCRIPT_IN?=hal/$(TARGET).ld SPI_TARGET=stm32 endif @@ -724,7 +724,7 @@ ifeq ($(ARCH),ARM) # reached through the Secure SBUS alias, which the HAL derives from it. ARCH_FLASH_OFFSET=0x12000000 WOLFBOOT_ORIGIN=0x12000000 - LSCRIPT_IN=hal/$(TARGET).ld + LSCRIPT_IN?=hal/$(TARGET).ld SPI_TARGET=psoc_c3 # Board wiring. Defaults match the PSOC Control C3 evaluation kit; override # for another variant. @@ -782,13 +782,13 @@ ifeq ($(ARCH),ARM) BOOTLOADER_PARTITION_SIZE=$$(( ($(WOLFBOOT_PARTITION_BOOT_ADDRESS) | 0x10000000) - $(WOLFBOOT_ORIGIN) - 0x40)) endif ifeq ($(TZEN),1) - LSCRIPT_IN=hal/$(TARGET)-tz.ld + LSCRIPT_IN?=hal/$(TARGET)-tz.ld OBJS+=hal/psoc_e8_tz.o # wolfHSM NVM in the RRAM user area, Secure. WOLFBOOT_KEYVAULT_ADDRESS?=0x32040000 WOLFBOOT_KEYVAULT_SIZE?=0x10000 else - LSCRIPT_IN=hal/$(TARGET).ld + LSCRIPT_IN?=hal/$(TARGET).ld endif # Board wiring, defaulted for KIT_PSE84_AI. PSOC_E8_UART_SCB?=2 @@ -830,7 +830,7 @@ ifeq ($(ARCH),ARM) ARCH_FLASH_OFFSET=0x00000000 WOLFBOOT_ORIGIN=0x00000000 ifneq ($(TZEN),1) - LSCRIPT_IN=hal/$(TARGET)-ns.ld + LSCRIPT_IN?=hal/$(TARGET)-ns.ld endif endif @@ -842,7 +842,7 @@ ifeq ($(ARCH),ARM) WOLFBOOT_ORIGIN=0x0C000000 else WOLFBOOT_ORIGIN=0x08000000 - LSCRIPT_IN=hal/$(TARGET)-ns.ld + LSCRIPT_IN?=hal/$(TARGET)-ns.ld endif SPI_TARGET=stm32 ifneq ($(DEBUG),0) @@ -869,9 +869,9 @@ ifeq ($(ARCH),ARM) ARCH_FLASH_OFFSET=0x10000000 WOLFBOOT_ORIGIN=0x10000000 ifeq ($(TZEN),1) - LSCRIPT_IN=hal/$(TARGET).ld + LSCRIPT_IN?=hal/$(TARGET).ld else - LSCRIPT_IN=hal/$(TARGET)-ns.ld + LSCRIPT_IN?=hal/$(TARGET)-ns.ld endif SPI_TARGET=raspberrypi_pico CFLAGS+=-DPICO_SDK_PATH=$(PICO_SDK_PATH) @@ -1420,7 +1420,7 @@ ifeq ($(ARCH),RISCV64) OBJS+=src/riscv_sbi.o endif # Use M-mode specific linker script - LSCRIPT_IN:=hal/$(TARGET)-m.ld + LSCRIPT_IN?=hal/$(TARGET)-m.ld # Boot mode 2: reserve the last eNVM page for the signed manifest the UBL # stub verifies (hal/mpfs250-m.ld); `make wolfboot_envm_signed.bin` fills it. ifeq ($(MPFS_ENVM_MANIFEST),1) @@ -1458,7 +1458,7 @@ ifeq ($(ARCH),RISCV64) CFLAGS+=-DWOLFBOOT_DUALBOOT ifeq ($(MPFS_L2LIM),1) # L2-LIM mode: wolfBoot in on-chip SRAM, loaded by HSS (no DDR) - LSCRIPT_IN:=hal/$(TARGET)-hss.ld + LSCRIPT_IN?=hal/$(TARGET)-hss.ld else # DDR mode (default): full MMU and FDT support CFLAGS+=-DMMU @@ -1480,7 +1480,11 @@ ifeq ($(ARCH),RISCV64) # Boot mode 2 UBL stub: LIM-resident, verifies the eNVM wolfBoot manifest # in place and jumps; no update path (hal/mpfs250_ubl.c). ifeq ($(TARGET),mpfs250_ubl) - LSCRIPT_IN:=hal/mpfs250_ubl.ld + # UBL stub has its own layout; overrides the generic M-mode default + # above (a user-provided LSCRIPT_IN still wins). + ifeq ($(LSCRIPT_IN_USER),) + LSCRIPT_IN:=hal/mpfs250_ubl.ld + endif UPDATE_OBJS:= # mcycle rate for hal_get_timer_us(): the stub runs at the reset clock CFLAGS+=-DRISCV_SMODE_TIMER_FREQ=80000000UL @@ -1709,7 +1713,7 @@ endif ifeq ($(TARGET),mcxw) CORTEX_M33=1 ifneq ($(TZEN),1) - LSCRIPT_IN=hal/$(TARGET)-ns.ld + LSCRIPT_IN?=hal/$(TARGET)-ns.ld endif CFLAGS+=\ -I$(MCUXPRESSO_DRIVERS) \ @@ -1762,7 +1766,7 @@ endif ifeq ($(TARGET),mcxn) CORTEX_M33=1 ifneq ($(TZEN),1) - LSCRIPT_IN=hal/$(TARGET)-ns.ld + LSCRIPT_IN?=hal/$(TARGET)-ns.ld endif CFLAGS+=\ -I$(MCUXPRESSO_DRIVERS) \ @@ -1817,7 +1821,7 @@ ifeq ($(TARGET),rw612) CORTEX_M33=1 ARCH_FLASH_OFFSET=0x08000000 ifneq ($(TZEN),1) - LSCRIPT_IN=hal/$(TARGET)-ns.ld + LSCRIPT_IN?=hal/$(TARGET)-ns.ld endif MCUXPRESSO_FLASH_CONFIG?=$(MCUXPRESSO_PROJECT_TEMPLATE)/../flash_config CFLAGS+=\ @@ -1858,13 +1862,13 @@ endif ifeq ($(TARGET),nrf5340) ifneq ($(TZEN), 1) - LSCRIPT_IN=hal/$(TARGET)-ns.ld + LSCRIPT_IN?=hal/$(TARGET)-ns.ld endif endif ifeq ($(TARGET),nrf54l) ifneq ($(TZEN), 1) - LSCRIPT_IN=hal/$(TARGET)-ns.ld + LSCRIPT_IN?=hal/$(TARGET)-ns.ld endif endif @@ -1926,9 +1930,9 @@ ifeq ($(TARGET),imx_rt) endif ifeq ($(TARGET_IMX_HAB),1) - LSCRIPT_IN:=hal/$(TARGET)_hab.ld + LSCRIPT_IN?=hal/$(TARGET)_hab.ld else - LSCRIPT_IN:=hal/$(TARGET).ld + LSCRIPT_IN?=hal/$(TARGET).ld endif ifeq ($(MCUXPRESSO_CPU),MIMXRT1064DVL6A) @@ -2251,7 +2255,7 @@ endif ifeq ($(TARGET),lpc55s69) ifneq ($(TZEN),1) - LSCRIPT_IN=hal/$(TARGET)-ns.ld + LSCRIPT_IN?=hal/$(TARGET)-ns.ld endif CFLAGS+=\ -I$(MCUXPRESSO_PROJECT_TEMPLATE) \ @@ -2459,9 +2463,9 @@ ifeq ("${FSP}", "1") ifeq ($(filter-out $(STAGE1),1),) # building stage1 ifeq ($(FSP_TGL), 1) - LSCRIPT_IN = ../hal/x86_fsp_tgl_stage1.ld + LSCRIPT_IN ?= ../hal/x86_fsp_tgl_stage1.ld else - LSCRIPT_IN = ../hal/$(TARGET)_stage1.ld + LSCRIPT_IN ?= ../hal/$(TARGET)_stage1.ld endif # using ../wolfboot.map as stage1 is built from stage1 sub-directory LDFLAGS = --defsym main=0x`nm ../wolfboot.elf | grep -w main | awk '{print $$1}'` \ @@ -2504,9 +2508,9 @@ ifeq ("${FSP}", "1") else # building wolfBoot ifeq ($(FSP_TGL), 1) - LSCRIPT_IN = hal/x86_fsp_tgl.ld.in + LSCRIPT_IN ?= hal/x86_fsp_tgl.ld.in else - LSCRIPT_IN = hal/$(TARGET).ld.in + LSCRIPT_IN ?= hal/$(TARGET).ld.in endif LDFLAGS = --gc-sections --entry=main -T $(LSCRIPT) -Map=wolfboot.map CFLAGS += -fno-stack-protector -fno-PIC -fno-pie -mno-mmx -mno-sse -Os -DDEBUG_UART @@ -2920,14 +2924,18 @@ ifeq ($(ARCH), AURIX) # HighTec's ancient ARM ld cannot parse the BSP linker-script fragments. # Flatten them at parse time with the wolfHSM port's ld-flatten.sh. # Paths are relative to this arch.mk, which is included from both the - # wolfBoot root and test-app directories. + # wolfBoot root and test-app directories. A user-provided LSCRIPT_IN + # is used as-is; only the stock HAL script goes through the flattener + # (its output lands in config/). ARCHMK_DIR:=$(dir $(lastword $(MAKEFILE_LIST))) - LSCRIPT_IN=$(ARCHMK_DIR)config/$(TARGET)_flat.ld - ifeq ($(filter clean keysclean,$(MAKECMDGOALS)),) - LD_FLATTEN_OUT:=$(shell $(WOLFHSM_INFINEON_TC3XX)/tchsm-server/ld-flatten.sh \ - $(ARCHMK_DIR)hal/$(TARGET).ld $(LSCRIPT_IN) $(TC3_DIR)/tc3 && echo OK) - ifneq ($(LD_FLATTEN_OUT),OK) - $(error ld-flatten.sh failed for hal/$(TARGET).ld) + ifeq ($(LSCRIPT_IN),) + LSCRIPT_IN:=$(ARCHMK_DIR)config/$(TARGET)_flat.ld + ifeq ($(filter clean keysclean,$(MAKECMDGOALS)),) + LD_FLATTEN_OUT:=$(shell $(WOLFHSM_INFINEON_TC3XX)/tchsm-server/ld-flatten.sh \ + $(ARCHMK_DIR)hal/$(TARGET).ld $(LSCRIPT_IN) $(TC3_DIR)/tc3 && echo OK) + ifneq ($(LD_FLATTEN_OUT),OK) + $(error ld-flatten.sh failed for hal/$(TARGET).ld) + endif endif endif else ifeq ($(HT_LLVM),1) @@ -3084,9 +3092,9 @@ ifeq ($(ARCH), AURIX) # Linker scripts ship with the port, not in hal/. ifeq ($(TARGET), aurix_tc4xx_csrm) - LSCRIPT_IN=$(TC4_WB_DIR)/csrm/aurix_tc4xx_csrm.ld + LSCRIPT_IN?=$(TC4_WB_DIR)/csrm/aurix_tc4xx_csrm.ld else - LSCRIPT_IN=$(TC4_WB_DIR)/aurix_tc4xx.ld + LSCRIPT_IN?=$(TC4_WB_DIR)/aurix_tc4xx.ld endif CFLAGS += \ -I$(TC4_LLD_DIR) \ @@ -3193,7 +3201,11 @@ ifeq ($(ARCH), AURIX) # Full-system CSRM wolfBoot target leaves host release to tchsm-server. ifeq ($(AURIX_TC4_FULLSYS),1) CFLAGS += -DWOLFBOOT_AURIX_TC4XX_FULLSYS - LSCRIPT_IN=$(TC4_WB_DIR)/csrm/aurix_tc4xx_csrm_fullsys.ld + # Full-system layout overrides the per-port default above; a + # user-provided LSCRIPT_IN still wins. + ifeq ($(LSCRIPT_IN_USER),) + LSCRIPT_IN:=$(TC4_WB_DIR)/csrm/aurix_tc4xx_csrm_fullsys.ld + endif endif endif diff --git a/docs/compile.md b/docs/compile.md index c4ead3ae69..bfe66d4045 100644 --- a/docs/compile.md +++ b/docs/compile.md @@ -114,6 +114,31 @@ trailer sector of room on top — see the sizing guide in [firmware_update.md](firmware_update.md#independent-partition-sizing). Not supported with `ENCRYPT` or `PULL_LINKER_DEFINES`. +### Custom linker script + +Each target ships a linker script (e.g. `hal/stm32f4.ld`) that is selected by +the build system based on the target and active options (TZEN, encryption, +trailers, ...). To use your own script instead, set `LSCRIPT_IN` to its path, +either in the .config file, in the environment, or on the make command line: + +```sh +make TARGET=stm32f4 LSCRIPT_IN=/path/to/my.ld +``` + +A user-provided `LSCRIPT_IN` wins over the target-specific default; when unset, +the build falls back to the script of the target, then to `hal/$(TARGET).ld`. +The script is processed by the same substitution pipeline as the included ones, +so it can (and should) use the same `@PLACEHOLDERS@` (e.g. +`@WOLFBOOT_PARTITION_BOOT_ADDRESS@`, `@WOLFBOOT_PARTITION_SIZE@`, +`@ARCH_FLASH_OFFSET@`); the substituted output is written to `config/target.ld`. + +Notes: + + - With ARMClang (`USE_ARMCLANG=1`) the script must be a `.sct` scatter file. + - On two-stage targets (e.g. x86) the same script is used for both stages. + - The script must place the bootloader sections so that they fit the flash + geometry configured above; wolfBoot does not validate the layout. + ## Bootloader features A number of characteristics can be turned on/off during wolfBoot compilation. Bootloader size, diff --git a/hal/boards/stm32wb_nucleo/board.mk b/hal/boards/stm32wb_nucleo/board.mk index 5b6f832a8f..b3c88e627f 100644 --- a/hal/boards/stm32wb_nucleo/board.mk +++ b/hal/boards/stm32wb_nucleo/board.mk @@ -1,5 +1,5 @@ ARCH_FLASH_OFFSET=0x08000000 -LSCRIPT_IN=hal/stm32wb.ld +LSCRIPT_IN?=hal/stm32wb.ld CFLAGS+=-DWHAL_CFG_NO_TIMEOUT diff --git a/hal/boards/stm32wba55cg_nucleo/board.mk b/hal/boards/stm32wba55cg_nucleo/board.mk index 800139bcea..07e6f19f7a 100644 --- a/hal/boards/stm32wba55cg_nucleo/board.mk +++ b/hal/boards/stm32wba55cg_nucleo/board.mk @@ -1,5 +1,5 @@ ARCH_FLASH_OFFSET=0x08000000 -LSCRIPT_IN=hal/stm32wba.ld +LSCRIPT_IN?=hal/stm32wba.ld CFLAGS+=-DWHAL_CFG_NO_TIMEOUT diff --git a/options.mk b/options.mk index b4dd0754ba..49d3b82024 100644 --- a/options.mk +++ b/options.mk @@ -1908,7 +1908,11 @@ ifeq ($(RAM_CODE),1) ifeq ($(ENCRYPT),1) ifeq ($(ENCRYPT_WITH_CHACHA),1) ifneq ($(WOLFHAL),1) - LSCRIPT_IN=hal/$(TARGET)_chacha_ram.ld + # RAM+ChaCha layout overrides the target default set earlier; a + # user-provided LSCRIPT_IN still wins. + ifeq ($(LSCRIPT_IN_USER),) + LSCRIPT_IN:=hal/$(TARGET)_chacha_ram.ld + endif endif endif endif diff --git a/stage1/Makefile b/stage1/Makefile index 8ab80ff3fa..44dd602296 100644 --- a/stage1/Makefile +++ b/stage1/Makefile @@ -17,7 +17,16 @@ CFLAGS:=-D"__WOLFBOOT" CFLAGS+=-Werror -Wextra -nostdlib LDFLAGS:= LSCRIPT:=loader_stage1.ld -LSCRIPT_IN:=../hal/$(TARGET)_stage1.ld +# Capture the user value (command line, environment, .config) before any +# default below; arch.mk/options.mk use this marker to let a user-provided +# LSCRIPT_IN win over their target refinements, same as the top-level Makefile. +LSCRIPT_IN_USER:=$(LSCRIPT_IN) +# Default stage1 script. Targets that share a script (the x86 FSP TGL +# boards use hal/x86_fsp_tgl_stage1.ld) set LSCRIPT_IN in arch.mk, so +# only default when the per-target file (or its .ld.in template) exists. +ifneq ($(wildcard ../hal/$(TARGET)_stage1.ld ../hal/$(TARGET)_stage1.ld.in),) +LSCRIPT_IN?=../hal/$(TARGET)_stage1.ld +endif LSCRIPT_FLAGS:= LD_START_GROUP:=-Wl,--start-group LD_END_GROUP:=-Wl,--end-group diff --git a/test-app/CMakeLists.txt b/test-app/CMakeLists.txt index 66a571cd2b..2ce1bcae7f 100644 --- a/test-app/CMakeLists.txt +++ b/test-app/CMakeLists.txt @@ -97,14 +97,21 @@ if(NOT DEFINED BOOTLOADER_PARTITION_SIZE) OUTPUT_FORMAT HEXADECIMAL) endif() -get_filename_component(WOLFBOOT_LSCRIPT ${CMAKE_SOURCE_DIR}/${WOLFBOOT_LSCRIPT_TEMPLATE} NAME) -set(WOLFBOOT_LSCRIPT ${CMAKE_CURRENT_BINARY_DIR}/${WOLFBOOT_LSCRIPT}) +# The generated bootloader script gets a fixed name so a user template +# sharing a basename with the app's template cannot collide in the build dir +set(WOLFBOOT_LSCRIPT ${CMAKE_CURRENT_BINARY_DIR}/wolfboot_${WOLFBOOT_TARGET}.ld) get_filename_component(APP_LSCRIPT ${APP_LSCRIPT_TEMPLATE} NAME) set(APP_LSCRIPT ${CMAKE_CURRENT_BINARY_DIR}/${APP_LSCRIPT}) -# generate linker script for bootloader -configure_file(${CMAKE_SOURCE_DIR}/${WOLFBOOT_LSCRIPT_TEMPLATE} ${WOLFBOOT_LSCRIPT}) +# generate linker script for bootloader; an absolute user-provided template +# is used as-is, relative ones are resolved against the source directory +if(IS_ABSOLUTE ${WOLFBOOT_LSCRIPT_TEMPLATE}) + set(WOLFBOOT_LSCRIPT_SRC ${WOLFBOOT_LSCRIPT_TEMPLATE}) +else() + set(WOLFBOOT_LSCRIPT_SRC ${CMAKE_SOURCE_DIR}/${WOLFBOOT_LSCRIPT_TEMPLATE}) +endif() +configure_file(${WOLFBOOT_LSCRIPT_SRC} ${WOLFBOOT_LSCRIPT}) # generate linker script for app configure_file(${APP_LSCRIPT_TEMPLATE} ${APP_LSCRIPT}) diff --git a/tools/config.mk b/tools/config.mk index 02dc6757b7..c64043862f 100644 --- a/tools/config.mk +++ b/tools/config.mk @@ -102,7 +102,7 @@ ifeq ($(ARCH),) DISK_LOCK_PASSWORD?= FLASH_OTP_KEYSTORE?=0 BIG_ENDIAN?=0 - FLASH_MULTI_SECTOR_ERASE=0 + FLASH_MULTI_SECTOR_ERASE?=0 WOLFHSM_CLIENT=0 WOLFHSM_CLIENT_ID?=1 endif From f70053cb6b755f500c1084d2de3ba9b2cf0e0b37 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 4 Nov 2026 18:45:37 +0100 Subject: [PATCH 2/4] make: persist LSCRIPT_IN in config, pass absolute path to stage1 Copilot review follow-ups: - tools/config.mk: add LSCRIPT_IN to CONFIG_VARS so 'make config' persists it; it was documented as a .config option but the regeneration silently dropped it - Makefile: pass a user-provided LSCRIPT_IN to the recursive stage1 build as an absolute path (abspath), since the sub-make resolves relative paths from stage1/ while the top-level link resolves them from the repo root; target-derived stage1 defaults are untouched --- Makefile | 5 ++++- tools/config.mk | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index b7b19de912..844479f76d 100644 --- a/Makefile +++ b/Makefile @@ -573,7 +573,10 @@ stage1: stage1/loader_stage1.bin stage1/loader_stage1.bin: wolfboot.elf stage1/loader_stage1.bin: FORCE @echo "\t[BIN] $@" - $(Q)$(MAKE) -C $(dir $@) $(notdir $@) + # A user-provided LSCRIPT_IN is relative to the repo root; the recursive + # make runs from stage1/, so pass it as an absolute path. Target-derived + # stage1 defaults keep their own selection (nothing is passed). + $(Q)$(MAKE) -C $(dir $@) $(notdir $@) $(if $(LSCRIPT_IN_USER),LSCRIPT_IN=$(abspath $(LSCRIPT_IN_USER))) libwolfboot.a: include/target.h $(OBJS) @echo "\t[LIB] $@" diff --git a/tools/config.mk b/tools/config.mk index c64043862f..7245e8723d 100644 --- a/tools/config.mk +++ b/tools/config.mk @@ -149,7 +149,7 @@ CONFIG_VARS:= ARCH TARGET SIGN HASH MCUXSDK MCUXPRESSO MCUXPRESSO_CPU MCUXPRESSO ENCRYPT_WITH_CHACHA ENCRYPT_WITH_AES128 ENCRYPT_WITH_AES256 ARMORED \ LMS_LEVELS LMS_HEIGHT LMS_WINTERNITZ \ WOLFBOOT_UNIVERSAL_KEYSTORE \ - XMSS_PARAMS \ + XMSS_PARAMS LSCRIPT_IN \ ELF BIG_ENDIAN \ GZIP FIT_RAMDISK \ COMPRESSED_UPDATE WOLFBOOT_COMPRESSED_WINDOW \ From 7f3236ce03eb6281131674cf81bce2438e2883fc Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 4 Nov 2026 19:23:50 +0100 Subject: [PATCH 3/4] make: treat empty LSCRIPT_IN as unset, guard stage1 .ld.in rule Copilot review follow-ups: - config/Makefile: skip emitting a variable whose value is empty, so 'make config' with a blank LSCRIPT_IN prompt no longer persists a defined-but-empty 'LSCRIPT_IN?=' (quoted test -n: unquoted, bash's test returns true for a missing operand) - Makefile: the last-resort hal/$(TARGET).ld default now keys on strip(LSCRIPT_IN) being empty, so a persisted empty value falls back correctly - stage1/x86_fsp.mk: the .ld.in generation rule only applies to the target-derived script; a user-provided LSCRIPT_IN is used as-is (it previously produced a bogus hal/.in prerequisite) --- Makefile | 6 +++++- config/Makefile | 2 +- stage1/x86_fsp.mk | 4 ++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 844479f76d..8ee1a22d36 100644 --- a/Makefile +++ b/Makefile @@ -277,7 +277,11 @@ include options.mk # Last-resort linker script for targets without a dedicated default in # arch.mk/options.mk/board.mk; a user-provided LSCRIPT_IN wins over both. -LSCRIPT_IN?=hal/$(TARGET).ld +# An empty value (e.g. an LSCRIPT_IN?= persisted by an older 'make config') +# counts as unset. +ifeq ($(strip $(LSCRIPT_IN)),) + LSCRIPT_IN:=hal/$(TARGET).ld +endif OBJS+=$(WOLFCRYPT_OBJS) OBJS+=$(PUBLIC_KEY_OBJS) diff --git a/config/Makefile b/config/Makefile index 3426c06352..3f3b4adc71 100644 --- a/config/Makefile +++ b/config/Makefile @@ -4,5 +4,5 @@ config: rm -f ../config/target.ld rm -f ../.config rm -f ../include/target.h - @$(foreach q, $(CONFIG_VARS), a=$($q); echo -n $q \? [$$a] :; a=$($q); read SH_$q; test -z $$SH_$q && SH_$q=$$a; echo "$q?=$$SH_$q" >> ../.config;) + @$(foreach q, $(CONFIG_VARS), a=$($q); echo -n $q \? [$$a] :; a=$($q); read SH_$q; test -z $$SH_$q && SH_$q=$$a; test -n "$$SH_$q" && echo "$q?=$$SH_$q" >> ../.config;) diff --git a/stage1/x86_fsp.mk b/stage1/x86_fsp.mk index f367679ea4..c4c34c3198 100644 --- a/stage1/x86_fsp.mk +++ b/stage1/x86_fsp.mk @@ -4,6 +4,9 @@ SIGN_KEY?=../wolfboot_signing_private_key.der X86FSP_PATH?=../`dirname $(FSP_M_BIN)` +# Generate the stage1 script from its .ld.in template; a user-provided +# LSCRIPT_IN is used as-is. +ifeq ($(LSCRIPT_IN_USER),) $(LSCRIPT_IN): $(WOLFBOOT_ROOT)/hal/$(LSCRIPT_IN).in FORCE @cat $(WOLFBOOT_ROOT)/hal/$(LSCRIPT_IN).in | \ sed -e "s/@FSP_T_BASE@/$(FSP_T_BASE)/g" | \ @@ -13,6 +16,7 @@ $(LSCRIPT_IN): $(WOLFBOOT_ROOT)/hal/$(LSCRIPT_IN).in FORCE sed -e "s/@UCODE0_BASE@/$(UCODE0_BASE)/g" | \ sed -e "s/@UCODE1_BASE@/$(UCODE1_BASE)/g" \ > $@ +endif ./boot_x86_fsp_start.o: boot_x86_fsp_start.S @echo "\t[NASM-$(ARCH)] $@" From 6b12eec9744c4b9d564e6eef93874ea71fa60fc2 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 4 Nov 2026 20:56:20 +0100 Subject: [PATCH 4/4] make: treat empty LSCRIPT_IN as unset at every target default Copilot review follow-up: ?= considers a defined-but-empty LSCRIPT_IN (stale LSCRIPT_IN?= line in .config, exported empty env var) already set, so it skipped every target-specific default and fell through to the last-resort hal/$(TARGET).ld - e.g. TARGET=stm32l5 TZEN=0 lost its hal/stm32l5-ns.ld layout. The strip-based last-resort check only fixed that one line, not the 32 target sites. Add the LSCRIPT_IN_DEFAULT helper in tools/config.mk (assigns only when LSCRIPT_IN is undefined or empty) and convert all 29 arch.mk, 2 board.mk and 1 stage1/Makefile sites to it. --- Makefile | 6 ++- arch.mk | 58 ++++++++++++------------- hal/boards/stm32wb_nucleo/board.mk | 2 +- hal/boards/stm32wba55cg_nucleo/board.mk | 2 +- stage1/Makefile | 2 +- tools/config.mk | 6 +++ 6 files changed, 42 insertions(+), 34 deletions(-) diff --git a/Makefile b/Makefile index 8ee1a22d36..4cd4ceb24a 100644 --- a/Makefile +++ b/Makefile @@ -39,8 +39,10 @@ SECURE_LDFLAGS:= LD_START_GROUP:=-Wl,--start-group LD_END_GROUP:=-Wl,--end-group # Linker script: capture the user value (command line, environment, .config) -# here; target defaults in arch.mk/options.mk/board.mk use ?= so a user -# value wins. Last-resort default is applied after options.mk below. +# here; target defaults in arch.mk/options.mk/board.mk use the +# LSCRIPT_IN_DEFAULT helper (see tools/config.mk), which only assigns when +# LSCRIPT_IN is undefined or empty, so a user value wins. Last-resort +# default is applied after options.mk below. LSCRIPT_IN_USER:=$(LSCRIPT_IN) L2SRAM_ADDR?=0xF8F00000 V?=0 diff --git a/arch.mk b/arch.mk index 05f9585346..35ffc16883 100644 --- a/arch.mk +++ b/arch.mk @@ -109,7 +109,7 @@ ifeq ($(ARCH),AARCH64) ZYNQMP_PSU_INIT_DIR?=hal/board/zynqmp CFLAGS+=-DWOLFBOOT_ZYNQMP_FSBL CFLAGS+=-Ihal/zynqmp -I$(ZYNQMP_PSU_INIT_DIR) - LSCRIPT_IN?=hal/zynqmp_ocm.ld + $(call LSCRIPT_IN_DEFAULT,hal/zynqmp_ocm.ld) OBJS+=hal/zynqmp_psu_shim.o OBJS+=hal/zynqmp_atf.o OBJS+=$(ZYNQMP_PSU_INIT_DIR)/psu_init_gpl.o @@ -510,7 +510,7 @@ ifeq ($(ARCH),ARM) SPI_TARGET=stm32 # Partition trailers in sectors 1-2, see hal/stm32f4.c ifeq ($(CUSTOM_PARTITION_TRAILER),1) - LSCRIPT_IN?=hal/stm32f4-trailer.ld + $(call LSCRIPT_IN_DEFAULT,hal/stm32f4-trailer.ld) endif endif @@ -682,7 +682,7 @@ ifeq ($(ARCH),ARM) WOLFBOOT_ORIGIN=0x0C000000 else WOLFBOOT_ORIGIN=0x08000000 - LSCRIPT_IN?=hal/$(TARGET)-ns.ld + $(call LSCRIPT_IN_DEFAULT,hal/$(TARGET)-ns.ld) endif endif @@ -694,7 +694,7 @@ ifeq ($(ARCH),ARM) WOLFBOOT_ORIGIN=0x0C000000 else WOLFBOOT_ORIGIN=0x08000000 - LSCRIPT_IN?=hal/$(TARGET)-ns.ld + $(call LSCRIPT_IN_DEFAULT,hal/$(TARGET)-ns.ld) endif SPI_TARGET=stm32 endif @@ -704,7 +704,7 @@ ifeq ($(ARCH),ARM) CFLAGS+=-Ihal ARCH_FLASH_OFFSET=0x08000000 WOLFBOOT_ORIGIN=0x08000000 - LSCRIPT_IN?=hal/$(TARGET).ld + $(call LSCRIPT_IN_DEFAULT,hal/$(TARGET).ld) SPI_TARGET=stm32 endif @@ -713,7 +713,7 @@ ifeq ($(ARCH),ARM) CFLAGS+=-Ihal ARCH_FLASH_OFFSET=0x08000000 WOLFBOOT_ORIGIN=0x08000000 - LSCRIPT_IN?=hal/$(TARGET).ld + $(call LSCRIPT_IN_DEFAULT,hal/$(TARGET).ld) SPI_TARGET=stm32 endif @@ -724,7 +724,7 @@ ifeq ($(ARCH),ARM) # reached through the Secure SBUS alias, which the HAL derives from it. ARCH_FLASH_OFFSET=0x12000000 WOLFBOOT_ORIGIN=0x12000000 - LSCRIPT_IN?=hal/$(TARGET).ld + $(call LSCRIPT_IN_DEFAULT,hal/$(TARGET).ld) SPI_TARGET=psoc_c3 # Board wiring. Defaults match the PSOC Control C3 evaluation kit; override # for another variant. @@ -782,13 +782,13 @@ ifeq ($(ARCH),ARM) BOOTLOADER_PARTITION_SIZE=$$(( ($(WOLFBOOT_PARTITION_BOOT_ADDRESS) | 0x10000000) - $(WOLFBOOT_ORIGIN) - 0x40)) endif ifeq ($(TZEN),1) - LSCRIPT_IN?=hal/$(TARGET)-tz.ld + $(call LSCRIPT_IN_DEFAULT,hal/$(TARGET)-tz.ld) OBJS+=hal/psoc_e8_tz.o # wolfHSM NVM in the RRAM user area, Secure. WOLFBOOT_KEYVAULT_ADDRESS?=0x32040000 WOLFBOOT_KEYVAULT_SIZE?=0x10000 else - LSCRIPT_IN?=hal/$(TARGET).ld + $(call LSCRIPT_IN_DEFAULT,hal/$(TARGET).ld) endif # Board wiring, defaulted for KIT_PSE84_AI. PSOC_E8_UART_SCB?=2 @@ -830,7 +830,7 @@ ifeq ($(ARCH),ARM) ARCH_FLASH_OFFSET=0x00000000 WOLFBOOT_ORIGIN=0x00000000 ifneq ($(TZEN),1) - LSCRIPT_IN?=hal/$(TARGET)-ns.ld + $(call LSCRIPT_IN_DEFAULT,hal/$(TARGET)-ns.ld) endif endif @@ -842,7 +842,7 @@ ifeq ($(ARCH),ARM) WOLFBOOT_ORIGIN=0x0C000000 else WOLFBOOT_ORIGIN=0x08000000 - LSCRIPT_IN?=hal/$(TARGET)-ns.ld + $(call LSCRIPT_IN_DEFAULT,hal/$(TARGET)-ns.ld) endif SPI_TARGET=stm32 ifneq ($(DEBUG),0) @@ -869,9 +869,9 @@ ifeq ($(ARCH),ARM) ARCH_FLASH_OFFSET=0x10000000 WOLFBOOT_ORIGIN=0x10000000 ifeq ($(TZEN),1) - LSCRIPT_IN?=hal/$(TARGET).ld + $(call LSCRIPT_IN_DEFAULT,hal/$(TARGET).ld) else - LSCRIPT_IN?=hal/$(TARGET)-ns.ld + $(call LSCRIPT_IN_DEFAULT,hal/$(TARGET)-ns.ld) endif SPI_TARGET=raspberrypi_pico CFLAGS+=-DPICO_SDK_PATH=$(PICO_SDK_PATH) @@ -1420,7 +1420,7 @@ ifeq ($(ARCH),RISCV64) OBJS+=src/riscv_sbi.o endif # Use M-mode specific linker script - LSCRIPT_IN?=hal/$(TARGET)-m.ld + $(call LSCRIPT_IN_DEFAULT,hal/$(TARGET)-m.ld) # Boot mode 2: reserve the last eNVM page for the signed manifest the UBL # stub verifies (hal/mpfs250-m.ld); `make wolfboot_envm_signed.bin` fills it. ifeq ($(MPFS_ENVM_MANIFEST),1) @@ -1458,7 +1458,7 @@ ifeq ($(ARCH),RISCV64) CFLAGS+=-DWOLFBOOT_DUALBOOT ifeq ($(MPFS_L2LIM),1) # L2-LIM mode: wolfBoot in on-chip SRAM, loaded by HSS (no DDR) - LSCRIPT_IN?=hal/$(TARGET)-hss.ld + $(call LSCRIPT_IN_DEFAULT,hal/$(TARGET)-hss.ld) else # DDR mode (default): full MMU and FDT support CFLAGS+=-DMMU @@ -1713,7 +1713,7 @@ endif ifeq ($(TARGET),mcxw) CORTEX_M33=1 ifneq ($(TZEN),1) - LSCRIPT_IN?=hal/$(TARGET)-ns.ld + $(call LSCRIPT_IN_DEFAULT,hal/$(TARGET)-ns.ld) endif CFLAGS+=\ -I$(MCUXPRESSO_DRIVERS) \ @@ -1766,7 +1766,7 @@ endif ifeq ($(TARGET),mcxn) CORTEX_M33=1 ifneq ($(TZEN),1) - LSCRIPT_IN?=hal/$(TARGET)-ns.ld + $(call LSCRIPT_IN_DEFAULT,hal/$(TARGET)-ns.ld) endif CFLAGS+=\ -I$(MCUXPRESSO_DRIVERS) \ @@ -1821,7 +1821,7 @@ ifeq ($(TARGET),rw612) CORTEX_M33=1 ARCH_FLASH_OFFSET=0x08000000 ifneq ($(TZEN),1) - LSCRIPT_IN?=hal/$(TARGET)-ns.ld + $(call LSCRIPT_IN_DEFAULT,hal/$(TARGET)-ns.ld) endif MCUXPRESSO_FLASH_CONFIG?=$(MCUXPRESSO_PROJECT_TEMPLATE)/../flash_config CFLAGS+=\ @@ -1862,13 +1862,13 @@ endif ifeq ($(TARGET),nrf5340) ifneq ($(TZEN), 1) - LSCRIPT_IN?=hal/$(TARGET)-ns.ld + $(call LSCRIPT_IN_DEFAULT,hal/$(TARGET)-ns.ld) endif endif ifeq ($(TARGET),nrf54l) ifneq ($(TZEN), 1) - LSCRIPT_IN?=hal/$(TARGET)-ns.ld + $(call LSCRIPT_IN_DEFAULT,hal/$(TARGET)-ns.ld) endif endif @@ -1930,9 +1930,9 @@ ifeq ($(TARGET),imx_rt) endif ifeq ($(TARGET_IMX_HAB),1) - LSCRIPT_IN?=hal/$(TARGET)_hab.ld + $(call LSCRIPT_IN_DEFAULT,hal/$(TARGET)_hab.ld) else - LSCRIPT_IN?=hal/$(TARGET).ld + $(call LSCRIPT_IN_DEFAULT,hal/$(TARGET).ld) endif ifeq ($(MCUXPRESSO_CPU),MIMXRT1064DVL6A) @@ -2255,7 +2255,7 @@ endif ifeq ($(TARGET),lpc55s69) ifneq ($(TZEN),1) - LSCRIPT_IN?=hal/$(TARGET)-ns.ld + $(call LSCRIPT_IN_DEFAULT,hal/$(TARGET)-ns.ld) endif CFLAGS+=\ -I$(MCUXPRESSO_PROJECT_TEMPLATE) \ @@ -2463,9 +2463,9 @@ ifeq ("${FSP}", "1") ifeq ($(filter-out $(STAGE1),1),) # building stage1 ifeq ($(FSP_TGL), 1) - LSCRIPT_IN ?= ../hal/x86_fsp_tgl_stage1.ld + $(call LSCRIPT_IN_DEFAULT,../hal/x86_fsp_tgl_stage1.ld) else - LSCRIPT_IN ?= ../hal/$(TARGET)_stage1.ld + $(call LSCRIPT_IN_DEFAULT,../hal/$(TARGET)_stage1.ld) endif # using ../wolfboot.map as stage1 is built from stage1 sub-directory LDFLAGS = --defsym main=0x`nm ../wolfboot.elf | grep -w main | awk '{print $$1}'` \ @@ -2508,9 +2508,9 @@ ifeq ("${FSP}", "1") else # building wolfBoot ifeq ($(FSP_TGL), 1) - LSCRIPT_IN ?= hal/x86_fsp_tgl.ld.in + $(call LSCRIPT_IN_DEFAULT,hal/x86_fsp_tgl.ld.in) else - LSCRIPT_IN ?= hal/$(TARGET).ld.in + $(call LSCRIPT_IN_DEFAULT,hal/$(TARGET).ld.in) endif LDFLAGS = --gc-sections --entry=main -T $(LSCRIPT) -Map=wolfboot.map CFLAGS += -fno-stack-protector -fno-PIC -fno-pie -mno-mmx -mno-sse -Os -DDEBUG_UART @@ -3092,9 +3092,9 @@ ifeq ($(ARCH), AURIX) # Linker scripts ship with the port, not in hal/. ifeq ($(TARGET), aurix_tc4xx_csrm) - LSCRIPT_IN?=$(TC4_WB_DIR)/csrm/aurix_tc4xx_csrm.ld + $(call LSCRIPT_IN_DEFAULT,$(TC4_WB_DIR)/csrm/aurix_tc4xx_csrm.ld) else - LSCRIPT_IN?=$(TC4_WB_DIR)/aurix_tc4xx.ld + $(call LSCRIPT_IN_DEFAULT,$(TC4_WB_DIR)/aurix_tc4xx.ld) endif CFLAGS += \ -I$(TC4_LLD_DIR) \ diff --git a/hal/boards/stm32wb_nucleo/board.mk b/hal/boards/stm32wb_nucleo/board.mk index b3c88e627f..ce7244075f 100644 --- a/hal/boards/stm32wb_nucleo/board.mk +++ b/hal/boards/stm32wb_nucleo/board.mk @@ -1,5 +1,5 @@ ARCH_FLASH_OFFSET=0x08000000 -LSCRIPT_IN?=hal/stm32wb.ld +$(call LSCRIPT_IN_DEFAULT,hal/stm32wb.ld) CFLAGS+=-DWHAL_CFG_NO_TIMEOUT diff --git a/hal/boards/stm32wba55cg_nucleo/board.mk b/hal/boards/stm32wba55cg_nucleo/board.mk index 07e6f19f7a..b230202d12 100644 --- a/hal/boards/stm32wba55cg_nucleo/board.mk +++ b/hal/boards/stm32wba55cg_nucleo/board.mk @@ -1,5 +1,5 @@ ARCH_FLASH_OFFSET=0x08000000 -LSCRIPT_IN?=hal/stm32wba.ld +$(call LSCRIPT_IN_DEFAULT,hal/stm32wba.ld) CFLAGS+=-DWHAL_CFG_NO_TIMEOUT diff --git a/stage1/Makefile b/stage1/Makefile index 44dd602296..f2690c10d5 100644 --- a/stage1/Makefile +++ b/stage1/Makefile @@ -25,7 +25,7 @@ LSCRIPT_IN_USER:=$(LSCRIPT_IN) # boards use hal/x86_fsp_tgl_stage1.ld) set LSCRIPT_IN in arch.mk, so # only default when the per-target file (or its .ld.in template) exists. ifneq ($(wildcard ../hal/$(TARGET)_stage1.ld ../hal/$(TARGET)_stage1.ld.in),) -LSCRIPT_IN?=../hal/$(TARGET)_stage1.ld +$(call LSCRIPT_IN_DEFAULT,../hal/$(TARGET)_stage1.ld) endif LSCRIPT_FLAGS:= LD_START_GROUP:=-Wl,--start-group diff --git a/tools/config.mk b/tools/config.mk index 7245e8723d..b51fc07ce2 100644 --- a/tools/config.mk +++ b/tools/config.mk @@ -171,3 +171,9 @@ CONFIG_VARS:= ARCH TARGET SIGN HASH MCUXSDK MCUXPRESSO MCUXPRESSO_CPU MCUXPRESSO CERT_CHAIN_GEN_CA_HASH \ CERT_CHAIN_NAME_CONSTRAINTS \ ENCRYPT_CACHE + +# ?= treats a defined-but-empty value as already set, so a stale +# LSCRIPT_IN?= line in .config (or an exported empty env var) would skip +# every target default. Assign $1 to LSCRIPT_IN only when it is undefined +# or empty. +LSCRIPT_IN_DEFAULT=$(if $(strip $(LSCRIPT_IN)),,$(eval LSCRIPT_IN:=$1))