Linux arm64下使用clone3系统调用实现线程触发段故障的问题
在Linux arm64平台使用clone3实现线程的问题与解决
问题描述
在Linux arm64平台上,尝试通过clone和clone3系统调用实现线程功能,但无法成功启动线程(克隆进程后执行execve是可行的)。预期效果是像pthread_create()一样启动线程并调用指定的start_routine()。
初始实现代码
C代码
unsigned long flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SYSVSEM | CLONE_SIGHAND | CLONE_SETTLS | CLONE_THREAD | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID); size_t stack_size = 8*1024*1024; void *stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_GROWSDOWN, -1, 0); struct clone_args args = { 0 }; args.flags = flags; args.tls = stack; args.stack = stack + 0x1000; args.stack_size = stack_size; int ret = _syscall_clone3(&args, sizeof(struct clone_args)); if (ret < 0) { return -1; } if (ret != 0) { // This is printed on console printf("continue from thread %d\n", gettid()); } else { // This never gets executed printf("In thread %d\n", gettid()); start_routine(arg); exit(0); }
汇编实现(_syscall_clone3)
__syscall_clone3: mov x8, #435 svc #0 ret
调试与解决过程
调试后发现栈为空,这是触发段故障的原因,推测编译器未正确填充栈,和C语言的工作机制有关。
研究libc实现后,发现部分实现会用汇编为start_routine做包装函数。修改汇编函数,新增传递参数并调用start_routine的逻辑:
// __syscall_clone3(args, sizeof(args), start_routine, start_routine_arg) __syscall_clone3: mov x8, #435 svc #0 ... mov x0, x3 blr x2 ret
修改后代码可正常工作,实现了预期的线程启动功能。
内容的提问来源于stack exchange,提问作者m3n
相关产品推荐
相关产品推荐

