diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 42f15f68ac..2a208cbf0c 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -77,6 +77,17 @@ jobs: run: | sudo apt-get install -y gcc-arm-none-eabi gcc-aarch64-linux-gnu gcc-powerpc-linux-gnu gnu-efi + - name: Install Clang + if: | + inputs.config-file == './config/examples/stm32h7.config' || + inputs.config-file == './config/examples/stm32h7-octospi.config' || + inputs.config-file == './config/examples/stm32u5.config' || + inputs.config-file == './config/examples/stm32u5-wolfcrypt-tz.config' || + inputs.config-file == './config/examples/stm32u5-nonsecure-dualbank.config' || + inputs.config-file == 'config/examples/stm32n567.config' + run: | + sudo apt-get install -y clang + - name: make clean run: | make distclean @@ -92,3 +103,17 @@ jobs: - name: Build wolfboot run: | make ${{inputs.make-args}} + + - name: Rebuild wolfboot with Clang + if: | + inputs.config-file == './config/examples/stm32h7.config' || + inputs.config-file == './config/examples/stm32h7-octospi.config' || + inputs.config-file == './config/examples/stm32u5.config' || + inputs.config-file == './config/examples/stm32u5-wolfcrypt-tz.config' || + inputs.config-file == './config/examples/stm32u5-nonsecure-dualbank.config' || + inputs.config-file == 'config/examples/stm32n567.config' + run: | + make distclean + cp ${{inputs.config-file}} .config + make -C tools/keytools && make -C tools/bin-assemble + make USE_CLANG=1 USE_GCC=0 ${{inputs.make-args}} diff --git a/Makefile b/Makefile index 321322a9fe..87565445d9 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,7 @@ DEBUG_UART?=0 LIBS= SIGN_ALG= OBJCOPY_FLAGS= +OBJCOPY_BIN_FLAGS= BIG_ENDIAN?=0 USE_CLANG?=0 ifeq ($(USE_CLANG),1) @@ -196,6 +197,12 @@ ifeq ($(USE_GCC_HEADLESS),1) LSCRIPT_FLAGS+=-T $(LSCRIPT) OBJCOPY_FLAGS+=--gap-fill $(FILL_BYTE) endif + +ifeq ($(USE_CLANG),1) + ifeq ($(ARCH),ARM) + OBJCOPY_BIN_FLAGS+=$(CLANG_ARM_OBJCOPY_FLASH_FLAGS_BOOT) + endif +endif ifeq ($(TARGET),ti_hercules) LSCRIPT_FLAGS+=--run_linker $(LSCRIPT) endif @@ -322,7 +329,7 @@ wolfboot.efi: wolfboot.elf wolfboot.bin: wolfboot.elf @echo "\t[BIN] $@" - $(Q)$(OBJCOPY) $(OBJCOPY_FLAGS) -O binary $^ $@ + $(Q)$(OBJCOPY) $(OBJCOPY_FLAGS) $(OBJCOPY_BIN_FLAGS) -O binary $^ $@ @echo @echo "\t[SIZE]" $(Q)$(SIZE) wolfboot.elf diff --git a/arch.mk b/arch.mk index a9de6d9e0f..96ad331542 100644 --- a/arch.mk +++ b/arch.mk @@ -1282,7 +1282,9 @@ ifeq ($(USE_CLANG),1) CLANG_NEWLIB_INCLUDE?=$(abspath $(dir $(CLANG_LIBC_A))/../include) CC=$(CLANG_DRIVER) - LD=$(CLANG_DRIVER) + # Keep clang for compilation, but use the GNU linker driver so linker-script + # LMAs for RAM sections are preserved and objcopy does not emit sparse images. + LD=$(CLANG_GCC_NAME) AS=$(CLANG_DRIVER) AR=$(CROSS_COMPILE)ar OBJCOPY?=$(CROSS_COMPILE)objcopy @@ -1290,7 +1292,15 @@ ifeq ($(USE_CLANG),1) CFLAGS+=-isystem $(CLANG_NEWLIB_INCLUDE) CFLAGS+=-DWOLFSSL_NO_ATOMIC -DWOLFSSL_NO_ATOMICS - LDFLAGS+=-nostdlib + CFLAGS+=-Wno-unknown-attributes -Wno-error=unknown-attributes + CFLAGS+=-fno-unwind-tables -fno-asynchronous-unwind-tables + LSCRIPT_FLAGS+=-T $(abspath $(WOLFBOOT_ROOT)/hal/clang-discard.ld) + # Keep Clang-specific raw-image section selection in one place. Both the + # bootloader and test-app need flash-backed sections only, but the bootloader + # has a few extra output sections that must be preserved. + CLANG_ARM_OBJCOPY_FLASH_FLAGS_BASE:=-j .text -j .edidx + CLANG_ARM_OBJCOPY_FLASH_FLAGS_BOOT:=$(CLANG_ARM_OBJCOPY_FLASH_FLAGS_BASE) -j .ramcode -j .keystore -j .gnu.sgstubs + CLANG_ARM_OBJCOPY_FLASH_FLAGS_APP:=$(CLANG_ARM_OBJCOPY_FLASH_FLAGS_BASE) endif ifeq ($(USE_GCC),1) diff --git a/hal/clang-discard.ld b/hal/clang-discard.ld new file mode 100644 index 0000000000..1217dddbc5 --- /dev/null +++ b/hal/clang-discard.ld @@ -0,0 +1,14 @@ +SECTIONS +{ + /DISCARD/ : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.eh_frame* .gcc_except_table*) + *(.preinit_array*) + *(.init_array*) + *(.fini_array*) + *(.ctors*) + *(.dtors*) + *(.jcr*) + } +} diff --git a/hal/stm32l4.ld b/hal/stm32l4.ld index 822f01174d..933985c17e 100644 --- a/hal/stm32l4.ld +++ b/hal/stm32l4.ld @@ -15,6 +15,7 @@ SECTIONS . = ALIGN(4); _end_text = .; } > FLASH + .edidx : { . = ALIGN(4); diff --git a/options.mk b/options.mk index 814e1d9987..89a66ca225 100644 --- a/options.mk +++ b/options.mk @@ -12,6 +12,9 @@ ifeq ($(USE_CLANG),1) ifeq ($(USE_GCC),1) $(error USE_CLANG=1 is incompatible with USE_GCC=1; set USE_GCC=0) endif + ifeq ($(ARMORED),1) + $(error USE_CLANG=1 requires ARMORED=0) + endif endif # Support for Built-in ROT into OTP flash memory diff --git a/test-app/Makefile b/test-app/Makefile index 1d0b1e5ad5..f45408204b 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -88,7 +88,7 @@ endif include ../arch.mk ifeq ($(USE_CLANG),1) - APP_OBJS+=../src/string.o + APP_NEEDS_STRING:=1 endif # Optional alias for clearer TZ PSA selection in app builds. @@ -102,9 +102,21 @@ LDFLAGS+=-T $(LSCRIPT) -Wl,-gc-sections -Wl,-Map=image.map -nostartfiles # Setup default objcopy flags OBJCOPY_FLAGS+=--gap-fill $(FILL_BYTE) +OBJCOPY_IMAGE_FLAGS:= + +ifeq ($(USE_CLANG),1) + # Clang-built ARM ELFs can keep RAM sections as loadable segments, and raw + # objcopy output then expands the flash-to-RAM gap into a huge sparse image. + # The app image only needs the flash-backed output sections. + OBJCOPY_IMAGE_FLAGS+=$(CLANG_ARM_OBJCOPY_FLASH_FLAGS_APP) +endif ifeq ($(DEBUG_UART),1) CFLAGS+=-DDEBUG_UART + APP_NEEDS_STRING:=1 +endif + +ifeq ($(APP_NEEDS_STRING),1) APP_OBJS+=../src/string.o endif @@ -288,7 +300,10 @@ ifeq ($(TZEN),1) endif endif endif - CFLAGS+=-DWOLFBOOT_SECURE_CALLS -Wstack-usage=19184 + CFLAGS+=-DWOLFBOOT_SECURE_CALLS + ifneq ($(USE_CLANG),1) + CFLAGS+=-Wstack-usage=19184 + endif LDFLAGS+=--specs=nosys.specs -u _printf_float endif ifeq ($(WOLFCRYPT_TZ_PSA),1) @@ -899,15 +914,15 @@ delta-extra-data:LDFLAGS=-Wl,-Map=image.map image.bin: image.elf @echo "\t[BIN] $@" - $(Q)$(OBJCOPY) $(OBJCOPY_FLAGS) -O binary $^ $@ + $(Q)$(OBJCOPY) $(OBJCOPY_FLAGS) $(OBJCOPY_IMAGE_FLAGS) -O binary $^ $@ image.hex: image.elf @echo "\t[HEX] $@" - $(Q)$(OBJCOPY) $(OBJCOPY_FLAGS) -O ihex $^ $@ + $(Q)$(OBJCOPY) $(OBJCOPY_FLAGS) $(OBJCOPY_IMAGE_FLAGS) -O ihex $^ $@ image.srec: image.elf @echo "\t[SREC] $@" - $(Q)$(OBJCOPY) $(OBJCOPY_FLAGS) -O srec $^ $@ + $(Q)$(OBJCOPY) $(OBJCOPY_FLAGS) $(OBJCOPY_IMAGE_FLAGS) -O srec $^ $@ APP_OBJS := $(patsubst $(WOLFBOOT_LIB_WOLFSSL)/%, \ $(WOLFSSL_LOCAL_OBJDIR)/%, $(APP_OBJS)) @@ -917,7 +932,7 @@ ifeq ($(ELF_FLASH_SCATTER),1) SQUASHELF_TOOL = ../tools/squashelf/squashelf image-orig.elf: $(APP_OBJS) $(LSCRIPT) @echo "\t[LD] $@" - $(Q)$(LD) $(LDFLAGS) $(APP_OBJS) $(LIBS) $(OUTPUT_FLAG) $@ + $(Q)$(LD) $(LDFLAGS) $(LSCRIPT_FLAGS) $(APP_OBJS) $(LIBS) $(OUTPUT_FLAG) $@ image.elf: image-orig.elf @echo "\t[SQUASHELF] $@" @@ -926,7 +941,7 @@ else # Default behavior when ELF_FLASH_SCATTER is not set image.elf: $(APP_OBJS) $(LSCRIPT) @echo "\t[LD] $@" - $(Q)$(LD) $(LDFLAGS) $(APP_OBJS) $(LIBS) $(OUTPUT_FLAG) $@ + $(Q)$(LD) $(LDFLAGS) $(LSCRIPT_FLAGS) $(APP_OBJS) $(LIBS) $(OUTPUT_FLAG) $@ endif standalone: image.bin