Skip to content

Commit

Permalink
[Zephyr] Fix build issues with LTO (#34633)
Browse files Browse the repository at this point in the history
* [Zephyr] Fix sys_heap malloc build with LTO

Fix the build of Matter samples with sys_heap malloc enabled.
The linker errors would occur because:
1. The realloc() function is not used outside the LTO-
   optimized code.
2. Thus, the LTO linker plugin would mark __wrap_realloc
   symbol as PREVAILING_DEF_IRONLY, which would enable
   the compiler to optimize away the function.
3. As a result, undefined references to realloc() could not
   be resolved by the linker.

Mark malloc/calloc/realloc/free as externally visible.

Signed-off-by: Damian Krolik <[email protected]>

* [nrfconnect] Do not link libCHIPShell.a with --whole-archive

libCHIPShell.a is already part of libCHIP.a but the former
had to be linked additionally with --whole-archive flag to
process the shell and init objects defined with SHELL_XXX
and SYS_INIT Zephyr macros and, in turn, register Matter
shell commands properly.

This symbol duplication between the two libraries causes
issues when building Matter with LTO, so replace the current
approach with explicitly pulling in one symbol from
MainLoopZephyr.cpp file.

Signed-off-by: Damian Krolik <[email protected]>

* [nrfconnect] Build all clusters app for nRF7002 with LTO

The flash usage on this app/platform is close to the limit.
Enable LTO to prevent from blocking the incoming PRs.

Signed-off-by: Damian Krolik <[email protected]>

---------

Signed-off-by: Damian Krolik <[email protected]>
  • Loading branch information
Damian-Nordic authored and pull[bot] committed Dec 6, 2024
1 parent 441a039 commit 1690848
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 17 deletions.
11 changes: 10 additions & 1 deletion config/nrfconnect/chip-module/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,6 @@ matter_generate_args_tmp_file()
# ==============================================================================

matter_build(chip
LIB_SHELL ${CONFIG_CHIP_LIB_SHELL}
LIB_TESTS ${CONFIG_CHIP_BUILD_TESTS}
DEVICE_INFO_EXAMPLE_PROVIDER ${CONFIG_CHIP_EXAMPLE_DEVICE_INFO_PROVIDER}
GN_DEPENDENCIES kernel
Expand All @@ -225,6 +224,16 @@ if (CONFIG_CHIP_MALLOC_SYS_HEAP_OVERRIDE)
)
endif()

if (CONFIG_CHIP_LIB_SHELL)
# Force pulling chip::Shell::Engine::RunMainLoop() in the final binary.
# Without this workaround, the linker script does not process the shell and
# init objects defined in MainLoopZephyr.cpp unless the Matter library or
# the Matter shell library is linked using the '--whole-archive' flag.
target_link_options(chip INTERFACE
-Wl,-u,_ZN4chip5Shell6Engine11RunMainLoopEv
)
endif()

# ==============================================================================
# Define 'chip-ota-image' target for building CHIP OTA image
# ==============================================================================
Expand Down
4 changes: 4 additions & 0 deletions examples/all-clusters-app/nrfconnect/prj_release.conf
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,7 @@ CONFIG_CHIP_FACTORY_DATA_BUILD=y

# Enable the Read Client for binding purposes
CONFIG_CHIP_ENABLE_READ_CLIENT=y

# Enable LTO to reduce the flash usage
CONFIG_LTO=y
CONFIG_ISR_TABLES_LOCAL_DECLARATION=y
4 changes: 2 additions & 2 deletions src/lib/shell/MainLoopZephyr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,15 @@ int ExecCommandInShellThread(const struct shell * shell, size_t argc, char ** ar
return error == CHIP_NO_ERROR ? 0 : -ENOEXEC;
}

int RegisterCommands()
int RegisterMatterCommands()
{
Shell::Engine::Root().RegisterDefaultCommands();
return 0;
}

} // namespace

SYS_INIT(RegisterCommands, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
SYS_INIT(RegisterMatterCommands, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
SHELL_CMD_ARG_REGISTER(matter, NULL, "Matter commands", ExecCommandInShellThread, 1, CHIP_SHELL_MAX_TOKENS);

namespace chip {
Expand Down
35 changes: 21 additions & 14 deletions src/platform/Zephyr/SysHeapMalloc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ extern "C" {
#include <cstdint>
#include <cstring>

// Construct name of the given function wrapped with the `--wrap=symbol` GCC option.
#define WRAP(f) __wrap_##f

using namespace chip;

namespace {
Expand Down Expand Up @@ -67,7 +64,7 @@ LockGuard::~LockGuard()
}
}

int initHeap()
int InitSysHeapMalloc()
{
sys_heap_init(&sHeap, sHeapMemory, sizeof(sHeapMemory));
return 0;
Expand All @@ -77,7 +74,7 @@ int initHeap()

// Initialize the heap in the POST_KERNEL phase to make sure that it is ready even before
// C++ static constructors are called (which happens prior to the APPLICATION initialization phase).
SYS_INIT(initHeap, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
SYS_INIT(InitSysHeapMalloc, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);

namespace chip {
namespace DeviceLayer {
Expand All @@ -99,7 +96,7 @@ void * Calloc(size_t num, size_t size)
return nullptr;
}

void * mem = malloc(totalSize);
void * mem = Malloc(totalSize);

if (mem)
{
Expand Down Expand Up @@ -156,27 +153,37 @@ void ResetMaxStats()

extern "C" {

void * WRAP(malloc)(size_t size) __attribute((alias("_ZN4chip11DeviceLayer6Malloc6MallocEj")));
void * WRAP(calloc)(size_t num, size_t size) __attribute((alias("_ZN4chip11DeviceLayer6Malloc6CallocEjj")));
void * WRAP(realloc)(void * mem, size_t size) __attribute((alias("_ZN4chip11DeviceLayer6Malloc7ReallocEPvj")));
void WRAP(free)(void * mem) __attribute((alias("_ZN4chip11DeviceLayer6Malloc4FreeEPv")));
// Construct the name of a function wrapped with the `--wrap=symbol` GCC option.
#define WRAP(f) __wrap_##f

// Define a function as an alias of another function.
#define ALIAS(f) __attribute((alias(f)))

// Mark a function as externally visible so that it is not optimized-away even
// if LTO or whole-program optimization is enabled.
#define EXTERNALLY_VISIBLE __attribute((externally_visible))

EXTERNALLY_VISIBLE void * WRAP(malloc)(size_t size) ALIAS("_ZN4chip11DeviceLayer6Malloc6MallocEj");
EXTERNALLY_VISIBLE void * WRAP(calloc)(size_t num, size_t size) ALIAS("_ZN4chip11DeviceLayer6Malloc6CallocEjj");
EXTERNALLY_VISIBLE void * WRAP(realloc)(void * mem, size_t size) ALIAS("_ZN4chip11DeviceLayer6Malloc7ReallocEPvj");
EXTERNALLY_VISIBLE void WRAP(free)(void * mem) ALIAS("_ZN4chip11DeviceLayer6Malloc4FreeEPv");

void * WRAP(_malloc_r)(_reent *, size_t size)
EXTERNALLY_VISIBLE void * WRAP(_malloc_r)(_reent *, size_t size)
{
return WRAP(malloc)(size);
}

void * WRAP(_calloc_r)(_reent *, size_t num, size_t size)
EXTERNALLY_VISIBLE void * WRAP(_calloc_r)(_reent *, size_t num, size_t size)
{
return WRAP(calloc)(num, size);
}

void * WRAP(_realloc_r)(_reent *, void * mem, size_t size)
EXTERNALLY_VISIBLE void * WRAP(_realloc_r)(_reent *, void * mem, size_t size)
{
return WRAP(realloc)(mem, size);
}

void WRAP(_free_r)(_reent *, void * mem)
EXTERNALLY_VISIBLE void WRAP(_free_r)(_reent *, void * mem)
{
WRAP(free)(mem);
}
Expand Down

0 comments on commit 1690848

Please sign in to comment.