diff --git a/libs/libc/dirent/lib_scandir.c b/libs/libc/dirent/lib_scandir.c index c734ff1d243..f55862a460a 100644 --- a/libs/libc/dirent/lib_scandir.c +++ b/libs/libc/dirent/lib_scandir.c @@ -31,6 +31,10 @@ #include #include +#ifdef CONFIG_FDPIC +# include +#endif + #include "libc.h" /* The scandir() function is not appropriate for use within the kernel in its @@ -91,6 +95,19 @@ int scandir(FAR const char *path, FAR struct dirent ***namelist, * the original errno value to be able to restore it in case of success. */ +#ifdef CONFIG_FDPIC + /* An FDPIC module passes the address of a function descriptor, not a code + * address. Resolve the filter, which is called from the loop below. + * + * compar is deliberately NOT resolved here. It is handed to qsort(), + * whose public entry point resolves it, and resolving it twice would + * treat an already-resolved code address as a descriptor. + */ + + filter = (CODE int (*)(FAR const struct dirent *)) + fdpic_callback((FAR void *)filter); +#endif + errsv = get_errno(); dirp = opendir(path); diff --git a/libs/libc/pthread/pthread_create.c b/libs/libc/pthread/pthread_create.c index 6c87140361c..e0b734be18b 100644 --- a/libs/libc/pthread/pthread_create.c +++ b/libs/libc/pthread/pthread_create.c @@ -30,6 +30,10 @@ #include +#ifdef CONFIG_FDPIC +# include +#endif + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -88,6 +92,20 @@ static void pthread_startup(pthread_startroutine_t entry, int pthread_create(FAR pthread_t *thread, FAR const pthread_attr_t *attr, pthread_startroutine_t pthread_entry, pthread_addr_t arg) { +#ifdef CONFIG_FDPIC + /* An FDPIC module passes the address of a function descriptor, not a code + * address. Resolve it here, once, in the public entry point. + * + * The new thread inherits the creator's D-Space -- nxtask_dup_dspace() + * runs before up_initial_state() installs it in the FDPIC register -- so + * it starts with the module's own data base already in place, and needs + * only the code address. + */ + + pthread_entry = (pthread_startroutine_t) + fdpic_callback((FAR void *)pthread_entry); +#endif + return nx_pthread_create(pthread_startup, thread, attr, pthread_entry, arg); } diff --git a/libs/libc/pthread/pthread_once.c b/libs/libc/pthread/pthread_once.c index ccd854b8788..ba2b87a73fe 100644 --- a/libs/libc/pthread/pthread_once.c +++ b/libs/libc/pthread/pthread_once.c @@ -33,6 +33,10 @@ #include #include +#ifdef CONFIG_FDPIC +# include +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -73,6 +77,21 @@ int pthread_once(FAR pthread_once_t *once_control, return EINVAL; } +#ifdef CONFIG_FDPIC + /* An FDPIC module passes the address of a function descriptor, not a code + * address. Resolve it here, in the public entry point. + * + * init_routine() runs on this thread, so the module's data base is + * already in the FDPIC register and only the code address is needed. The + * resolved value is a local copy and is never stored, so a later call + * through the same once_control resolves the caller's descriptor afresh + * rather than re-resolving a code address. + */ + + init_routine = (CODE void (*)(void)) + fdpic_callback((FAR void *)init_routine); +#endif + if (!once_control->done) { pthread_mutex_lock(&once_control->mutex); diff --git a/libs/libc/signal/sig_signal.c b/libs/libc/signal/sig_signal.c index 8ed40cf2ef2..bf19d765ea0 100644 --- a/libs/libc/signal/sig_signal.c +++ b/libs/libc/signal/sig_signal.c @@ -71,6 +71,14 @@ _sa_handler_t signal(int signo, _sa_handler_t func) DEBUGASSERT(func != SIG_ERR && func != SIG_HOLD); + /* An FDPIC module passes the address of a function descriptor rather than + * a code address, but it is not resolved here: sigaction() then + * nxsig_action() resolves the handler in the innermost common code, which + * covers both this path and a module that calls sigaction() directly. + * Resolving here as well would resolve it twice and branch through a code + * address as if it were a descriptor. + */ + /* Initialize the sigaction structure */ act.sa_handler = func; diff --git a/sched/signal/sig_action.c b/sched/signal/sig_action.c index ab37db83d26..0bb28cea125 100644 --- a/sched/signal/sig_action.c +++ b/sched/signal/sig_action.c @@ -38,6 +38,10 @@ #include #include +#ifdef CONFIG_FDPIC +# include +#endif + #include "sched/sched.h" #include "group/group.h" #include "signal/signal.h" @@ -326,6 +330,27 @@ int nxsig_action(int signo, FAR const struct sigaction *act, handler = act->sa_handler; +#ifdef CONFIG_FDPIC + /* An FDPIC module passes the address of a function descriptor, not a code + * address. Resolve it here, in the innermost common code, so a module + * that calls sigaction() directly is covered as well as one that goes + * through signal(), and each exactly once -- signal() passes its argument + * through unresolved for that reason. + * + * The dispositions have to be excluded by hand. SIG_ERR, SIG_IGN, + * SIG_DFL and SIG_HOLD are the small integers -1, 0, 1 and 2 rather than + * addresses, and fdpic_callback() only declines to dereference NULL. + * sa_handler and sa_sigaction are a union, so this one resolution serves + * both handler forms. + */ + + if (handler != SIG_ERR && handler != SIG_IGN && handler != SIG_DFL && + handler != SIG_HOLD) + { + handler = (_sa_handler_t)fdpic_callback((FAR void *)handler); + } +#endif + #ifdef CONFIG_SIG_DEFAULT /* If the caller is setting the handler to SIG_DFL, then we need to * replace this with the correct, internal default signal action handler. diff --git a/sched/task/task_create.c b/sched/task/task_create.c index 4530a742491..a517dcf0962 100644 --- a/sched/task/task_create.c +++ b/sched/task/task_create.c @@ -37,6 +37,10 @@ #include #include +#ifdef CONFIG_FDPIC +# include +#endif + #include "sched/sched.h" #include "group/group.h" #include "task/task.h" @@ -202,8 +206,23 @@ int task_create_with_stack(FAR const char *name, int priority, FAR void *stack_addr, int stack_size, main_t entry, FAR char * const argv[]) { - int ret = nxtask_create(name, priority, stack_addr, - stack_size, entry, argv, NULL); + int ret; + +#ifdef CONFIG_FDPIC + /* An FDPIC module passes the address of a function descriptor, not a code + * address. Resolving it here covers task_create() too, which is a plain + * forwarder -- and covers it exactly once, which matters: resolving twice + * would treat an already-resolved code address as a descriptor. + * + * The new task inherits the creator's D-Space, so it starts with the + * module's own data base installed and needs only the code address. + */ + + entry = (main_t)fdpic_callback((FAR void *)entry); +#endif + + ret = nxtask_create(name, priority, stack_addr, + stack_size, entry, argv, NULL); if (ret < 0) { set_errno(-ret); diff --git a/sched/task/task_spawn.c b/sched/task/task_spawn.c index a29db7f893c..4252b6b577e 100644 --- a/sched/task/task_spawn.c +++ b/sched/task/task_spawn.c @@ -38,6 +38,10 @@ #include #include +#ifdef CONFIG_FDPIC +# include +#endif + #include "sched/sched.h" #include "group/group.h" #include "task/spawn.h" @@ -335,6 +339,17 @@ int task_spawn(FAR const char *name, main_t entry, pid_t pid = INVALID_PROCESS_ID; int ret; +#ifdef CONFIG_FDPIC + /* An FDPIC module passes the address of a function descriptor, not a code + * address. Resolve it here, once, in the public entry point. + * + * The new task inherits the creator's D-Space, so it starts with the + * module's own data base installed and needs only the code address. + */ + + entry = (main_t)fdpic_callback((FAR void *)entry); +#endif + sinfo("name=%s entry=%p file_actions=%p attr=%p argv=%p\n", name, entry, file_actions, attr, argv);