Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .vscode/c_cpp_properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"env": {
// TODO: This is a duplication of the configuration set in /docker/build.sh!
"TOOLS_DIR": "/opt",
"GCC_ARM_PATH": "gcc-arm-none-eabi-10.3-2021.10"
"GCC_ARM_PATH": "arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi"
},
"configurations": [
{
Expand Down
4 changes: 2 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
"continue"
],
// Only use armToolchainPath if your arm-none-eabi-gdb is not in your path (some GCC packages does not contain arm-none-eabi-gdb)
"armToolchainPath": "${workspaceRoot}/../gcc-arm-none-eabi-10.3-2021.10/bin",
"armToolchainPath": "${workspaceRoot}/../arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi/bin",
"svdFile": "${workspaceRoot}/nrf52.svd",
"configFiles": [
"interface/stlink.cfg",
Expand All @@ -68,7 +68,7 @@
"request": "launch",
"servertype": "external",
// FIXME: This is hardcoded. I have no idea how to use the values set in build.sh here
"gdbPath": "/opt/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-gdb",
"gdbPath": "/opt/arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-gdb",
// Connect to an already running OpenOCD instance
"gdbTarget": "host.docker.internal:3333",
"svdFile": "${workspaceRoot}/nrf52.svd",
Expand Down
4 changes: 2 additions & 2 deletions doc/buildAndProgram.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

To build this project, you'll need:

- A cross-compiler : [ARM-GCC (10.3-2021.10)](https://developer.arm.com/downloads/-/gnu-rm)
- A cross-compiler : [ARM-GCC 15.2-Rel1 from December 17, 2025 (AArch32 bare-metal target (arm-none-eabi))](https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads)
- The NRF52 SDK 15.3.0 : [nRF-SDK v15.3.0](https://nsscprodmedia.blob.core.windows.net/prod/software-and-other-downloads/sdks/nrf5/binaries/nrf5sdk153059ac345.zip)
- The Python 3 modules `cbor`, `intelhex`, `click` and `cryptography` modules for the `mcuboot` tool (see [requirements.txt](../tools/mcuboot/requirements.txt))
- To keep the system clean, you can install python modules into a python virtual environment (`venv`)
Expand Down Expand Up @@ -38,7 +38,7 @@ CMake configures the project according to variables you specify the command line

Variable | Description | Example|
----------|-------------|--------|
**ARM_NONE_EABI_TOOLCHAIN_PATH**|path to the toolchain directory|`-DARM_NONE_EABI_TOOLCHAIN_PATH=/home/jf/nrf52/gcc-arm-none-eabi-10.3-2021.10/`|
**ARM_NONE_EABI_TOOLCHAIN_PATH**|path to the toolchain directory|`-DARM_NONE_EABI_TOOLCHAIN_PATH=/home/jf/nrf52/arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi/`|
**NRF5_SDK_PATH**|path to the NRF52 SDK|`-DNRF5_SDK_PATH=/home/jf/nrf52/Pinetime/sdk`|
**CMAKE_BUILD_TYPE (\*)**| Build type (Release or Debug). Release is applied by default if this variable is not specified.|`-DCMAKE_BUILD_TYPE=Debug`
**BUILD_DFU (\*\*)**|Build DFU files while building (needs [adafruit-nrfutil](https://github.com/adafruit/Adafruit_nRF52_nrfutil)).|`-DBUILD_DFU=1`
Expand Down
2 changes: 1 addition & 1 deletion doc/buildWithVScode.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ To support as many setups as possible the VS Code configuration files expect the

Variable | Description | Example
----------|-------------|--------
**ARM_NONE_EABI_TOOLCHAIN_PATH**|path to the toolchain directory|`export ARM_NONE_EABI_TOOLCHAIN_PATH=/opt/gcc-arm-none-eabi-10.3-2021.10`
**ARM_NONE_EABI_TOOLCHAIN_PATH**|path to the toolchain directory|`export ARM_NONE_EABI_TOOLCHAIN_PATH=/opt/arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi`
**NRF5_SDK_PATH**|path to the NRF52 SDK|`export NRF5_SDK_PATH=/opt/nRF5_SDK_15.3.0_59ac345`

## VS Code Extensions
Expand Down
6 changes: 3 additions & 3 deletions docker/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export NPM_DIR="$BUILD_DIR/npm"
export npm_config_cache="${NPM_DIR}"

export BUILD_TYPE=${BUILD_TYPE:=Release}
export GCC_ARM_VER=${GCC_ARM_VER:="10.3-2021.10"}
export GCC_ARM_VER=${GCC_ARM_VER:="15.2.rel1"}
export NRF_SDK_VER=${NRF_SDK_VER:="nRF5_SDK_15.3.0_59ac345"}
# convert to lower case and remove _ and . character
# the download URL uses the SLUG, but the extracted folder is named like the original value
Expand All @@ -26,7 +26,7 @@ export NRF_SDK_VER_SLUG=${NRF_SDK_VER_SLUG//[_.]/}
MACHINE="$(uname -m)"
[ "$MACHINE" = "arm64" ] && MACHINE="aarch64"

export GCC_ARM_PATH="gcc-arm-none-eabi-$GCC_ARM_VER"
export GCC_ARM_PATH="arm-gnu-toolchain-$GCC_ARM_VER-$MACHINE-arm-none-eabi"

main() {
local target="$1"
Expand All @@ -50,7 +50,7 @@ main() {
}

GetGcc() {
wget -q https://developer.arm.com/-/media/Files/downloads/gnu-rm/$GCC_ARM_VER/$GCC_ARM_PATH-$MACHINE-linux.tar.bz2 -O - | tar -xj -C $TOOLS_DIR/
wget -q https://developer.arm.com/-/media/Files/downloads/gnu/$GCC_ARM_VER/binrel/$GCC_ARM_PATH.tar.xz -O - | tar -xJ -C $TOOLS_DIR/
if [ ! -d "$TOOLS_DIR/$GCC_ARM_PATH" ]; then
echo "missing GCC path: $TOOLS_DIR/$GCC_ARM_PATH"
return 1
Expand Down
12 changes: 6 additions & 6 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -930,7 +930,7 @@ target_compile_options(${EXECUTABLE_NAME} PUBLIC

set_target_properties(${EXECUTABLE_NAME} PROPERTIES
SUFFIX ".out"
LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} --specs=nosys.specs -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_FILE_NAME}.map"
LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_FILE_NAME}.map"
)

add_custom_command(TARGET ${EXECUTABLE_NAME}
Expand Down Expand Up @@ -965,7 +965,7 @@ target_compile_options(${EXECUTABLE_MCUBOOT_NAME} PUBLIC

set_target_properties(${EXECUTABLE_MCUBOOT_NAME} PROPERTIES
SUFFIX ".out"
LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT_MCUBOOT} --specs=nosys.specs -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_MCUBOOT_FILE_NAME}.map"
LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT_MCUBOOT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_MCUBOOT_FILE_NAME}.map"
)

add_custom_command(TARGET ${EXECUTABLE_MCUBOOT_NAME}
Expand Down Expand Up @@ -1008,7 +1008,7 @@ target_compile_options(${EXECUTABLE_RECOVERY_NAME} PUBLIC

set_target_properties(${EXECUTABLE_RECOVERY_NAME} PROPERTIES
SUFFIX ".out"
LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} --specs=nosys.specs -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_RECOVERY_FILE_NAME}.map"
LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_RECOVERY_FILE_NAME}.map"
)

add_custom_command(TARGET ${EXECUTABLE_RECOVERY_NAME}
Expand Down Expand Up @@ -1040,7 +1040,7 @@ target_compile_options(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PUBLIC

set_target_properties(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PROPERTIES
SUFFIX ".out"
LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT_MCUBOOT} --specs=nosys.specs -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_GRAPHICS_FILE_NAME}.map"
LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT_MCUBOOT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_GRAPHICS_FILE_NAME}.map"
)

add_custom_command(TARGET ${EXECUTABLE_RECOVERY_MCUBOOT_NAME}
Expand Down Expand Up @@ -1083,7 +1083,7 @@ add_dependencies(${EXECUTABLE_RECOVERYLOADER_NAME} ${EXECUTABLE_RECOVERY_MCUBOOT

set_target_properties(${EXECUTABLE_RECOVERYLOADER_NAME} PROPERTIES
SUFFIX ".out"
LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} --specs=nosys.specs -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_RECOVERYLOADER_FILE_NAME}.map"
LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_RECOVERYLOADER_FILE_NAME}.map"
)

add_custom_command(TARGET ${EXECUTABLE_RECOVERYLOADER_NAME}
Expand Down Expand Up @@ -1118,7 +1118,7 @@ add_dependencies(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} ${EXECUTABLE_RECOVERY

set_target_properties(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} PROPERTIES
SUFFIX ".out"
LINK_FLAGS "-mthumb -mabi=aapcs -std=gnu++98 -std=c99 -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT_MCUBOOT} --specs=nosys.specs -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.map"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just so I understand correctly. To get down size we exluded the stlib with the nosys.specs linker flag.

Why can we remove it now? I'd like to learn more

Copy link
Member Author

@mark9064 mark9064 Jan 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

libnosys provides stub implementations for system calls like read, write etc.

Since GCC11 these stubs emit warnings at the end of compilation which are noisy and annoying

From my research it seems like the best solution is to reimplement those calls as stubs ourselves, as we're sure that they're not being used. So since we're implementing those calls ourselves, we don't need libnosys anymore

LINK_FLAGS "-mthumb -mabi=aapcs -std=gnu++98 -std=c99 -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT_MCUBOOT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.map"
)

add_custom_command(TARGET ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME}
Expand Down
59 changes: 58 additions & 1 deletion src/stdlib.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include <stdlib.h>
#include <string.h>
#include <FreeRTOS.h>
#include <sys/stat.h>
#include <unistd.h>

// Override malloc() and free() to use the memory manager from FreeRTOS.
// According to the documentation of libc, we also need to override
Expand Down Expand Up @@ -29,7 +31,7 @@ void __wrap_free(void* ptr) {
}

void* calloc(size_t num, size_t size) {
void *ptr = malloc(num * size);
void* ptr = malloc(num * size);
if (ptr) {
memset(ptr, 0, num * size);
}
Expand All @@ -49,3 +51,58 @@ void* realloc(void* ptr, size_t newSize) {
void* __wrap_realloc(void* ptr, size_t newSize) {
return realloc(ptr, newSize);
}

// Implement functions required by libc as stubs
// These functions aren't linked into the final binary

__attribute__((error("stub"))) void _close(int fp) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The attributes might be a no-op as these are technically definitions rather than declarations. But they can't hurt I guess... the docs aren't super clear

__builtin_trap();
(void) fp;
}

__attribute__((error("stub"))) void _fstat(int fildes, struct stat* buf) {
__builtin_trap();
(void) fildes;
(void) buf;
}

__attribute__((error("stub"))) pid_t _getpid() {
__builtin_trap();
}

__attribute__((error("stub"))) int _isatty(int fd) {
__builtin_trap();
(void) fd;
}

__attribute__((error("stub"))) int _kill(pid_t pid, int sig) {
__builtin_trap();
(void) pid;
(void) sig;
}

__attribute__((error("stub"))) off_t _lseek(int fd, off_t offset, int whence) {
__builtin_trap();
(void) fd;
(void) offset;
(void) whence;
}

__attribute__((error("stub"))) ssize_t _read(int fd, void* buf, size_t count) {
__builtin_trap();
(void) fd;
(void) buf;
(void) count;
}

__attribute__((error("stub"))) ssize_t _write(int fd, void* buf, size_t count) {
__builtin_trap();
(void) fd;
(void) buf;
(void) count;
}

__attribute__((error("stub"))) void _exit(int status) {
__builtin_trap();
(void) status;
}