From 97cf7f3394780d524038fc083e2c134031b54728 Mon Sep 17 00:00:00 2001 From: David 'Digit' Turner Date: Fri, 22 Jan 2010 18:59:05 -0800 Subject: [PATCH] Implement clone() C library function properly. Only provide an implementation for ARM at the moment, since it requires specific assembly fragments (the standard syscall stubs cannot be used because the child returns in a different stack). --- libc/Android.mk | 1 + libc/SYSCALLS.TXT | 7 +- libc/arch-arm/bionic/clone.S | 108 +++++++++++++++------ libc/arch-arm/syscalls.mk | 2 +- .../arch-arm/syscalls/{__clone.S => __sys_clone.S} | 14 +-- libc/arch-sh/bionic/clone.S | 5 + libc/arch-sh/syscalls.mk | 2 +- libc/arch-sh/syscalls/{__clone.S => __sys_clone.S} | 11 ++- libc/arch-x86/bionic/clone.S | 5 + libc/arch-x86/syscalls.mk | 2 +- .../arch-x86/syscalls/{__clone.S => __sys_clone.S} | 17 ++-- libc/bionic/bionic_clone.c | 81 ++++++++++++++++ libc/docs/CHANGES.TXT | 1 + libc/include/sched.h | 5 +- libc/include/sys/linux-unistd.h | 2 +- 15 files changed, 212 insertions(+), 51 deletions(-) rename libc/arch-arm/syscalls/{__clone.S => __sys_clone.S} (51%) rename libc/arch-sh/syscalls/{__clone.S => __sys_clone.S} (74%) rename libc/arch-x86/syscalls/{__clone.S => __sys_clone.S} (64%) create mode 100644 libc/bionic/bionic_clone.c diff --git a/libc/Android.mk b/libc/Android.mk index c32cc30fe..e820b60fa 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -289,6 +289,7 @@ libc_common_src_files := \ ifeq ($(TARGET_ARCH),arm) libc_common_src_files += \ bionic/eabi.c \ + bionic/bionic_clone.c \ arch-arm/bionic/__get_pc.S \ arch-arm/bionic/__get_sp.S \ arch-arm/bionic/_exit_with_stack_teardown.S \ diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT index 684b43eb5..6a21b048f 100644 --- a/libc/SYSCALLS.TXT +++ b/libc/SYSCALLS.TXT @@ -34,7 +34,12 @@ void _exit_thread:exit (int) 1 pid_t __fork:fork (void) 2 pid_t _waitpid:waitpid (pid_t, int*, int, struct rusage*) -1,7 int waitid(int, pid_t, struct siginfo_t*, int,void*) 280,284 -pid_t __clone:clone(int (*fn)(void*), void *child_stack, int flags, void *arg) 120 + +# NOTE: this system call is never called directly, but we list it there +# to have __NR_clone properly defined. +# +pid_t __sys_clone:clone (int, void*, int*, void*, int*) 120 + int execve (const char*, char* const*, char* const*) 11 int setuid:setuid32 (uid_t) 213 diff --git a/libc/arch-arm/bionic/clone.S b/libc/arch-arm/bionic/clone.S index 791c73d28..9c2505373 100644 --- a/libc/arch-arm/bionic/clone.S +++ b/libc/arch-arm/bionic/clone.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2008-2010 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,48 +27,102 @@ */ #include - .text - .type __pthread_clone, #function - .global __pthread_clone - .align 4 - + .text + .type __pthread_clone, #function + .global __pthread_clone + .align 4 + .fnstart + __pthread_clone: - @ insert the args onto the new stack - str r0, [r1, #-4] - str r3, [r1, #-8] + @ insert the args onto the new stack + str r0, [r1, #-4] + str r3, [r1, #-8] + + @ do the system call + @ get flags - @ do the system call - @ get flags - mov r0, r2 - + @ new sp is already in r1 #if __ARM_EABI__ stmfd sp!, {r4, r7} ldr r7, =__NR_clone - swi #0 + swi #0 #else - swi #__NR_clone + swi #__NR_clone #endif - movs r0, r0 + movs r0, r0 #if __ARM_EABI__ ldmnefd sp!, {r4, r7} #endif - blt __error - bxne lr + blt __error + bxne lr - @ pick the function arg and call address off the stack and jump - @ to the C __thread_entry function which does some setup and then - @ calls the thread's start function + @ pick the function arg and call address off the stack and jump + @ to the C __thread_entry function which does some setup and then + @ calls the thread's start function - ldr r0, [sp, #-4] - ldr r1, [sp, #-8] - mov r2, sp @ __thread_entry needs the TLS pointer - b __thread_entry + ldr r0, [sp, #-4] + ldr r1, [sp, #-8] + mov r2, sp @ __thread_entry needs the TLS pointer + b __thread_entry __error: - mov r0, #-1 - bx lr + mov r0, #-1 + bx lr + .fnend + + + # + # This function is defined as: + # + # pid_t __bionic_clone( int flags, void *child_stack, + # pid_t *pid, void *tls, pid_t *ctid, + # int (*fn)(void *), void* arg ); + # + # NOTE: This is not the same signature than the GLibc + # __clone function here !! Placing 'fn' and 'arg' + # at the end of the parameter list makes the + # implementation much simpler. + # + .type __bionic_clone, #function + .globl __bionic_clone + .align 4 + .fnstart + +__bionic_clone: + mov ip, sp + .save {r4, r5, r6, r7} + + # save registers to parent stack + stmfd sp!, {r4, r5, r6, r7} + + # load extra parameters + ldmfd ip, {r4, r5, r6} + + # store 'fn' and 'arg' to the child stack + str r5, [r1, #-4] + str r6, [r1, #-8] + + # system call + ldr r7, =__NR_clone + swi #0 + movs r0, r0 + beq 1f + + # in parent, reload saved registers + # then either exit or error + # + ldmfd sp!, {r4, r5, r6, r7} + bxne lr + b __set_syscall_errno + +1: # in the child - pick arguments + ldr r0, [sp, #-4] + ldr r1, [sp, #-8] + b __bionic_clone_entry + + .fnend diff --git a/libc/arch-arm/syscalls.mk b/libc/arch-arm/syscalls.mk index 706cb0c9b..5f416e8f7 100644 --- a/libc/arch-arm/syscalls.mk +++ b/libc/arch-arm/syscalls.mk @@ -4,7 +4,7 @@ syscall_src += arch-arm/syscalls/_exit.S syscall_src += arch-arm/syscalls/_exit_thread.S syscall_src += arch-arm/syscalls/__fork.S syscall_src += arch-arm/syscalls/waitid.S -syscall_src += arch-arm/syscalls/__clone.S +syscall_src += arch-arm/syscalls/__sys_clone.S syscall_src += arch-arm/syscalls/execve.S syscall_src += arch-arm/syscalls/setuid.S syscall_src += arch-arm/syscalls/getuid.S diff --git a/libc/arch-arm/syscalls/__clone.S b/libc/arch-arm/syscalls/__sys_clone.S similarity index 51% rename from libc/arch-arm/syscalls/__clone.S rename to libc/arch-arm/syscalls/__sys_clone.S index 650e2c0ca..9fe2641e1 100644 --- a/libc/arch-arm/syscalls/__clone.S +++ b/libc/arch-arm/syscalls/__sys_clone.S @@ -2,17 +2,19 @@ #include .text - .type __clone, #function - .globl __clone + .type __sys_clone, #function + .globl __sys_clone .align 4 .fnstart -__clone: - .save {r4, r7} - stmfd sp!, {r4, r7} +__sys_clone: + mov ip, sp + .save {r4, r5, r6, r7} + stmfd sp!, {r4, r5, r6, r7} + ldmfd ip, {r4, r5, r6} ldr r7, =__NR_clone swi #0 - ldmfd sp!, {r4, r7} + ldmfd sp!, {r4, r5, r6, r7} movs r0, r0 bxpl lr b __set_syscall_errno diff --git a/libc/arch-sh/bionic/clone.S b/libc/arch-sh/bionic/clone.S index 0bbaecbc9..9cb19eeb5 100644 --- a/libc/arch-sh/bionic/clone.S +++ b/libc/arch-sh/bionic/clone.S @@ -72,3 +72,8 @@ __return: .align 2 0: .long __NR_clone 1: .long __thread_entry + +/* XXX: TODO: Add __bionic_clone here + * See bionic/bionic_clone.c and arch-arm/bionic/clone.S + * for more details... + */ \ No newline at end of file diff --git a/libc/arch-sh/syscalls.mk b/libc/arch-sh/syscalls.mk index cefb2ec46..d3e531e3d 100644 --- a/libc/arch-sh/syscalls.mk +++ b/libc/arch-sh/syscalls.mk @@ -5,7 +5,7 @@ syscall_src += arch-sh/syscalls/_exit_thread.S syscall_src += arch-sh/syscalls/__fork.S syscall_src += arch-sh/syscalls/_waitpid.S syscall_src += arch-sh/syscalls/waitid.S -syscall_src += arch-sh/syscalls/__clone.S +syscall_src += arch-sh/syscalls/__sys_clone.S syscall_src += arch-sh/syscalls/execve.S syscall_src += arch-sh/syscalls/setuid.S syscall_src += arch-sh/syscalls/getuid.S diff --git a/libc/arch-sh/syscalls/__clone.S b/libc/arch-sh/syscalls/__sys_clone.S similarity index 74% rename from libc/arch-sh/syscalls/__clone.S rename to libc/arch-sh/syscalls/__sys_clone.S index 1df6ca288..c2e7dd20b 100644 --- a/libc/arch-sh/syscalls/__clone.S +++ b/libc/arch-sh/syscalls/__sys_clone.S @@ -2,15 +2,18 @@ #include .text - .type __clone, @function - .globl __clone + .type __sys_clone, @function + .globl __sys_clone .align 4 -__clone: +__sys_clone: + + /* get ready for additonal arg */ + mov.l @r15, r0 /* invoke trap */ mov.l 0f, r3 /* trap num */ - trapa #(4 + 0x10) + trapa #(5 + 0x10) /* check return value */ cmp/pz r0 diff --git a/libc/arch-x86/bionic/clone.S b/libc/arch-x86/bionic/clone.S index 361808ded..3b50cc3d3 100644 --- a/libc/arch-x86/bionic/clone.S +++ b/libc/arch-x86/bionic/clone.S @@ -48,3 +48,8 @@ __pthread_clone: popl %ecx popl %ebx ret + +/* XXX: TODO: Add __bionic_clone here + * See bionic/bionic_clone.c and arch-arm/bionic/clone.S + * for more details... + */ \ No newline at end of file diff --git a/libc/arch-x86/syscalls.mk b/libc/arch-x86/syscalls.mk index 86d23080a..e718e18c0 100644 --- a/libc/arch-x86/syscalls.mk +++ b/libc/arch-x86/syscalls.mk @@ -5,7 +5,7 @@ syscall_src += arch-x86/syscalls/_exit_thread.S syscall_src += arch-x86/syscalls/__fork.S syscall_src += arch-x86/syscalls/_waitpid.S syscall_src += arch-x86/syscalls/waitid.S -syscall_src += arch-x86/syscalls/__clone.S +syscall_src += arch-x86/syscalls/__sys_clone.S syscall_src += arch-x86/syscalls/execve.S syscall_src += arch-x86/syscalls/setuid.S syscall_src += arch-x86/syscalls/getuid.S diff --git a/libc/arch-x86/syscalls/__clone.S b/libc/arch-x86/syscalls/__sys_clone.S similarity index 64% rename from libc/arch-x86/syscalls/__clone.S rename to libc/arch-x86/syscalls/__sys_clone.S index 586212974..172d6af89 100644 --- a/libc/arch-x86/syscalls/__clone.S +++ b/libc/arch-x86/syscalls/__sys_clone.S @@ -2,19 +2,21 @@ #include .text - .type __clone, @function - .globl __clone + .type __sys_clone, @function + .globl __sys_clone .align 4 -__clone: +__sys_clone: pushl %ebx pushl %ecx pushl %edx pushl %esi - mov 20(%esp), %ebx - mov 24(%esp), %ecx - mov 28(%esp), %edx - mov 32(%esp), %esi + pushl %edi + mov 24(%esp), %ebx + mov 28(%esp), %ecx + mov 32(%esp), %edx + mov 36(%esp), %esi + mov 40(%esp), %edi movl $__NR_clone, %eax int $0x80 cmpl $-129, %eax @@ -25,6 +27,7 @@ __clone: addl $4, %esp orl $-1, %eax 1: + popl %edi popl %esi popl %edx popl %ecx diff --git a/libc/bionic/bionic_clone.c b/libc/bionic/bionic_clone.c new file mode 100644 index 000000000..6b2fa58f6 --- /dev/null +++ b/libc/bionic/bionic_clone.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#define __GNU_SOURCE 1 +#include +#include +#include +#include + +/* WARNING: AT THE MOMENT, THIS IS ONLY SUPPORTED ON ARM + */ + +extern int __bionic_clone(unsigned long clone_flags, + void* newsp, + int *parent_tidptr, + void *new_tls, + int *child_tidptr, + int (*fn)(void *), + void *arg); + +extern void _exit_thread(int retCode); + +/* this function is called from the __bionic_clone + * assembly fragment to call the thread function + * then exit. */ +extern void +__bionic_clone_entry( int (*fn)(void *), void *arg ) +{ + int ret = (*fn)(arg); + _exit_thread(ret); +} + +int +clone(int (*fn)(void *), void *child_stack, int flags, void* arg, ...) +{ + va_list args; + int *parent_tidptr = NULL; + void *new_tls = NULL; + int *child_tidptr = NULL; + int ret; + + /* extract optional parameters - they are cummulative */ + va_start(args, arg); + if (flags & (CLONE_PARENT_SETTID|CLONE_SETTLS|CLONE_CHILD_SETTID)) { + parent_tidptr = va_arg(args, int*); + } + if (flags & (CLONE_SETTLS|CLONE_CHILD_SETTID)) { + new_tls = va_arg(args, void*); + } + if (flags & CLONE_CHILD_SETTID) { + child_tidptr = va_arg(args, int*); + } + va_end(args); + + ret = __bionic_clone(flags, child_stack, parent_tidptr, new_tls, child_tidptr, fn, arg); + return ret; +} diff --git a/libc/docs/CHANGES.TXT b/libc/docs/CHANGES.TXT index 07eac57b5..c2655c513 100644 --- a/libc/docs/CHANGES.TXT +++ b/libc/docs/CHANGES.TXT @@ -46,6 +46,7 @@ Differences between current and Android 2.1: - : Add mbstowcs() and wcstombs() +- add clone() implementation for ARM (x86 and SH-4 not working yet) ------------------------------------------------------------------------------- Differences between Android 2.1 and 2.0.1: diff --git a/libc/include/sched.h b/libc/include/sched.h index 6600bae64..33b9ad684 100644 --- a/libc/include/sched.h +++ b/libc/include/sched.h @@ -69,8 +69,9 @@ extern int sched_rr_get_interval(pid_t pid, struct timespec *tp); #define CLONE_CHILD_SETTID 0x01000000 #define CLONE_STOPPED 0x02000000 -extern int clone(int (*fn)(void*), void *child_stack, int flags, void *arg); -extern pid_t __clone(int, void *); +#ifdef __GNU_SOURCE +extern int clone(int (*fn)(void *), void *child_stack, int flags, void* arg, ...); +#endif __END_DECLS diff --git a/libc/include/sys/linux-unistd.h b/libc/include/sys/linux-unistd.h index 12f7704f1..9a151d2d2 100644 --- a/libc/include/sys/linux-unistd.h +++ b/libc/include/sys/linux-unistd.h @@ -10,7 +10,7 @@ void _exit_thread (int); pid_t __fork (void); pid_t _waitpid (pid_t, int*, int, struct rusage*); int waitid (int, pid_t, struct siginfo_t*, int,void*); -pid_t __clone (int (*fn)(void*), void *child_stack, int flags, void *arg); +pid_t __sys_clone (int, void*, int*, void*, int*); int execve (const char*, char* const*, char* const*); int setuid (uid_t); uid_t getuid (void); -- 2.11.0