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)
|
||||
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 \
|
||||
|
@ -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
|
||||
|
@ -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 <sys/linux-syscalls.h>
|
||||
|
||||
.text
|
||||
.type __pthread_clone, #function
|
||||
.global __pthread_clone
|
||||
.align 4
|
||||
|
||||
__pthread_clone:
|
||||
@ insert the args onto the new stack
|
||||
str r0, [r1, #-4]
|
||||
str r3, [r1, #-8]
|
||||
.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]
|
||||
|
||||
@ 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
|
||||
|
@ -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
|
||||
|
@ -2,17 +2,19 @@
|
||||
#include <sys/linux-syscalls.h>
|
||||
|
||||
.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
|
@ -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...
|
||||
*/
|
@ -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
|
||||
|
@ -2,15 +2,18 @@
|
||||
#include <sys/linux-syscalls.h>
|
||||
|
||||
.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
|
@ -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...
|
||||
*/
|
@ -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
|
||||
|
@ -2,19 +2,21 @@
|
||||
#include <sys/linux-syscalls.h>
|
||||
|
||||
.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
|
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()
|
||||
|
||||
- add clone() implementation for ARM (x86 and SH-4 not working yet)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
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_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
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user