Add support for ARM Compiler for Embedded on stm32u5

pull/840/head
Mattia Moffa 2026-07-09 05:49:48 +02:00 committed by Daniele Lacamera
parent 6b8702dd63
commit 6da07ffc3d
13 changed files with 496 additions and 10 deletions

1
.gitignore vendored
View File

@ -133,6 +133,7 @@ tools/tpm/pcr_extend
tools/tpm/policy_create
tools/tpm/policy_sign
config/*.ld
config/*.sct
test-lib
lib-fs

View File

@ -27,7 +27,8 @@ SIGN_ALG=
OBJCOPY_FLAGS=
BIG_ENDIAN?=0
USE_CLANG?=0
ifeq ($(USE_CLANG),1)
USE_ARMCLANG?=0
ifneq ($(filter 1,$(USE_CLANG) $(USE_ARMCLANG)),)
USE_GCC?=0
else
USE_GCC?=1
@ -251,6 +252,39 @@ ifeq ($(ARCH),AURIX_TC3)
endif
endif
## ARM Compiler for Embedded (USE_ARMCLANG=1): rebuild the link options from
## scratch and switch the linker script to a scatter file, to support armlink.
ifeq ($(USE_ARMCLANG),1)
CFLAGS+=-D'END_STACK=Image$$$$ARM_LIB_STACK$$$$ZI$$$$Limit'
ifeq ($(WOLFCRYPT_TZ),1)
# Trap stubs for symbols referenced from wolfSSL code paths that are
# dead in this configuration: GNU ld garbage-collects the referencing
# sections, but armlink resolves all symbols before unused section
# elimination
OBJS+=tools/armclang/armclang_stubs.o
CFLAGS+=-DARMCLANG_STUBS_DEAD_REFS
ifeq ($(WOLFCRYPT_TZ_PKCS11),1)
CFLAGS+=-D'_flash_keyvault=Image$$$$KEYVAULT$$$$Base'
CFLAGS+=-D'_flash_keyvault_size=Image$$$$KEYVAULT$$$$ZI$$$$Length'
CFLAGS+=-D'_start_heap=Image$$$$RAM_HEAP$$$$Base'
CFLAGS+=-D'_heap_size=Image$$$$RAM_HEAP$$$$ZI$$$$Length'
# ARM libc malloc needs the C-library init that never runs (entry is
# isr_reset): provide a heap allocator instead
CFLAGS+=-DARMCLANG_STUBS_MALLOC
endif
endif
LDFLAGS:=$(ARMCLANG_LDFLAGS) --map --list=wolfboot.map
LSCRIPT:=config/target.sct
LSCRIPT_IN:=hal/$(TARGET).sct
LSCRIPT_FLAGS:=--scatter=$(LSCRIPT)
LD_START_GROUP:=
LD_END_GROUP:=
SECURE_LDFLAGS:=
ifeq ($(TZEN),1)
SECURE_LDFLAGS:=--import_cmse_lib_out=./src/wolfboot_tz_nsc.o
endif
endif
# Environment variables for sign tool
SIGN_ENV=IMAGE_HEADER_SIZE=$(IMAGE_HEADER_SIZE) \
WOLFBOOT_PARTITION_SIZE=$(WOLFBOOT_PARTITION_SIZE) \
@ -656,7 +690,7 @@ src/flash_otp_keystore.o: $(PRIVATE_KEY) src/flash_otp_keystore.c
keys: $(PRIVATE_KEY)
clean:
$(Q)rm -f src/*.o hal/*.o hal/spi/*.o test-app/*.o src/x86/*.o
$(Q)rm -f src/*.o hal/*.o hal/spi/*.o hal/uart/*.o test-app/*.o src/x86/*.o
$(Q)rm -f src/wolfboot_tz_nsc.o
$(Q)rm -f $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/*.o $(WOLFBOOT_LIB_WOLFTPM)/src/*.o $(WOLFBOOT_LIB_WOLFTPM)/src/fwtpm/*.o $(WOLFBOOT_LIB_WOLFTPM)/hal/*.o $(WOLFBOOT_LIB_WOLFTPM)/examples/pcr/*.o
$(Q)rm -f $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/Renesas/*.o

39
arch.mk
View File

@ -1719,6 +1719,45 @@ ifeq ($(USE_CLANG),1)
LDFLAGS+=-nostdlib
endif
ifeq ($(USE_ARMCLANG),1)
ifneq ($(ARCH),ARM)
$(error USE_ARMCLANG=1 is currently supported only for ARCH=ARM)
endif
ARMCLANG_PATH?=
CC=$(ARMCLANG_PATH)armclang --target=arm-arm-none-eabi
AS=$(CC)
LD=$(ARMCLANG_PATH)armlink
AR=$(ARMCLANG_PATH)armar
FROMELF?=$(ARMCLANG_PATH)fromelf
SIZE=$(FROMELF) -z
OBJCOPY=FROMELF="$(FROMELF)" $(WOLFBOOT_ROOT)/tools/armclang/objcopy.sh
CFLAGS+=-mfloat-abi=soft
CFLAGS+=-fno-unwind-tables -fno-asynchronous-unwind-tables
CFLAGS+=-Wno-unknown-attributes -Wno-error=unknown-attributes
# Map scatter files region names to GNU ld symbols used by wolfBoot code
CFLAGS+=-D'_start_text=Image$$$$ER_VECTORS$$$$Base'
CFLAGS+=-D'_stored_data=Load$$$$RW_RAM$$$$Base'
CFLAGS+=-D'_start_data=Image$$$$RW_RAM$$$$Base'
CFLAGS+=-D'_end_data=Image$$$$RW_RAM$$$$Limit'
CFLAGS+=-D'_start_bss=Image$$$$RW_RAM$$$$ZI$$$$Base'
CFLAGS+=-D'_end_bss=Image$$$$RW_RAM$$$$ZI$$$$Limit'
# Base armlink options shared by both images:
# - the unreferenced vector table needs an explicit --keep or unused
# section elimination removes it
# - RW data compression must be off: wolfBoot copies .data to RAM itself,
# word by word, and would copy the compressed image
# - Suppress L6314W (no section matches pattern) is suppressed: the scatter
# files list sections that are only present in some configurations (e.g.
# .ramcode)
# - --no_startup: wolfBoot has its own reset handler.
ARMCLANG_LDFLAGS=--cpu=Cortex-M33 --fpu=SoftVFP --entry=isr_reset \
--keep="*(.isr_vector)" --datacompressor=off --remove \
--no_startup --info=sizes,totals,unused --diag_suppress=6314
endif
ifeq ($(USE_GCC),1)
## Toolchain setup
CC=$(CROSS_COMPILE)gcc

View File

@ -20,13 +20,13 @@ RAM_CODE?=0
DUALBANK_SWAP?=0
WOLFBOOT_PARTITION_SIZE?=0x20000
WOLFBOOT_SECTOR_SIZE?=0x2000
WOLFBOOT_KEYVAULT_ADDRESS?=0x0C020000
WOLFBOOT_KEYVAULT_ADDRESS?=0x0C040000
WOLFBOOT_KEYVAULT_SIZE?=0x18000
WOLFBOOT_NSC_ADDRESS?=0x0C038000
WOLFBOOT_NSC_ADDRESS?=0x0C058000
WOLFBOOT_NSC_SIZE?=0x8000
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x08040000
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x08060000
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x08080000
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x08060000
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x08080000
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x080A0000
FLAGS_HOME=0
DISABLE_BACKUP=0
WOLFCRYPT_TZ=1

View File

@ -384,6 +384,25 @@ iterating over a range of flash sectors and erasing them one at a time. Setting
single HAL flash erase invocation with a larger erase length versus the iterative approach. On targets where multi-sector erases are more performant, this option can be used to dramatically speed up the
image swap procedure.
### Building with the ARM Compiler for Embedded (armclang)
wolfBoot can be built with the [ARM Compiler for Embedded](https://developer.arm.com/Tools%20and%20Software/Arm%20Compiler%20for%20Embedded)
(AC6: `armclang`, `armlink`, `armar`, `fromelf`), the toolchain used by Keil
MDK. No tool from the GNU or LLVM toolchains is required.
At the moment, the only supported and tested target is the STM32U5
(`config/examples/{stm32u5.config,stm32u5-wolfcrypt-tz.config}`).
To use this, either have the AC6 tools in your `PATH` or set `ARMCLANG_PATH` to
their location (including a trailing slash). Then build with USE_ARMCLANG=1:
```
cp config/examples/stm32u5.config .config
make USE_ARMCLANG=1
```
Alternatively, append `USE_ARMCLANG=1` and/or `ARMCLANG_PATH` to your `.config`.
### Using Mac OS/X
If you see 0xC3 0xBF (C3BF) repeated in your factory.bin then your OS is using Unicode characters.

View File

@ -1,6 +1,6 @@
MEMORY
{
FLASH (rx) : ORIGIN = @WOLFBOOT_ORIGIN@, LENGTH = @WOLFBOOT_KEYVAULT_ADDRESS@ - @ARCH_FLASH_OFFSET@
FLASH (rx) : ORIGIN = @WOLFBOOT_ORIGIN@, LENGTH = @WOLFBOOT_KEYVAULT_ADDRESS@ - @WOLFBOOT_ORIGIN@
RAM (rwx) : ORIGIN = 0x30000000, LENGTH = 0x00012000
RAM_HEAP (rw): ORIGIN = 0x30012000, LENGTH = 0xe000 /* 56KB Heap for wolfcrypt/PKCS11 */
FLASH_KEYVAULT(rw): ORIGIN = @WOLFBOOT_KEYVAULT_ADDRESS@, LENGTH = @WOLFBOOT_KEYVAULT_SIZE@

64
hal/stm32u5.sct 100644
View File

@ -0,0 +1,64 @@
#! armclang -E --target=arm-arm-none-eabi -mcpu=cortex-m33 -xc
; wolfBoot stm32u5 (TZEN=1) scatter file for armlink, equivalent to
; hal/stm32u5.ld. The @VAR@ placeholders are substituted by the Makefile
; (same rule as the GNU linker scripts), then armlink runs the armclang
; preprocessor on the result (#! line above).
;
; Region symbols consumed by the code (mapped from the GNU-ld symbol names
; via -D in arch.mk / Makefile):
; ER_VECTORS -> _start_text
; RW_RAM -> _stored_data (load), _start_data/_end_data,
; _start_bss/_end_bss
; ARM_LIB_STACK -> END_STACK (stack top, grows down from end of RAM)
; RAM_HEAP -> _start_heap/_heap_size (WOLFCRYPT_TZ PKCS11 heap)
; KEYVAULT -> _flash_keyvault/_flash_keyvault_size
#define WOLFBOOT_STACK_RESERVE 0x1000
LR_FLASH @WOLFBOOT_ORIGIN@ (@WOLFBOOT_KEYVAULT_ADDRESS@ - @WOLFBOOT_ORIGIN@)
{
ER_VECTORS @WOLFBOOT_ORIGIN@
{
*(.isr_vector, +FIRST)
}
ER_TEXT +0 ALIGN 8
{
.ANY(+RO)
}
RW_RAM 0x30000000 ALIGN 8 (0x00012000 - WOLFBOOT_STACK_RESERVE)
{
*(.ramcode)
.ANY(+RW)
.ANY(+ZI)
}
; Empty region only used to define the initial stack pointer; also lets
; armlink error out if RW_RAM grows into the stack reserve
ARM_LIB_STACK 0x30012000 EMPTY -WOLFBOOT_STACK_RESERVE
{
}
#if @WOLFBOOT_KEYVAULT_SIZE@ + 0
; 56KB heap for wolfcrypt/PKCS11
RAM_HEAP 0x30012000 EMPTY 0xe000
{
}
KEYVAULT @WOLFBOOT_KEYVAULT_ADDRESS@ EMPTY @WOLFBOOT_KEYVAULT_SIZE@
{
}
#endif
}
; CMSE secure gateway veneers, generated by armlink. Placed at NSC + 0x400
; like the GNU script (hal/stm32u5.ld reserves the first 0x400 bytes of the
; NSC region).
LR_NSC (@WOLFBOOT_NSC_ADDRESS@ + 0x400) (@WOLFBOOT_NSC_SIZE@ - 0x400)
{
ER_NSC (@WOLFBOOT_NSC_ADDRESS@ + 0x400)
{
*(Veneer$$CMSE)
}
}

View File

@ -39,7 +39,8 @@ WOLFHSM_SERVER_OBJS := \
$(WOLFBOOT_LIB_WOLFHSM)/src/wh_message_comm.o
USE_CLANG?=0
ifeq ($(USE_CLANG),1)
USE_ARMCLANG?=0
ifneq ($(filter 1,$(USE_CLANG) $(USE_ARMCLANG)),)
USE_GCC?=0
else
USE_GCC?=1
@ -56,6 +57,18 @@ ifeq ($(USE_CLANG),1)
endif
endif
ifeq ($(USE_ARMCLANG),1)
ifeq ($(USE_GCC),1)
$(error USE_ARMCLANG=1 is incompatible with USE_GCC=1; set USE_GCC=0)
endif
ifeq ($(USE_CLANG),1)
$(error USE_ARMCLANG=1 is incompatible with USE_CLANG=1)
endif
ifeq ($(ARMORED),1)
$(error USE_ARMCLANG=1 requires ARMORED=0)
endif
endif
# Support for Built-in ROT into OTP flash memory
ifeq ($(FLASH_OTP_KEYSTORE),1)
CFLAGS+=-D"FLASH_OTP_KEYSTORE"

View File

@ -0,0 +1,40 @@
#! armclang -E --target=arm-arm-none-eabi -mcpu=cortex-m33 -xc
; wolfBoot test-app stm32u5 (TZEN=1, non-secure app) scatter file for
; armlink, equivalent to test-app/ARM-stm32u5-ns.ld.
;
; Region symbols (mapped from the GNU-ld symbol names via -D in arch.mk and
; test-app/Makefile):
; ER_VECTORS -> _start_text
; RW_RAM -> _stored_data (load), _start_data/_end_data,
; _start_bss/_end_bss, _start_heap (= end of ZI)
; ARM_LIB_STACK -> _end_stack (stack top, grows down from end of RAM)
#define APP_RAM_BASE 0x20020000
#define APP_RAM_SIZE 0x00020000
#define APP_STACK_RESERVE 0x1000
LR_FLASH @WOLFBOOT_TEST_APP_ADDRESS@ @WOLFBOOT_TEST_APP_SIZE@
{
ER_VECTORS @WOLFBOOT_TEST_APP_ADDRESS@
{
*(.isr_vector, +FIRST)
}
ER_TEXT +0 ALIGN 8
{
.ANY(+RO)
}
RW_RAM APP_RAM_BASE ALIGN 8 (APP_RAM_SIZE - APP_STACK_RESERVE)
{
*(.ramcode)
.ANY(+RW)
.ANY(+ZI)
}
; Empty region only used to define the initial stack pointer; also lets
; armlink error out if RW_RAM grows into the stack reserve
ARM_LIB_STACK (APP_RAM_BASE + APP_RAM_SIZE) EMPTY -APP_STACK_RESERVE
{
}
}

View File

@ -1258,6 +1258,19 @@ ifeq ($(PPC64),1)
CFLAGS:=$(filter-out -DWOLFSSL_PPC32_ASM -DWOLFSSL_PPC32_ASM_INLINE,$(CFLAGS))
endif
## ARM Compiler for Embedded (USE_ARMCLANG=1): rebuild the link options from
## scratch, since the GNU-specific LDFLAGS accumulated above don't apply to
## armlink, and switch the linker script to a scatter file.
ifeq ($(USE_ARMCLANG),1)
CFLAGS+=-D'_end_stack=Image$$$$ARM_LIB_STACK$$$$ZI$$$$Limit'
CFLAGS+=-D'_start_heap=Image$$$$RW_RAM$$$$ZI$$$$Limit'
# GCC-only flags accumulated above
CFLAGS:=$(filter-out -Wstack-usage=% -gstabs,$(CFLAGS))
LSCRIPT:=../config/target-app.sct
LSCRIPT_TEMPLATE:=ARM-$(TARGET)-ns.sct
LDFLAGS:=$(ARMCLANG_LDFLAGS) --map --list=image.map --scatter=$(LSCRIPT)
endif
# Capture final flags for locally built wolfSSL objects.
WOLFSSL_CFLAGS:=$(CFLAGS)
WOLFTPM_CFLAGS:=$(CFLAGS)

View File

@ -27,7 +27,8 @@
#include <target.h>
#include <time.h>
int clock_gettime (clockid_t clock_id, struct timespec *tp);
struct timespec;
int clock_gettime (unsigned long clock_id, struct timespec *tp);
#include "wolfboot/wc_secure.h"
#define WOLFCRYPT_ONLY

View File

@ -0,0 +1,182 @@
/* armclang_stubs.c
*
* C library glue for building wolfBoot with the ARM Compiler for Embedded
* (USE_ARMCLANG=1). Only used by the WOLFCRYPT_TZ/PKCS11 configurations.
*
* - ARMCLANG_STUBS_MALLOC (secure image): heap allocator over the RAM_HEAP
* scatter region. The GNU build uses newlib-nano's malloc on top of the
* _sbrk hook in src/pkcs11_store.c; the ARM C library malloc cannot be
* used instead because it requires the C library runtime initialization
* (__rt_entry), which never runs since wolfBoot enters at isr_reset.
*
* - ARMCLANG_STUBS_DEAD_REFS: trap stubs for symbols that are only
* referenced from sections that GNU ld garbage-collects; armlink needs
* the definitions to exist before its own unused section elimination.
*
* This file is part of wolfBoot.
*
* wolfBoot is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfBoot is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifdef ARMCLANG_STUBS_MALLOC
#include <stddef.h>
#include <stdint.h>
#include <string.h>
/* Renamed to the RAM_HEAP region symbols by the -D options in the Makefile */
extern unsigned int _start_heap;
extern unsigned int _heap_size;
/* First-fit allocator with address-ordered free list and coalescing.
* Block header keeps the total block size (header included); blocks and
* payloads are 8-byte aligned. */
struct heap_blk {
size_t size;
struct heap_blk *next;
};
#define HEAP_ALIGN(sz) (((sz) + 7U) & ~(size_t)7U)
#define HEAP_MIN_SPLIT (sizeof(struct heap_blk) + 8U)
static struct heap_blk *heap_free_list;
static int heap_initialized;
static void heap_init(void)
{
heap_free_list = (struct heap_blk *)HEAP_ALIGN((uintptr_t)&_start_heap);
heap_free_list->size = (size_t)((uintptr_t)&_start_heap
+ (uintptr_t)&_heap_size - (uintptr_t)heap_free_list)
& ~(size_t)7U;
heap_free_list->next = NULL;
heap_initialized = 1;
}
void *malloc(size_t size)
{
struct heap_blk *blk, **prev;
if (!heap_initialized)
heap_init();
if (size == 0)
return NULL;
size = HEAP_ALIGN(size) + sizeof(struct heap_blk);
for (prev = &heap_free_list; (blk = *prev) != NULL; prev = &blk->next) {
if (blk->size < size)
continue;
if (blk->size - size >= HEAP_MIN_SPLIT) {
struct heap_blk *rest = (struct heap_blk *)((uint8_t *)blk + size);
rest->size = blk->size - size;
rest->next = blk->next;
blk->size = size;
*prev = rest;
} else {
*prev = blk->next;
}
blk->next = NULL;
return (uint8_t *)blk + sizeof(struct heap_blk);
}
return NULL;
}
void free(void *ptr)
{
struct heap_blk *blk, *cur, **prev;
if (ptr == NULL)
return;
blk = (struct heap_blk *)((uint8_t *)ptr - sizeof(struct heap_blk));
/* Keep the free list sorted by address */
for (prev = &heap_free_list; (cur = *prev) != NULL; prev = &cur->next) {
if (cur > blk)
break;
}
blk->next = cur;
*prev = blk;
/* Coalesce with the next and previous blocks when adjacent */
if (cur != NULL && (uint8_t *)blk + blk->size == (uint8_t *)cur) {
blk->size += cur->size;
blk->next = cur->next;
}
if (prev != &heap_free_list) {
struct heap_blk *before = (struct heap_blk *)((uint8_t *)prev
- offsetof(struct heap_blk, next));
if ((uint8_t *)before + before->size == (uint8_t *)blk) {
before->size += blk->size;
before->next = blk->next;
}
}
}
void *calloc(size_t nmemb, size_t size)
{
void *ptr;
size_t total = nmemb * size;
if (size != 0 && total / size != nmemb)
return NULL;
ptr = malloc(total);
if (ptr != NULL)
memset(ptr, 0, total);
return ptr;
}
void *realloc(void *ptr, size_t size)
{
void *new_ptr;
struct heap_blk *blk;
size_t old_payload;
if (ptr == NULL)
return malloc(size);
if (size == 0) {
free(ptr);
return NULL;
}
blk = (struct heap_blk *)((uint8_t *)ptr - sizeof(struct heap_blk));
old_payload = blk->size - sizeof(struct heap_blk);
if (old_payload >= size)
return ptr;
new_ptr = malloc(size);
if (new_ptr != NULL) {
memcpy(new_ptr, ptr, old_payload);
free(ptr);
}
return new_ptr;
}
#endif /* ARMCLANG_STUBS_MALLOC */
#ifdef ARMCLANG_STUBS_DEAD_REFS
/* Trap stubs for symbols that are referenced only from wolfSSL sections
* that are dead in the wolfBoot configurations (proven by the GNU builds,
* where the references would be a link error if the referencing sections
* survived garbage collection). armlink resolves all symbols before its
* unused section elimination, so the references need a definition; both
* the stubs and the referencing sections are eliminated from the image.
* The infinite loop makes any unexpected live call fail loudly. */
#define ARMCLANG_DEAD_REF_STUB(name) \
void name(void); \
void name(void) { while (1) ; }
ARMCLANG_DEAD_REF_STUB(wc_CryptKey)
ARMCLANG_DEAD_REF_STUB(Base64_Encode)
ARMCLANG_DEAD_REF_STUB(wc_PKCS12_PBKDF)
#endif /* ARMCLANG_STUBS_DEAD_REFS */

View File

@ -0,0 +1,80 @@
#!/bin/sh
# GNU objcopy command-line adapter over ARM fromelf, used when building with
# the ARM Compiler for Embedded (USE_ARMCLANG=1) so that the .bin/.hex/.srec
# Makefile recipes can be shared with the GNU toolchains.
#
# Only the invocation shapes used by the wolfBoot Makefiles are supported:
# objcopy [--gap-fill <byte>] -O binary <in.elf> <out.bin>
# objcopy -O ihex <in.elf> <out.hex>
# objcopy -O srec <in.elf> <out.srec>
#
# The fromelf executable is taken from the FROMELF environment variable
# (default: fromelf).
set -e
FROMELF="${FROMELF:-fromelf}"
GAP_FILL=
FORMAT=
INPUT=
OUTPUT=
while [ $# -gt 0 ]; do
case "$1" in
--gap-fill)
GAP_FILL="$2"
shift 2
;;
--gap-fill=*)
GAP_FILL="${1#*=}"
shift
;;
-O)
FORMAT="$2"
shift 2
;;
-*)
echo "$0: unsupported objcopy option: $1" >&2
exit 1
;;
*)
if [ -z "$INPUT" ]; then
INPUT="$1"
elif [ -z "$OUTPUT" ]; then
OUTPUT="$1"
else
echo "$0: too many arguments: $1" >&2
exit 1
fi
shift
;;
esac
done
if [ -z "$FORMAT" ] || [ -z "$INPUT" ] || [ -z "$OUTPUT" ]; then
echo "usage: $0 [--gap-fill <byte>] -O binary|ihex|srec <in.elf> <out>" >&2
exit 1
fi
case "$FORMAT" in
binary)
# --bincombined merges all load regions into a single image, padding
# the gaps between them (GNU objcopy -O binary behavior)
set -- --bincombined
if [ -n "$GAP_FILL" ]; then
set -- "$@" "--bincombined_padding=1,$GAP_FILL"
fi
;;
ihex)
set -- --i32combined
;;
srec)
set -- --m32combined
;;
*)
echo "$0: unsupported output format: $FORMAT" >&2
exit 1
;;
esac
exec "$FROMELF" "$@" --output="$OUTPUT" "$INPUT"