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).
This commit is contained in:
parent
1a2917ca95
commit
97cf7f3394
@ -289,6 +289,7 @@ libc_common_src_files := \
|
|||||||
ifeq ($(TARGET_ARCH),arm)
|
ifeq ($(TARGET_ARCH),arm)
|
||||||
libc_common_src_files += \
|
libc_common_src_files += \
|
||||||
bionic/eabi.c \
|
bionic/eabi.c \
|
||||||
|
bionic/bionic_clone.c \
|
||||||
arch-arm/bionic/__get_pc.S \
|
arch-arm/bionic/__get_pc.S \
|
||||||
arch-arm/bionic/__get_sp.S \
|
arch-arm/bionic/__get_sp.S \
|
||||||
arch-arm/bionic/_exit_with_stack_teardown.S \
|
arch-arm/bionic/_exit_with_stack_teardown.S \
|
||||||
|
@ -34,7 +34,12 @@ void _exit_thread:exit (int) 1
|
|||||||
pid_t __fork:fork (void) 2
|
pid_t __fork:fork (void) 2
|
||||||
pid_t _waitpid:waitpid (pid_t, int*, int, struct rusage*) -1,7
|
pid_t _waitpid:waitpid (pid_t, int*, int, struct rusage*) -1,7
|
||||||
int waitid(int, pid_t, struct siginfo_t*, int,void*) 280,284
|
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 execve (const char*, char* const*, char* const*) 11
|
||||||
|
|
||||||
int setuid:setuid32 (uid_t) 213
|
int setuid:setuid32 (uid_t) 213
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2008 The Android Open Source Project
|
* Copyright (C) 2008-2010 The Android Open Source Project
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -27,18 +27,19 @@
|
|||||||
*/
|
*/
|
||||||
#include <sys/linux-syscalls.h>
|
#include <sys/linux-syscalls.h>
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.type __pthread_clone, #function
|
.type __pthread_clone, #function
|
||||||
.global __pthread_clone
|
.global __pthread_clone
|
||||||
.align 4
|
.align 4
|
||||||
|
.fnstart
|
||||||
|
|
||||||
__pthread_clone:
|
__pthread_clone:
|
||||||
@ insert the args onto the new stack
|
@ insert the args onto the new stack
|
||||||
str r0, [r1, #-4]
|
str r0, [r1, #-4]
|
||||||
str r3, [r1, #-8]
|
str r3, [r1, #-8]
|
||||||
|
|
||||||
@ do the system call
|
@ do the system call
|
||||||
@ get flags
|
@ get flags
|
||||||
|
|
||||||
mov r0, r2
|
mov r0, r2
|
||||||
|
|
||||||
@ -47,28 +48,81 @@ __pthread_clone:
|
|||||||
#if __ARM_EABI__
|
#if __ARM_EABI__
|
||||||
stmfd sp!, {r4, r7}
|
stmfd sp!, {r4, r7}
|
||||||
ldr r7, =__NR_clone
|
ldr r7, =__NR_clone
|
||||||
swi #0
|
swi #0
|
||||||
#else
|
#else
|
||||||
swi #__NR_clone
|
swi #__NR_clone
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
movs r0, r0
|
movs r0, r0
|
||||||
#if __ARM_EABI__
|
#if __ARM_EABI__
|
||||||
ldmnefd sp!, {r4, r7}
|
ldmnefd sp!, {r4, r7}
|
||||||
#endif
|
#endif
|
||||||
blt __error
|
blt __error
|
||||||
bxne lr
|
bxne lr
|
||||||
|
|
||||||
|
|
||||||
@ pick the function arg and call address off the stack and jump
|
@ pick the function arg and call address off the stack and jump
|
||||||
@ to the C __thread_entry function which does some setup and then
|
@ to the C __thread_entry function which does some setup and then
|
||||||
@ calls the thread's start function
|
@ calls the thread's start function
|
||||||
|
|
||||||
ldr r0, [sp, #-4]
|
ldr r0, [sp, #-4]
|
||||||
ldr r1, [sp, #-8]
|
ldr r1, [sp, #-8]
|
||||||
mov r2, sp @ __thread_entry needs the TLS pointer
|
mov r2, sp @ __thread_entry needs the TLS pointer
|
||||||
b __thread_entry
|
b __thread_entry
|
||||||
|
|
||||||
__error:
|
__error:
|
||||||
mov r0, #-1
|
mov r0, #-1
|
||||||
bx lr
|
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
|
||||||
|
@ -4,7 +4,7 @@ syscall_src += arch-arm/syscalls/_exit.S
|
|||||||
syscall_src += arch-arm/syscalls/_exit_thread.S
|
syscall_src += arch-arm/syscalls/_exit_thread.S
|
||||||
syscall_src += arch-arm/syscalls/__fork.S
|
syscall_src += arch-arm/syscalls/__fork.S
|
||||||
syscall_src += arch-arm/syscalls/waitid.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/execve.S
|
||||||
syscall_src += arch-arm/syscalls/setuid.S
|
syscall_src += arch-arm/syscalls/setuid.S
|
||||||
syscall_src += arch-arm/syscalls/getuid.S
|
syscall_src += arch-arm/syscalls/getuid.S
|
||||||
|
@ -2,17 +2,19 @@
|
|||||||
#include <sys/linux-syscalls.h>
|
#include <sys/linux-syscalls.h>
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.type __clone, #function
|
.type __sys_clone, #function
|
||||||
.globl __clone
|
.globl __sys_clone
|
||||||
.align 4
|
.align 4
|
||||||
.fnstart
|
.fnstart
|
||||||
|
|
||||||
__clone:
|
__sys_clone:
|
||||||
.save {r4, r7}
|
mov ip, sp
|
||||||
stmfd sp!, {r4, r7}
|
.save {r4, r5, r6, r7}
|
||||||
|
stmfd sp!, {r4, r5, r6, r7}
|
||||||
|
ldmfd ip, {r4, r5, r6}
|
||||||
ldr r7, =__NR_clone
|
ldr r7, =__NR_clone
|
||||||
swi #0
|
swi #0
|
||||||
ldmfd sp!, {r4, r7}
|
ldmfd sp!, {r4, r5, r6, r7}
|
||||||
movs r0, r0
|
movs r0, r0
|
||||||
bxpl lr
|
bxpl lr
|
||||||
b __set_syscall_errno
|
b __set_syscall_errno
|
@ -72,3 +72,8 @@ __return:
|
|||||||
.align 2
|
.align 2
|
||||||
0: .long __NR_clone
|
0: .long __NR_clone
|
||||||
1: .long __thread_entry
|
1: .long __thread_entry
|
||||||
|
|
||||||
|
/* XXX: TODO: Add __bionic_clone here
|
||||||
|
* See bionic/bionic_clone.c and arch-arm/bionic/clone.S
|
||||||
|
* for more details...
|
||||||
|
*/
|
@ -5,7 +5,7 @@ syscall_src += arch-sh/syscalls/_exit_thread.S
|
|||||||
syscall_src += arch-sh/syscalls/__fork.S
|
syscall_src += arch-sh/syscalls/__fork.S
|
||||||
syscall_src += arch-sh/syscalls/_waitpid.S
|
syscall_src += arch-sh/syscalls/_waitpid.S
|
||||||
syscall_src += arch-sh/syscalls/waitid.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/execve.S
|
||||||
syscall_src += arch-sh/syscalls/setuid.S
|
syscall_src += arch-sh/syscalls/setuid.S
|
||||||
syscall_src += arch-sh/syscalls/getuid.S
|
syscall_src += arch-sh/syscalls/getuid.S
|
||||||
|
@ -2,15 +2,18 @@
|
|||||||
#include <sys/linux-syscalls.h>
|
#include <sys/linux-syscalls.h>
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.type __clone, @function
|
.type __sys_clone, @function
|
||||||
.globl __clone
|
.globl __sys_clone
|
||||||
.align 4
|
.align 4
|
||||||
|
|
||||||
__clone:
|
__sys_clone:
|
||||||
|
|
||||||
|
/* get ready for additonal arg */
|
||||||
|
mov.l @r15, r0
|
||||||
|
|
||||||
/* invoke trap */
|
/* invoke trap */
|
||||||
mov.l 0f, r3 /* trap num */
|
mov.l 0f, r3 /* trap num */
|
||||||
trapa #(4 + 0x10)
|
trapa #(5 + 0x10)
|
||||||
|
|
||||||
/* check return value */
|
/* check return value */
|
||||||
cmp/pz r0
|
cmp/pz r0
|
@ -48,3 +48,8 @@ __pthread_clone:
|
|||||||
popl %ecx
|
popl %ecx
|
||||||
popl %ebx
|
popl %ebx
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
/* XXX: TODO: Add __bionic_clone here
|
||||||
|
* See bionic/bionic_clone.c and arch-arm/bionic/clone.S
|
||||||
|
* for more details...
|
||||||
|
*/
|
@ -5,7 +5,7 @@ syscall_src += arch-x86/syscalls/_exit_thread.S
|
|||||||
syscall_src += arch-x86/syscalls/__fork.S
|
syscall_src += arch-x86/syscalls/__fork.S
|
||||||
syscall_src += arch-x86/syscalls/_waitpid.S
|
syscall_src += arch-x86/syscalls/_waitpid.S
|
||||||
syscall_src += arch-x86/syscalls/waitid.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/execve.S
|
||||||
syscall_src += arch-x86/syscalls/setuid.S
|
syscall_src += arch-x86/syscalls/setuid.S
|
||||||
syscall_src += arch-x86/syscalls/getuid.S
|
syscall_src += arch-x86/syscalls/getuid.S
|
||||||
|
@ -2,19 +2,21 @@
|
|||||||
#include <sys/linux-syscalls.h>
|
#include <sys/linux-syscalls.h>
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.type __clone, @function
|
.type __sys_clone, @function
|
||||||
.globl __clone
|
.globl __sys_clone
|
||||||
.align 4
|
.align 4
|
||||||
|
|
||||||
__clone:
|
__sys_clone:
|
||||||
pushl %ebx
|
pushl %ebx
|
||||||
pushl %ecx
|
pushl %ecx
|
||||||
pushl %edx
|
pushl %edx
|
||||||
pushl %esi
|
pushl %esi
|
||||||
mov 20(%esp), %ebx
|
pushl %edi
|
||||||
mov 24(%esp), %ecx
|
mov 24(%esp), %ebx
|
||||||
mov 28(%esp), %edx
|
mov 28(%esp), %ecx
|
||||||
mov 32(%esp), %esi
|
mov 32(%esp), %edx
|
||||||
|
mov 36(%esp), %esi
|
||||||
|
mov 40(%esp), %edi
|
||||||
movl $__NR_clone, %eax
|
movl $__NR_clone, %eax
|
||||||
int $0x80
|
int $0x80
|
||||||
cmpl $-129, %eax
|
cmpl $-129, %eax
|
||||||
@ -25,6 +27,7 @@ __clone:
|
|||||||
addl $4, %esp
|
addl $4, %esp
|
||||||
orl $-1, %eax
|
orl $-1, %eax
|
||||||
1:
|
1:
|
||||||
|
popl %edi
|
||||||
popl %esi
|
popl %esi
|
||||||
popl %edx
|
popl %edx
|
||||||
popl %ecx
|
popl %ecx
|
81
libc/bionic/bionic_clone.c
Normal file
81
libc/bionic/bionic_clone.c
Normal file
@ -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 <sched.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
@ -46,6 +46,7 @@ Differences between current and Android 2.1:
|
|||||||
|
|
||||||
- <wchar.h>: Add mbstowcs() and wcstombs()
|
- <wchar.h>: 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:
|
Differences between Android 2.1 and 2.0.1:
|
||||||
|
@ -69,8 +69,9 @@ extern int sched_rr_get_interval(pid_t pid, struct timespec *tp);
|
|||||||
#define CLONE_CHILD_SETTID 0x01000000
|
#define CLONE_CHILD_SETTID 0x01000000
|
||||||
#define CLONE_STOPPED 0x02000000
|
#define CLONE_STOPPED 0x02000000
|
||||||
|
|
||||||
extern int clone(int (*fn)(void*), void *child_stack, int flags, void *arg);
|
#ifdef __GNU_SOURCE
|
||||||
extern pid_t __clone(int, void *);
|
extern int clone(int (*fn)(void *), void *child_stack, int flags, void* arg, ...);
|
||||||
|
#endif
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ void _exit_thread (int);
|
|||||||
pid_t __fork (void);
|
pid_t __fork (void);
|
||||||
pid_t _waitpid (pid_t, int*, int, struct rusage*);
|
pid_t _waitpid (pid_t, int*, int, struct rusage*);
|
||||||
int waitid (int, pid_t, struct siginfo_t*, int,void*);
|
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 execve (const char*, char* const*, char* const*);
|
||||||
int setuid (uid_t);
|
int setuid (uid_t);
|
||||||
uid_t getuid (void);
|
uid_t getuid (void);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user