Skip to content
Merged
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
3 changes: 3 additions & 0 deletions cmake/preload/toolchains/util/pico_arm_gcc_common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
# wrongly emit .fpu softvfp regardless of any other options! go figure!!!
if (PICO_HARD_FLOAT_ABI)
set(PICO_COMMON_LANG_FLAGS "${PICO_COMMON_LANG_FLAGS} -mfloat-abi=hard")
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL cortex-m0plus)
# older GCC dont accept softfp for M0+ and end up picking wrong libraries in multilib
set(PICO_COMMON_LANG_FLAGS "${PICO_COMMON_LANG_FLAGS} -mfloat-abi=soft")
else()
set(PICO_COMMON_LANG_FLAGS "${PICO_COMMON_LANG_FLAGS} -mfloat-abi=softfp")
endif()
Expand Down
1 change: 1 addition & 0 deletions src/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ alias(
"//src/common/hardware_claim:__pkg__",
"//src/common/pico_base_headers:__pkg__",
"//src/common/pico_binary_info:__pkg__",
"//src/rp2_common/pico_cxx_options:__pkg__",
# These libraries sometimes need the host version even though they live
# in rp2_common.
"//src/rp2_common/boot_bootrom_headers:__pkg__",
Expand Down
1 change: 1 addition & 0 deletions src/common/pico_base_headers/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ cc_library(
"//src/rp2_common/hardware_watchdog:__pkg__",
"//src/rp2_common/hardware_xosc:__pkg__",
"//src/rp2_common/pico_crt0:__pkg__",
"//src/rp2_common/pico_cxx_options:__pkg__",
"//src/rp2_common/pico_platform_common:__pkg__",
"//src/rp2_common/pico_printf:__pkg__",
"//src/rp2_common/pico_runtime:__pkg__",
Expand Down
21 changes: 18 additions & 3 deletions src/rp2_common/pico_clib_interface/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,16 @@ cc_library(

cc_library(
name = "llvm_libc_interface_link",
srcs = ["llvm_libc_interface.c"],
srcs = [
"cxa_guard.c",
"llvm_libc_interface.c",
"llvm_libc_interface_cpp.cpp",
],
implementation_deps = [
":llvm_libc_interface",
"//src/rp2_common/pico_atomic",
"//src/rp2_common/pico_bootrom",
"//src/rp2_common/pico_cxx_options",
"//src/rp2_common/pico_runtime_init",
"//src/rp2_common/pico_stdio:pico_stdio_headers",
],
Expand All @@ -85,10 +90,15 @@ alias(

cc_library(
name = "newlib_interface_link",
srcs = ["newlib_interface.c"],
srcs = [
"cxa_guard.c",
"newlib_interface.c",
],
implementation_deps = [
"//src/common/pico_time",
"//src/rp2_common/pico_atomic",
"//src/rp2_common/pico_bootrom",
"//src/rp2_common/pico_cxx_options",
"//src/rp2_common/pico_printf",
"//src/rp2_common/pico_runtime_init",
"//src/rp2_common/pico_stdio:pico_stdio_headers",
Expand All @@ -107,10 +117,15 @@ alias(

cc_library(
name = "picolibc_interface_link",
srcs = ["picolibc_interface.c"],
srcs = [
"cxa_guard.c",
"picolibc_interface.c",
],
implementation_deps = [
"//src/common/pico_time",
"//src/rp2_common/pico_atomic",
"//src/rp2_common/pico_bootrom",
"//src/rp2_common/pico_cxx_options",
"//src/rp2_common/pico_printf",
"//src/rp2_common/pico_runtime_init",
"//src/rp2_common/pico_stdio:pico_stdio_headers",
Expand Down
9 changes: 7 additions & 2 deletions src/rp2_common/pico_clib_interface/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,20 @@ if (NOT TARGET pico_clib_interface)

target_sources(pico_newlib_interface INTERFACE
${CMAKE_CURRENT_LIST_DIR}/newlib_interface.c
${CMAKE_CURRENT_LIST_DIR}/cxa_guard.c
)
pico_mirrored_target_link_libraries(pico_newlib_interface INTERFACE pico_stdio pico_atomic pico_cxx_options)

# ---- picolibc ----

pico_add_library(pico_picolibc_interface)

target_sources(pico_picolibc_interface INTERFACE
${CMAKE_CURRENT_LIST_DIR}/picolibc_interface.c
${CMAKE_CURRENT_LIST_DIR}/cxa_guard.c
)

pico_mirrored_target_link_libraries(pico_picolibc_interface INTERFACE pico_stdio pico_atomic pico_cxx_options)
# replacing the functions is fine it seems
#target_compile_definitions(pico_picolibc_interface INTERFACE
# PICO_STDIO_SHORT_CIRCUIT_CLIB_FUNCS=0
Expand All @@ -26,13 +30,14 @@ if (NOT TARGET pico_clib_interface)

target_sources(pico_llvm_libc_interface INTERFACE
${CMAKE_CURRENT_LIST_DIR}/llvm_libc_interface.c
${CMAKE_CURRENT_LIST_DIR}/llvm_libc_interface_cpp.cpp
${CMAKE_CURRENT_LIST_DIR}/cxa_guard.c
)

target_include_directories(pico_llvm_libc_interface SYSTEM INTERFACE
${CMAKE_CURRENT_LIST_DIR}/include/llvm_libc
)
target_link_libraries(pico_llvm_libc_interface INTERFACE pico_atomic)
pico_mirrored_target_link_libraries(pico_llvm_libc_interface INTERFACE pico_stdio)
pico_mirrored_target_link_libraries(pico_llvm_libc_interface INTERFACE pico_stdio pico_atomic pico_cxx_options)

if (NOT PICO_CLIB)
# PICO_CMAKE_CONFIG: PICO_CLIB, The C library to use e.g. newlib/picolibc/llvm_libc, type=string, default=based on PICO_COMPILER, group=build, docref=cmake-toolchain-config
Expand Down
92 changes: 92 additions & 0 deletions src/rp2_common/pico_clib_interface/cxa_guard.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright (c) 2026 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#include "pico/cxx_options.h"

#define CXA_GUARD_UNINITIALIZED 0
#define CXA_GUARD_INITIALIZED 1
#define CXA_GUARD_INITIALIZING 2

#if PICO_CXX_THREAD_SAFE_STATIC_INIT
#include <stdatomic.h>
#include <hardware/sync.h>

// newer LLVM complains on RP2040 because there are no atomics (it doesn't know we have pico_atomic)
Clang_Pragma("clang diagnostic push")
Clang_Pragma("clang diagnostic ignored \"-Watomic-alignment\"")

int __cxa_guard_acquire(int32_t *guard_object) {
// Cast the raw pointer to a standard C11 atomic pointer type
_Atomic int32_t *atomic_guard = (_Atomic int32_t *)guard_object;

while (true) {
// read current state
int32_t current = atomic_load_explicit(atomic_guard, memory_order_acquire);

// bit 0 set -> Initialization is complete, skip constructor
if (current & CXA_GUARD_INITIALIZED) {
return 0;
}

// bit 1 set -> another thread/core is initializing it, so sleep
if (current & CXA_GUARD_INITIALIZING) {
__wfe();
continue;
}

// attempt to atomically claim the lock by moving state from CXA_GUARD_UNINITIALIZED to CXA_GUARD_INITIALIZING.
int32_t expected = CXA_GUARD_UNINITIALIZED;
if (atomic_compare_exchange_weak_explicit(atomic_guard, &expected, CXA_GUARD_INITIALIZING,
memory_order_release,
memory_order_relaxed)) {
return 1; // Success! This core must execute the constructor
}
}
}

void __cxa_guard_release(int32_t *guard_object) {
_Atomic int32_t *atomic_guard = (_Atomic int32_t *)guard_object;

// set Bit 0 (done) and clear Bit 1 (unlocked)
atomic_store_explicit(atomic_guard, CXA_GUARD_INITIALIZED, memory_order_release);

// wake up any waiters
__sev();
}

void __cxa_guard_abort(int32_t *guard_object) {
_Atomic int32_t *atomic_guard = (_Atomic int32_t *)guard_object;

// reset back to uninitialized state
atomic_store_explicit(atomic_guard, CXA_GUARD_UNINITIALIZED, memory_order_release);

// wake up any waiters
__sev();
}

Clang_Pragma("clang diagnostic pop")
#else

int __cxa_guard_acquire(volatile int32_t *guard_object) {
int32_t guard_val = *guard_object;
if (guard_val == CXA_GUARD_INITIALIZED) {
return 0;
}
if (guard_val & CXA_GUARD_INITIALIZING) {
panic("recursive CXX initializer");
}
*guard_object = CXA_GUARD_INITIALIZING;
return 1;
}

void __cxa_guard_release(volatile int32_t *guard_object) {
*guard_object = CXA_GUARD_INITIALIZED;
}

void __cxa_guard_abort(volatile int32_t *guard_object) {
*guard_object = CXA_GUARD_UNINITIALIZED;
}
#endif
11 changes: 7 additions & 4 deletions src/rp2_common/pico_clib_interface/llvm_libc_interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include <stddef.h>
#include <sys/time.h>
#include <time.h>

#include <llvm-libc-types/ssize_t.h>

#include "pico/runtime_init.h"
Expand Down Expand Up @@ -79,7 +78,12 @@ bool __llvm_libc_timespec_get_utc(struct timespec *ts) {
return true;
}

void __cxa_finalize(__unused void *dso) {}
__weak void __cxa_finalize(__unused void *dso) {}

__weak int atexit(void (*function)(void)) {
(void)function;
return 0;
}

void __attribute__((noreturn)) __llvm_libc_exit(__unused int status) {
#if PICO_ENTER_USB_BOOT_ON_EXIT
Expand Down Expand Up @@ -120,5 +124,4 @@ void runtime_init(void) {
for (void (**p)(void) = &__init_array_start; p < &__init_array_end; ++p) {
(*p)();
}
}

}
13 changes: 13 additions & 0 deletions src/rp2_common/pico_clib_interface/llvm_libc_interface_cpp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include <version>
#include <cstdarg>

#include "pico.h"

namespace std {
inline namespace __2 {
[[__noreturn__]] _LIBCPP_AVAILABILITY_VERBOSE_ABORT _LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_ATTRIBUTE_FORMAT(
__printf__, 1, 2) void __libcpp_verbose_abort(const char* __format, ...) _NOEXCEPT {
panic("c++ abort: %s", __format);
}
}
}
3 changes: 3 additions & 0 deletions src/rp2_common/pico_clib_interface/newlib_interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ void __attribute__((noreturn)) __weak _exit(__unused int status) {
#endif
}

void __weak _fini(void) {
}

__weak void *_sbrk(int incr) {
extern char end; /* Set by linker. */
static char *heap_end;
Expand Down
9 changes: 9 additions & 0 deletions src/rp2_common/pico_clib_interface/picolibc_interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ void __attribute__((noreturn)) __weak _exit(__unused int status) {
#endif
}

int __weak getpid(void) {
return 0;
}

int __weak kill(__unused int pid, __unused int sig) {
__breakpoint();
return -1;
}

static int64_t epoch_time_us_since_boot;

__weak int gettimeofday (struct timeval *__restrict tv, __unused void *__restrict tz) {
Expand Down
7 changes: 6 additions & 1 deletion src/rp2_common/pico_cxx_options/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,14 @@ pico_sdk_define(
cc_library(
name = "pico_cxx_options",
srcs = ["new_delete.cpp"],
hdrs = [
"include/pico/cxx_options.h",
],
includes = ["include"],
target_compatible_with = compatible_with_rp2(),
deps = [
":PICO_CXX_ENABLE_EXCEPTIONS",
"//src/rp2_common:pico_platform",
"//src:pico_platform_internal",
"//src/common/pico_base_headers",
],
)
1 change: 1 addition & 0 deletions src/rp2_common/pico_cxx_options/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ if (NOT TARGET pico_cxx_options)
target_sources(pico_cxx_options INTERFACE
${CMAKE_CURRENT_LIST_DIR}/new_delete.cpp
)
target_include_directories(pico_cxx_options SYSTEM INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)

# PICO_CMAKE_CONFIG: PICO_CXX_ENABLE_EXCEPTIONS, Enable CXX exception handling, type=bool, default=0, group=pico_cxx_options
# PICO_BUILD_DEFINE: PICO_CXX_ENABLE_EXCEPTIONS, value of CMake var PICO_CXX_ENABLE_EXCEPTIONS, type=string, default=0, group=pico_cxx_options
Expand Down
21 changes: 21 additions & 0 deletions src/rp2_common/pico_cxx_options/include/pico/cxx_options.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2026 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#ifndef _PICO_CXX_OPTIONS_H
#define _PICO_CXX_OPTIONS_H

#include "pico.h"

// PICO_CONFIG: PICO_CXX_DISABLE_ALLOCATION_OVERRIDES, Disable SDK overrides of C++ new/delete operators, type=bool, default=0, advanced=true, group=pico_cxx_options

// PICO_CONFIG: PICO_CXX_THREAD_SAFE_STATIC_INIT, Enable thread/IRQ safe locks for C++ static initializers, type=bool, default=1 when using pico_multicore, advanced=true, group=pico_cxx_options
#ifndef PICO_CXX_THREAD_SAFE_STATIC_INIT
#define PICO_CXX_THREAD_SAFE_STATIC_INIT LIB_PICO_MULTICORE
#endif

#endif


5 changes: 3 additions & 2 deletions src/rp2_common/pico_cxx_options/new_delete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "pico/cxx_options.h"

#if !PICO_CXX_ENABLE_EXCEPTIONS
// Override the standard allocators to use regular malloc/free

#if !PICO_CXX_DISABLE_ALLOCATION_OVERRIDES // Let user override
#include <stdlib.h> // weird looking but it is required if dropping picolibc on top of GCC+newlib (reent issue)
#include <stdlib.h> // weird looking, but it is required if dropping picolibc on top of GCC+newlib (reent issue)
Comment thread
kilograham marked this conversation as resolved.
#include <cstdlib>
#include "pico.h"

Expand All @@ -20,7 +21,7 @@ void *operator new[](std::size_t n) {
return std::malloc(n);
}

void operator delete(void *p) { std::free(p); }
void operator delete(void *p) noexcept { std::free(p); }

void operator delete[](void *p) noexcept { std::free(p); }

Expand Down
11 changes: 6 additions & 5 deletions src/rp2_common/pico_standard_link/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ if (NOT TARGET pico_standard_link)
# \brief\ Place time-critical code for the target into <MEMORY>
#
# Configures the target to run functions marked __time_critical_func() from <MEMORY> rather than
# normal SRAM, useful if <MEMORY> has dedicated AHB ports which are otherwise unused. For example,
# normal SRAM, useful if <MEMORY> has dedicated AHB ports which are otherwise unused. For example,
# xip_ram could be used in no_flash and copy_to_ram binaries, as the XIP AHB ports are unused.
# This sets PICO_TIME_CRITICAL_PLACEMENT=__in_<MEMORY>, and any necessary defines required to use
# <MEMORY> (e.g. PICO_USE_XIP_CACHE_AS_RAM=1 for xip_ram).
Expand All @@ -229,7 +229,7 @@ if (NOT TARGET pico_standard_link)
# \brief\ Place time-critical code for the target into <MEMORY>
#
# Configures the target to place data (and code) marked __not_in_flash() in <MEMORY> rather than
# normal SRAM, useful if <MEMORY> has dedicated AHB ports which are otherwise unused. For example,
# normal SRAM, useful if <MEMORY> has dedicated AHB ports which are otherwise unused. For example,
# xip_ram could be used in no_flash and copy_to_ram binaries, as the XIP AHB ports are unused.
# This sets PICO_NOT_IN_FLASH_PLACEMENT=__in_<MEMORY>, and any necessary defines required to use
# <MEMORY> (e.g. PICO_USE_XIP_CACHE_AS_RAM=1 for xip_ram).
Expand Down Expand Up @@ -363,9 +363,10 @@ if (NOT TARGET pico_standard_link)
target_compile_definitions(pico_standard_link INTERFACE PICO_DEOPTIMIZED_DEBUG=1)
endif()

# this (arguably wrong) code is restored for 1.5.1 as setting -nostartfiles on many C++ binaries causes link errors. see issue #1368
# -nostartfiles will be added if PICO_NO_FLASH would be defined to 1
target_link_options(pico_standard_link INTERFACE $<$<IF:$<IN_LIST:$<TARGET_PROPERTY:PICO_TARGET_BINARY_TYPE>,${NO_FLASH_BINARY_TYPES}>,1,$<AND:$<IN_LIST:${PICO_DEFAULT_BINARY_TYPE},${NO_FLASH_BINARY_TYPES}>,$<STREQUAL:,$<TARGET_PROPERTY:PICO_TARGET_BINARY_TYPE>>>>:-nostartfiles>)
if (PICO_C_COMPILER_IS_GNU)
target_link_options(pico_standard_link INTERFACE -nostartfiles)
endif()

# boot_stage2 will be linked if PICO_NO_FLASH would be defined to 0; note if boot_stage2 headers not present, then boot_stage2 is omitted from build anyway
if (TARGET boot_stage2_headers)
target_link_libraries(pico_standard_link INTERFACE $<$<NOT:$<IF:$<IN_LIST:$<TARGET_PROPERTY:PICO_TARGET_BINARY_TYPE>,${NO_FLASH_BINARY_TYPES}>,1,$<AND:$<IN_LIST:${PICO_DEFAULT_BINARY_TYPE},${NO_FLASH_BINARY_TYPES}>,$<STREQUAL:,$<TARGET_PROPERTY:PICO_TARGET_BINARY_TYPE>>>>>:$<IF:$<BOOL:$<TARGET_PROPERTY:PICO_TARGET_BOOT_STAGE2>>,$<TARGET_PROPERTY:PICO_TARGET_BOOT_STAGE2>,bs2_default>_library>)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
__tls_base, __tls_end
__tbss_end
__global_pointer$
__dso_handle
*/

SECTIONS
Expand Down Expand Up @@ -65,6 +66,7 @@ SECTIONS
*(SORT(.fini_array.*))
*(.fini_array)
PROVIDE_HIDDEN (__fini_array_end = .);
PROVIDE(__dso_handle = 0);
Comment thread
kilograham marked this conversation as resolved.

*(.jcr)
. = ALIGN(4);
Expand Down
Loading
Loading