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
3 changes: 3 additions & 0 deletions arch/sim/src/cmake/Toolchain.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ endif()
if(CONFIG_COVERAGE_ALL)
if(CONFIG_ARCH_TOOLCHAIN_GCC)
add_compile_options(-fprofile-arcs -ftest-coverage -fno-inline)
if(APPLE)
add_link_options(-fprofile-arcs -ftest-coverage)
endif()
elseif(CONFIG_ARCH_TOOLCHAIN_CLANG)
add_compile_options(-fprofile-instr-generate -fcoverage-mapping)
add_link_options(-fprofile-instr-generate)
Expand Down
4 changes: 3 additions & 1 deletion arch/sim/src/sim/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ set(HOSTSRCS)
set(HOST_INCLUDE_DIRS)
set(STDLIBS pthread)

if(CONFIG_COVERAGE_TOOLCHAIN)
if(CONFIG_COVERAGE_TOOLCHAIN
AND CONFIG_ARCH_TOOLCHAIN_GCC
AND NOT APPLE)
list(APPEND STDLIBS gcov)
endif()

Expand Down
26 changes: 17 additions & 9 deletions arch/sim/src/sim/posix/sim_macho_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
#include <sys/mman.h>

#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>

Expand Down Expand Up @@ -78,11 +80,12 @@ static void save_and_replace_init_funcs(int argc, const char *argv[],
const char *apple[])
{
init_func_t *fp;
bool found_self = false;
unsigned int i;
unsigned int nfuncs = &mod_init_func_end - &mod_init_func_start;

assert(nfuncs > 0);
g_num_saved_init_funcs = nfuncs - 1;
if (g_num_saved_init_funcs == 0)
if (nfuncs == 1)
{
/* This function is the only constructor in the binary.
* no need to apply the following hack.
Expand All @@ -96,23 +99,28 @@ static void save_and_replace_init_funcs(int argc, const char *argv[],
g_saved_envp = envp;
g_saved_apple = apple;

g_saved_init_funcs = malloc(g_num_saved_init_funcs *
sizeof(*g_saved_init_funcs));
g_saved_init_funcs = malloc((nfuncs - 1) * sizeof(*g_saved_init_funcs));
allow_write(&mod_init_func_start, &mod_init_func_end);
int i = 0;
i = 0;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

merge with line 84

for (fp = &mod_init_func_start; fp < &mod_init_func_end; fp++)
{
if (*fp == save_and_replace_init_funcs)
{
assert(i == 0);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

save_and_replace_init_funcs must be the first entry, so it can move all constructors to new array and call them after nuttx kernel finish the basic initialization.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

On macOS Mach-O, a function registered with attribute((constructor)) is not guaranteed to be placed at the beginning of the __DATA,__mod_init_func section. When CMake, Apple’s toolchain, coverage runtime, or initialization functions originating from Rust/Cargo are involved, another constructor may be placed before save_and_replace_init_funcs. If assert(i == 0); is kept in that situation, the program may fail with an assertion failure at startup, or the old logic may handle g_saved_init_funcs incorrectly because its assumption is no longer valid.
Therefore, this change was necessary to handle the reality that, on macOS, save_and_replace_init_funcs does not always come first. The new logic searches for save_and_replace_init_funcs in the constructor array and safely saves and replaces only the constructors that appear after it. That said, from NuttX’s design perspective, it is still preferable for this function to be the first entry. A complete solution would be to separately consider a way to guarantee that placement, for example by controlling the link order or using a dedicated section.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

please study the code to understand how the thing work: you must find a method to ensure save_and_replace_init_funcs come to first, otherwise all constructors before save_and_replace_init_funcs get executed too early. That's why the origin author add assert in the code.

Copy link
Copy Markdown
Contributor

@xiaoxiang781216 xiaoxiang781216 May 16, 2026

Choose a reason for hiding this comment

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

or we need find other different solution to fix this problem.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

here is another fix: #18886. since I don't use macOS, @toku-mac could you try it?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

About PR #18886.

In my environment, it didn't work without making several modifications.
I left a comment on that PR.

Thanks.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

how about let's work on #18886 and close this pr? it's better to open a new pr for tokio library issue.

found_self = true;
continue;
}
else

if (found_self)
{
g_saved_init_funcs[i - 1] = *fp;
assert(i < nfuncs - 1);
g_saved_init_funcs[i] = *fp;
*fp = noop;
i++;
}
i++;
}

assert(found_self);
g_num_saved_init_funcs = i;
}

/****************************************************************************
Expand Down
21 changes: 20 additions & 1 deletion sched/clock/clock_gettime.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,20 @@
# include "clock/clock_timekeeping.h"
#endif

/****************************************************************************
* Pre-processor Definitions
****************************************************************************/

#if defined(CONFIG_ARCH_SIM) && defined(CONFIG_HOST_MACOS)
/* Rust code built for the macOS host uses Darwin's libc clock IDs. When it
* is linked into the NuttX simulator, those values are passed to NuttX's
* clock_gettime() implementation instead of Darwin's one.
*/

# define DARWIN_CLOCK_MONOTONIC 6
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why add macos specific code in common module? all macos specific code should be in arch/sim/.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I'm trying to fix the dependency issue using weak_function,
but I'm still unable to resolve the panic occurring in Rust's tokio.
I'll keep investigating further.

# define DARWIN_CLOCK_UPTIME_RAW 8
#endif

/****************************************************************************
* Private Functions
****************************************************************************/
Expand Down Expand Up @@ -97,7 +111,12 @@ int nxclock_gettime(clockid_t clock_id, FAR struct timespec *tp)
return -EINVAL;
}

if (clock_id == CLOCK_MONOTONIC)
if (clock_id == CLOCK_MONOTONIC
#if defined(CONFIG_ARCH_SIM) && defined(CONFIG_HOST_MACOS)
|| clock_id == DARWIN_CLOCK_MONOTONIC
|| clock_id == DARWIN_CLOCK_UPTIME_RAW
#endif
)
{
/* The the time elapsed since the timer was initialized at power on
* reset, excluding the time that the system is suspended.
Expand Down
Loading