Skip to content

Commit

Permalink
cpu/native: fix build with musl
Browse files Browse the repository at this point in the history
This changes a bunch of things that allows building with the musl C lib,
provided that `libucontext-dev` and `pkg-config` are installed.

Note that installing libucontext makes absolutely zero sense on C libs
that do natively provide this deprecated System V API, such as glibc.
Hence, it no sane glibc setup is expected to ever have libucontext
installed.

A main pain point was that argv and argc are expected to be passed to
init_fini handlers, but that is actually a glibc extension. This just
parses `/proc/self/cmdline` by hand to populate argv and argc during
startup, unless running on glibc.
  • Loading branch information
Marian Buschsieweke authored and maribu committed May 30, 2024
1 parent 251ea7f commit 5321059
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 33 deletions.
7 changes: 7 additions & 0 deletions cpu/native/Makefile.include
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,10 @@ ifeq ($(OS) $(OS_ARCH),Linux x86_64)
endif

include $(RIOTMAKE)/arch/native.inc.mk

USE_LIBUCONTEXT := $(shell pkg-config libucontext 2> /dev/null && echo 1 || echo 0)

ifeq ($(USE_LIBUCONTEXT),1)
CFLAGS += $(pkg-config libucontext --cflags) -DUSE_LIBUCONTEXT=1
LINKFLAGS += $(shell pkg-config libucontext --libs)
endif
1 change: 0 additions & 1 deletion cpu/native/include/native_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,6 @@ extern volatile int _native_in_isr;
extern volatile int _native_in_syscall;

extern char __isr_stack[];
extern char __end_stack[];
extern ucontext_t native_isr_context;
extern ucontext_t end_context;
extern ucontext_t *_native_cur_ctx, *_native_isr_ctx;
Expand Down
20 changes: 11 additions & 9 deletions cpu/native/irq_cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,16 @@
* @author Ludwig Knüpfer <ludwig.knuepfer@fu-berlin.de>
*/

/* __USE_GNU for gregs[REG_EIP] access under glibc
* _GNU_SOURCE for REG_EIP and strsignal() under musl */
#define __USE_GNU
#define _GNU_SOURCE

#include <err.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

#ifdef HAVE_VALGRIND_H
#include <valgrind.h>
Expand All @@ -29,16 +35,12 @@
#define VALGRIND_DEBUG(...)
#endif

/* __USE_GNU for gregs[REG_EIP] access under Linux */
#define __USE_GNU
#include <signal.h>
#undef __USE_GNU

#include "irq.h"
#include "cpu.h"
#include "periph/pm.h"

#include "native_internal.h"
#include "test_utils/expect.h"

#define ENABLE_DEBUG 0
#include "debug.h"
Expand All @@ -58,7 +60,6 @@ volatile int _native_sigpend;
int _sig_pipefd[2];

static _native_callback_t native_irq_handlers[255];
char sigalt_stk[SIGSTKSZ];

void *thread_isr_stack_pointer(void)
{
Expand Down Expand Up @@ -523,8 +524,9 @@ void native_interrupt_init(void)
_native_isr_ctx = &native_isr_context;

static stack_t sigstk;
sigstk.ss_sp = sigalt_stk;
sigstk.ss_size = sizeof(sigalt_stk);
sigstk.ss_sp = malloc(SIGSTKSZ);
expect(sigstk.ss_sp != NULL);
sigstk.ss_size = SIGSTKSZ;
sigstk.ss_flags = 0;

if (sigaltstack(&sigstk, NULL) < 0) {
Expand Down
28 changes: 17 additions & 11 deletions cpu/native/native_cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,22 @@
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

/* __USE_GNU for gregs[REG_EIP] access under glibc
* _GNU_SOURCE for REG_EIP and strsignal() under musl */
#define __USE_GNU
#define _GNU_SOURCE

#include <err.h>
#include <signal.h>
#undef __USE_GNU
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#if USE_LIBUCONTEXT
#include <libucontext/libucontext.h>
#else
#include <ucontext.h>
#include <err.h>
#endif

#ifdef HAVE_VALGRIND_H
#include <valgrind.h>
Expand All @@ -45,11 +51,11 @@

#include <stdlib.h>

#include "irq.h"
#include "sched.h"

#include "cpu.h"
#include "cpu_conf.h"
#include "irq.h"
#include "sched.h"
#include "test_utils/expect.h"

#ifdef MODULE_NETDEV_TAP
#include "netdev_tap.h"
Expand All @@ -62,7 +68,6 @@ extern netdev_tap_t netdev_tap;
#include "debug.h"

ucontext_t end_context;
char __end_stack[SIGSTKSZ];

/**
* make the new context assign `_native_in_isr = 0` before resuming
Expand Down Expand Up @@ -263,7 +268,8 @@ void native_cpu_init(void)
err(EXIT_FAILURE, "native_cpu_init: getcontext");
}

end_context.uc_stack.ss_sp = __end_stack;
end_context.uc_stack.ss_sp = malloc(SIGSTKSZ);
expect(end_context.uc_stack.ss_sp != NULL);
end_context.uc_stack.ss_size = SIGSTKSZ;
end_context.uc_stack.ss_flags = 0;
makecontext(&end_context, sched_task_exit, 0);
Expand Down
71 changes: 59 additions & 12 deletions cpu/native/startup.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,28 @@
#else
#include <dlfcn.h>
#endif
#include "byteorder.h"
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <features.h>
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <err.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include "kernel_init.h"
#include "cpu.h"
#include "byteorder.h"
#include "irq.h"

#include "board_internal.h"
#include "kernel_init.h"
#include "native_internal.h"
#include "stdio_base.h"
#include "tty_uart.h"

#include "periph/init.h"
#include "periph/pm.h"
#include "test_utils/expect.h"
#include "tty_uart.h"

#define ENABLE_DEBUG 0
#include "debug.h"
Expand Down Expand Up @@ -121,6 +119,12 @@ static const char short_opts[] = ":hi:s:deEoc:"
#endif
"";

#if __GLIBC__
static const bool _is_glibc = true;
#else
static const bool _is_glibc = false;
#endif

static const struct option long_opts[] = {
{ "help", no_argument, NULL, 'h' },
{ "id", required_argument, NULL, 'i' },
Expand Down Expand Up @@ -468,6 +472,49 @@ __attribute__((constructor)) static void startup(int argc, char **argv, char **e
/* initialize stdio as early as possible */
early_init();

/* Passing argc, argv, and envp to init_fini handlers is a glibc
* extension. If we are not running glibc, we parse /proc/self/cmdline
* to populate argc and argv by hand */
if (!_is_glibc) {
const size_t bufsize = 4096;
const size_t argc_max = 32;
size_t cmdlen = 0;
char *cmdline = malloc(bufsize);
argv = calloc(sizeof(char *), argc_max);
argc = 0;
envp = NULL;
expect(cmdline != NULL);
int cmdfd = real_open("/proc/self/cmdline", O_RDONLY);
expect(cmdfd != -1);
ssize_t count;
do {
count = real_read(cmdfd, cmdline + cmdlen, bufsize - cmdlen);
if (count < 0) {
if ((errno == EWOULDBLOCK) || (errno == EAGAIN)) {
continue;
}
expect(0);
}
cmdlen += count;
} while (count > 0);
real_close(cmdfd);
cmdline = realloc(cmdline, cmdlen);

char *argpos = cmdline;
while ((size_t)argc < argc_max) {
size_t len = strlen(argpos);
if (len == 0) {
argv[argc] = NULL;
break;
}

argv[argc++] = argpos;
argpos += len + 1;
}
expect((size_t)argc < argc_max);
argv = realloc(argv, sizeof(char *) * (argc + 1));
}

_native_argv = argv;
_progname = argv[0];
_native_pid = real_getpid();
Expand Down

0 comments on commit 5321059

Please sign in to comment.