overhaul clone syscall wrapping

several things are changed. first, i have removed the old __uniclone
function signature and replaced it with the "standard" linux
__clone/clone signature. this was necessary to expose clone to
applications anyway, and it makes it easier to port __clone to new
archs, since it's now testable independently of pthread_create.

secondly, i have removed all references to the ugly ldt descriptor
structure (i386 only) from the c code and pthread structure. in places
where it is needed, it is now created on the stack just when it's
needed, in assembly code. thus, the i386 __clone function takes the
desired thread pointer as its argument, rather than an ldt descriptor
pointer, just like on all other sane archs. this should not affect
applications since there is really no way an application can use clone
with threads/tls in a way that doesn't horribly conflict with and
clobber the underlying implementation's use. applications are expected
to use clone only for creating actual processes, possibly with new
namespace features and whatnot.
This commit is contained in:
Rich Felker 2011-09-18 10:14:37 -04:00
parent 455fc98389
commit 3f72cdac73
9 changed files with 135 additions and 62 deletions

View File

@ -31,6 +31,33 @@ int sched_yield(void);
#define SCHED_FIFO 1 #define SCHED_FIFO 1
#define SCHED_RR 2 #define SCHED_RR 2
#ifdef _GNU_SOURCE
#define CSIGNAL 0x000000ff
#define CLONE_VM 0x00000100
#define CLONE_FS 0x00000200
#define CLONE_FILES 0x00000400
#define CLONE_SIGHAND 0x00000800
#define CLONE_PTRACE 0x00002000
#define CLONE_VFORK 0x00004000
#define CLONE_PARENT 0x00008000
#define CLONE_THREAD 0x00010000
#define CLONE_NEWNS 0x00020000
#define CLONE_SYSVSEM 0x00040000
#define CLONE_SETTLS 0x00080000
#define CLONE_PARENT_SETTID 0x00100000
#define CLONE_CHILD_CLEARTID 0x00200000
#define CLONE_DETACHED 0x00400000
#define CLONE_UNTRACED 0x00800000
#define CLONE_CHILD_SETTID 0x01000000
#define CLONE_NEWUTS 0x04000000
#define CLONE_NEWIPC 0x08000000
#define CLONE_NEWUSER 0x10000000
#define CLONE_NEWPID 0x20000000
#define CLONE_NEWNET 0x40000000
#define CLONE_IO 0x80000000
int clone (int (*)(void *), void *, int, void *, ...);
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -22,7 +22,6 @@
struct pthread { struct pthread {
struct pthread *self; struct pthread *self;
unsigned long tlsdesc[4];
pid_t tid, pid; pid_t tid, pid;
int tsd_used, errno_val, *errno_ptr; int tsd_used, errno_val, *errno_ptr;
volatile uintptr_t cp_sp, cp_ip; volatile uintptr_t cp_sp, cp_ip;
@ -87,7 +86,7 @@ struct __timer {
pthread_t __pthread_self_init(void); pthread_t __pthread_self_init(void);
int __uniclone(void *, void (*)(pthread_t), void *); int __clone(int (*)(void *), void *, int, void *, ...);
int __set_thread_area(void *); int __set_thread_area(void *);
int __libc_sigaction(int, const struct sigaction *, struct sigaction *); int __libc_sigaction(int, const struct sigaction *, struct sigaction *);
int __libc_sigprocmask(int, const sigset_t *, sigset_t *); int __libc_sigprocmask(int, const sigset_t *, sigset_t *);

View File

@ -1,4 +1,4 @@
#include <pthread_impl.h> #include "pthread_impl.h"
int __set_thread_area(void *p) int __set_thread_area(void *p)
{ {

View File

@ -0,0 +1,10 @@
#include <errno.h>
#include "libc.h"
int __clone(int (*func)(void *), void *stack, int flags, void *arg, ...)
{
errno = ENOSYS;
return -1;
}
weak_alias(__clone, clone);

View File

@ -1,3 +1,4 @@
#if 0
#include "pthread_impl.h" #include "pthread_impl.h"
#include <setjmp.h> #include <setjmp.h>
@ -64,3 +65,4 @@ pid_t forkall()
__synccall(do_forkall, &c); __synccall(do_forkall, &c);
return c.pid; return c.pid;
} }
#endif

View File

@ -2,20 +2,21 @@
.global __set_thread_area .global __set_thread_area
.type __set_thread_area,@function .type __set_thread_area,@function
__set_thread_area: __set_thread_area:
pushl %ebx push %ebx
movl 8(%esp),%ecx push $0x51
movl $-1,4(%ecx) push $0xfffff
movl %ecx,8(%ecx) push 16(%esp)
movl $0xfffff,12(%ecx) push $-1
movl $0x51,16(%ecx) mov %esp,%ebx
leal 4(%ecx),%ebx xor %eax,%eax
movl $243,%eax mov $243,%al
int $128 int $128
popl %ebx
testl %eax,%eax testl %eax,%eax
jnz 1f jnz 1f
movl 4(%ecx),%ecx movl (%esp),%ecx
leal 3(,%ecx,8),%ecx leal 3(,%ecx,8),%ecx
movw %cx,%gs movw %cx,%gs
1: 1:
addl $16,%esp
popl %ebx
ret ret

View File

@ -1,26 +1,51 @@
.text .text
.global __uniclone .global __clone
.type __uniclone,@function .weak clone
__uniclone: .type __clone,@function
movl 4(%esp),%ecx .type clone,@function
subl $24,%ecx __clone:
movl 8(%esp),%eax clone:
movl %eax,16(%ecx) push %ebp
movl 12(%esp),%eax mov %esp,%ebp
movl %eax,24(%ecx) push %ebx
pushl %ebx push %esi
pushl %esi push %edi
pushl %edi
pushl %ebp xor %eax,%eax
movl %eax,8(%eax) push $0x51
leal 20(%eax),%edx mov %gs,%ax
leal 4(%eax),%esi push $0xfffff
movl %edx,%edi shr $3,%eax
movl $0x7d0f00,%ebx push 28(%ebp)
movl $120,%eax push %eax
int $128 mov $120,%al
popl %ebp
popl %edi mov 12(%ebp),%ecx
popl %esi mov 16(%ebp),%ebx
popl %ebx and $-16,%ecx
sub $16,%ecx
mov 20(%ebp),%edi
mov %edi,(%ecx)
mov 24(%ebp),%edx
mov %esp,%esi
mov 32(%ebp),%edi
mov 8(%ebp),%ebp
int $128
test %eax,%eax
jnz 1f
mov %ebp,%eax
xor %ebp,%ebp
call *%eax
mov %eax,%ebx
xor %eax,%eax
inc %eax
int $128
hlt
1: add $16,%esp
pop %edi
pop %esi
pop %ebx
pop %ebp
ret ret

View File

@ -52,11 +52,13 @@ void __pthread_do_unregister(struct __ptcb *cb)
self->cancelbuf = self->cancelbuf->__next; self->cancelbuf = self->cancelbuf->__next;
} }
static void start(pthread_t self) static int start(void *p)
{ {
pthread_t self = p;
if (self->unblock_cancel) if (self->unblock_cancel)
__syscall(SYS_rt_sigprocmask, SIG_UNBLOCK, SIGPT_SET, 0, 8); __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK, SIGPT_SET, 0, 8);
pthread_exit(self->start(self->start_arg)); pthread_exit(self->start(self->start_arg));
return 0;
} }
#define ROUND(x) (((x)+PAGE_SIZE-1)&-PAGE_SIZE) #define ROUND(x) (((x)+PAGE_SIZE-1)&-PAGE_SIZE)
@ -115,14 +117,12 @@ int pthread_create(pthread_t *res, const pthread_attr_t *attr, void *(*entry)(vo
new->tsd = (void *)tsd; new->tsd = (void *)tsd;
if (attr) new->detached = attr->_a_detach; if (attr) new->detached = attr->_a_detach;
new->unblock_cancel = self->cancel; new->unblock_cancel = self->cancel;
memcpy(new->tlsdesc, self->tlsdesc, sizeof new->tlsdesc); stack = (void *)new;
new->tlsdesc[1] = (uintptr_t)new;
stack = (void *)((uintptr_t)new-1 & ~(uintptr_t)15);
__synccall_lock(); __synccall_lock();
a_inc(&libc.threads_minus_1); a_inc(&libc.threads_minus_1);
ret = __uniclone(stack, start, new); ret = __clone(start, stack, 0x7d8f00, new, &new->tid, new, &new->tid);
__synccall_unlock(); __synccall_unlock();

View File

@ -1,21 +1,30 @@
/* Copyright 2011 Nicholas J. Kain, licensed GNU LGPL 2.1 or later */
.text .text
.global __uniclone .global __clone
.type __uniclone,@function .weak clone
/* rdi = child_stack, rsi = start, rdx = pthread_struct */ .type __clone,@function
__uniclone: .type clone,@function
subq $8,%rsp /* pad parent stack to prevent branch later */ __clone:
subq $24,%rdi /* grow child_stack */ clone:
mov %rsi,8(%rdi) /* push start onto child_stack as return ptr */ xor %eax,%eax
mov %rdx,0(%rdi) /* push pthread_struct onto child_stack */ mov $56,%al
mov %rdx,%r8 /* r8 = tls */ mov %rdi,%r11
mov %rdi,%rsi /* rsi = child_stack */ mov %rdx,%rdi
leaq 40(%rdx),%r10 /* r10 = child_id */ mov %r8,%rdx
movl $56,%eax /* clone syscall number */ mov %r9,%r8
movl $0x7d0f00,%edi /* rdi = flags */ mov 8(%rsp),%r10
mov %r10,%rdx /* rdx = parent_id */ mov %r11,%r9
syscall /* clone(flags, child_stack, parent_id, and $-16,%rsi
* child_id, tls) */ sub $8,%rsi
pop %rdi /* child stack: restore pthread_struct mov %rcx,(%rsi)
* parent stack: undo rsp displacement */ syscall
ret test %eax,%eax
jnz 1f
xor %ebp,%ebp
pop %rdi
call *%r9
mov %eax,%edi
xor %eax,%eax
mov $60,%al
syscall
hlt
1: ret