我正在尝试使用 Linux clone3() 系统调用(在 Linux 5.3 中引入)来创建线程,而不使用标准库。虽然有很多使用旧的clone()系统调用的例子,但我还没有找到使用clone3()创建线程的明确例子。 我正在尝试做的事情:
直接使用clone3()系统调用创建线程 无需 libc (-nostdlib) 即可实现此功能 让线程执行一个打印消息的简单函数。
当前行为: 打印“Created”后,程序因 SIGSEGV 崩溃。 strace 输出显示:
execve("./clone3", ["./clone3"], 0x7ffc16f11ca0 /* 43 vars */) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_GROWSDOWN|MAP_STACK, -1, 0) = 0x7156c433d000
clone3({flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND, exit_signal=0, stack=0x7156c433d000, stack_size=0x2000}, 88) = 9973
write(1, "C", 1C) = 1
write(1, "r", 1r) = 1
write(1, "e", 1e) = 1
write(1, "a", 1a) = 1
write(1, "t", 1t) = 1
write(1, "e", 1e) = 1
write(1, "d", 1d) = 1
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x20040114d} ---
+++ killed by SIGSEGV (core dumped) +++
fish: Job 1, 'strace ./clone3' terminated by signal SIGSEGV (Address boundary error)
代码:
#define _GNU_SOURCE
#include <linux/mman.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <stddef.h>
#include <sys/syscall.h>
typedef int (*thread_fn)(void *arg);
static inline long syscall6(long n, long a1, long a2, long a3, long a4, long a5,
long a6) {
register long rax __asm__("rax") = n;
register long rdi __asm__("rdi") = a1;
register long rsi __asm__("rsi") = a2;
register long rdx __asm__("rdx") = a3;
register long r10 __asm__("r10") = a4;
register long r8 __asm__("r8") = a5;
register long r9 __asm__("r9") = a6;
__asm__ volatile("syscall"
: "+r"(rax)
: "r"(rdi), "r"(rsi), "r"(rdx), "r"(r10), "r"(r8), "r"(r9)
: "rcx", "r11", "memory");
return rax;
}
static inline long mmap(void *addr, size_t length, int prot, int flags, int fd,
long offset) {
return syscall6(SYS_mmap, (long)addr, (long)length, (long)prot, (long)flags,
(long)fd, offset);
}
static inline void exit(int code) {
syscall6(SYS_exit_group, code, 0, 0, 0, 0, 0);
}
static inline void sleep_seconds(unsigned int seconds) {
struct timespec ts = {.tv_sec = seconds, .tv_nsec = 0};
syscall6(SYS_nanosleep, (long)&ts, 0, 0, 0, 0, 0);
}
static inline void write_str(const char *str) {
while (*str) {
syscall6(SYS_write, 1, (long)str, 1, 0, 0, 0);
str++;
}
}
static inline long clone3(struct clone_args *args) {
register long rax __asm__("rax") = SYS_clone3;
register long rdi __asm__("rdi") = (long)args;
register long rsi __asm__("rsi") = (long)sizeof(struct clone_args);
__asm__ volatile("syscall"
: "+r"(rax)
: "r"(rdi), "r"(rsi)
: "r11", "memory");
if (rax < 0) {
write_str("clone3 was unsuccessful!");
exit(1);
}
return rax;
}
int thread_func(void *arg) {
write_str("Hello from thread!\n");
sleep_seconds(1);
return 0;
}
__attribute__((noreturn)) void _start() {
const unsigned long STACK_SIZE = 8192;
void *stack = (void *)mmap(
0, STACK_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_GROWSDOWN, -1, 0);
void *stack_top = stack + STACK_SIZE;
unsigned long *sp = (unsigned long *)stack_top;
*(--sp) = 0;
*(--sp) = (unsigned long)thread_func;
struct clone_args args = {0};
args.flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND;
args.stack = (unsigned long)stack;
args.stack_size = STACK_SIZE;
long tid = clone3(&args);
if (tid > 0) {
write_str("Created thread!\n");
sleep_seconds(2);
}
exit(0);
__builtin_unreachable();
}
编译:
gcc clone3.c -static -nostdlib -fno-stack-protector -o clone3
Linux 内核:6.11.6
我已经查看了内核文档和手册页,但找不到使用clone3()创建线程的具体示例。任何有助于理解我所缺少的内容的帮助将不胜感激。
我从 Chris Wellons 那里找到了工作项目。阅读他的文章:https://nullprogram.com/blog/2023/03/23/ 和他的来源 我测试了编译器的源代码,这是一项工作。