Skip to content

Commit 9fc8c77

Browse files
[Zephyr] Fix build issues with LTO (#34633)
* [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 <damian.krolik@nordicsemi.no> * [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 <damian.krolik@nordicsemi.no> * [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 <damian.krolik@nordicsemi.no> --------- Signed-off-by: Damian Krolik <damian.krolik@nordicsemi.no>
1 parent 268e7ca commit 9fc8c77

File tree

4 files changed

+37
-17
lines changed

4 files changed

+37
-17
lines changed

config/nrfconnect/chip-module/CMakeLists.txt

+10-1
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,6 @@ matter_generate_args_tmp_file()
200200
# ==============================================================================
201201

202202
matter_build(chip
203-
LIB_SHELL ${CONFIG_CHIP_LIB_SHELL}
204203
LIB_TESTS ${CONFIG_CHIP_BUILD_TESTS}
205204
DEVICE_INFO_EXAMPLE_PROVIDER ${CONFIG_CHIP_EXAMPLE_DEVICE_INFO_PROVIDER}
206205
GN_DEPENDENCIES kernel
@@ -225,6 +224,16 @@ if (CONFIG_CHIP_MALLOC_SYS_HEAP_OVERRIDE)
225224
)
226225
endif()
227226

227+
if (CONFIG_CHIP_LIB_SHELL)
228+
# Force pulling chip::Shell::Engine::RunMainLoop() in the final binary.
229+
# Without this workaround, the linker script does not process the shell and
230+
# init objects defined in MainLoopZephyr.cpp unless the Matter library or
231+
# the Matter shell library is linked using the '--whole-archive' flag.
232+
target_link_options(chip INTERFACE
233+
-Wl,-u,_ZN4chip5Shell6Engine11RunMainLoopEv
234+
)
235+
endif()
236+
228237
# ==============================================================================
229238
# Define 'chip-ota-image' target for building CHIP OTA image
230239
# ==============================================================================

examples/all-clusters-app/nrfconnect/prj_release.conf

+4
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,7 @@ CONFIG_CHIP_FACTORY_DATA_BUILD=y
6262

6363
# Enable the Read Client for binding purposes
6464
CONFIG_CHIP_ENABLE_READ_CLIENT=y
65+
66+
# Enable LTO to reduce the flash usage
67+
CONFIG_LTO=y
68+
CONFIG_ISR_TABLES_LOCAL_DECLARATION=y

src/lib/shell/MainLoopZephyr.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -91,15 +91,15 @@ int ExecCommandInShellThread(const struct shell * shell, size_t argc, char ** ar
9191
return error == CHIP_NO_ERROR ? 0 : -ENOEXEC;
9292
}
9393

94-
int RegisterCommands()
94+
int RegisterMatterCommands()
9595
{
9696
Shell::Engine::Root().RegisterDefaultCommands();
9797
return 0;
9898
}
9999

100100
} // namespace
101101

102-
SYS_INIT(RegisterCommands, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
102+
SYS_INIT(RegisterMatterCommands, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
103103
SHELL_CMD_ARG_REGISTER(matter, NULL, "Matter commands", ExecCommandInShellThread, 1, CHIP_SHELL_MAX_TOKENS);
104104

105105
namespace chip {

src/platform/Zephyr/SysHeapMalloc.cpp

+21-14
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,6 @@ extern "C" {
3030
#include <cstdint>
3131
#include <cstring>
3232

33-
// Construct name of the given function wrapped with the `--wrap=symbol` GCC option.
34-
#define WRAP(f) __wrap_##f
35-
3633
using namespace chip;
3734

3835
namespace {
@@ -67,7 +64,7 @@ LockGuard::~LockGuard()
6764
}
6865
}
6966

70-
int initHeap()
67+
int InitSysHeapMalloc()
7168
{
7269
sys_heap_init(&sHeap, sHeapMemory, sizeof(sHeapMemory));
7370
return 0;
@@ -77,7 +74,7 @@ int initHeap()
7774

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

8279
namespace chip {
8380
namespace DeviceLayer {
@@ -99,7 +96,7 @@ void * Calloc(size_t num, size_t size)
9996
return nullptr;
10097
}
10198

102-
void * mem = malloc(totalSize);
99+
void * mem = Malloc(totalSize);
103100

104101
if (mem)
105102
{
@@ -156,27 +153,37 @@ void ResetMaxStats()
156153

157154
extern "C" {
158155

159-
void * WRAP(malloc)(size_t size) __attribute((alias("_ZN4chip11DeviceLayer6Malloc6MallocEj")));
160-
void * WRAP(calloc)(size_t num, size_t size) __attribute((alias("_ZN4chip11DeviceLayer6Malloc6CallocEjj")));
161-
void * WRAP(realloc)(void * mem, size_t size) __attribute((alias("_ZN4chip11DeviceLayer6Malloc7ReallocEPvj")));
162-
void WRAP(free)(void * mem) __attribute((alias("_ZN4chip11DeviceLayer6Malloc4FreeEPv")));
156+
// Construct the name of a function wrapped with the `--wrap=symbol` GCC option.
157+
#define WRAP(f) __wrap_##f
158+
159+
// Define a function as an alias of another function.
160+
#define ALIAS(f) __attribute((alias(f)))
161+
162+
// Mark a function as externally visible so that it is not optimized-away even
163+
// if LTO or whole-program optimization is enabled.
164+
#define EXTERNALLY_VISIBLE __attribute((externally_visible))
165+
166+
EXTERNALLY_VISIBLE void * WRAP(malloc)(size_t size) ALIAS("_ZN4chip11DeviceLayer6Malloc6MallocEj");
167+
EXTERNALLY_VISIBLE void * WRAP(calloc)(size_t num, size_t size) ALIAS("_ZN4chip11DeviceLayer6Malloc6CallocEjj");
168+
EXTERNALLY_VISIBLE void * WRAP(realloc)(void * mem, size_t size) ALIAS("_ZN4chip11DeviceLayer6Malloc7ReallocEPvj");
169+
EXTERNALLY_VISIBLE void WRAP(free)(void * mem) ALIAS("_ZN4chip11DeviceLayer6Malloc4FreeEPv");
163170

164-
void * WRAP(_malloc_r)(_reent *, size_t size)
171+
EXTERNALLY_VISIBLE void * WRAP(_malloc_r)(_reent *, size_t size)
165172
{
166173
return WRAP(malloc)(size);
167174
}
168175

169-
void * WRAP(_calloc_r)(_reent *, size_t num, size_t size)
176+
EXTERNALLY_VISIBLE void * WRAP(_calloc_r)(_reent *, size_t num, size_t size)
170177
{
171178
return WRAP(calloc)(num, size);
172179
}
173180

174-
void * WRAP(_realloc_r)(_reent *, void * mem, size_t size)
181+
EXTERNALLY_VISIBLE void * WRAP(_realloc_r)(_reent *, void * mem, size_t size)
175182
{
176183
return WRAP(realloc)(mem, size);
177184
}
178185

179-
void WRAP(_free_r)(_reent *, void * mem)
186+
EXTERNALLY_VISIBLE void WRAP(_free_r)(_reent *, void * mem)
180187
{
181188
WRAP(free)(mem);
182189
}

0 commit comments

Comments
 (0)