1//------------------------------------------------------------------------------
2// Copyright (c) 2016 by Lukasz Janyst <lukasz@jany.st>
3//------------------------------------------------------------------------------
4// This file is part of thread-bites.
5//
6// thread-bites is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// thread-bites is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with thread-bites. If not, see <http://www.gnu.org/licenses/>.
18//------------------------------------------------------------------------------
19
20#include <asm/unistd_64.h> // for syscall numbers
21
22//------------------------------------------------------------------------------
23// All this has been derived from glibc's sysdeps/unix/sysv/linux/x86_64/clone.S
24// the Linux kernel sources, and a bunch of websites.
25//
26// We need to make a function callable from C that calls the clone syscall and
27// and starts the user function on the new task. We do this in assembly
28// to properly set up the call frame information (CFI) for debugging,
29// backtraces, exceptions and such.
30//
31// The C call has the following format:
32//
33// int tbclone(int (*fn)(void *arg), void *arg, int flags, void *child_stack
34// pid_t *parent_tidptr, pid_t *child_tidptr, void *tls),
35//
36// This results with the registers having the following values:
37//
38// rdi: fn
39// rsi: arg
40// rdx: flags
41// rcx: child_stack
42// r8: parent TID pointer
43// r9: child TID pointer
44// %rsp+8: TLS pointer
45//
46// The syscall has the following interface:
47//
48// SYSCALL_DEFINE5(clone,
49// unsigned long, clone_flags,
50// unsigned long, newsp,
51// int __user *, parent_tidptr,
52// int __user *, child_tidptr,
53// unsigned long, tls)
54//
55// So we need the registers to be:
56//
57// rax: __NR_clone
58// rdi: flags
59// rsi: child_stack
60// rdx: parent TID pointer
61// r10: child TID pointer
62// r8: TLS pointer
63//
64//------------------------------------------------------------------------------
65
66 .text
67
68 .global tbclone // sets the symbol as externally linkable
69 .type tbclone,@function // declare this symbol as a function in ELF
70 .align 16 // place the next instruction at an address
71 // divisible by 16 in the resulting ELF binary
72tbclone:
73 .cfi_startproc // cfi_* is the stuff for exception frames
74 subq $16, %rcx // decrement the new stack pointer by 16 because
75 // we will pop stuff from it later
76 movq %rsi, 8(%rcx) // store the function argument in the child's stack
77 movq %rdi, 0(%rcx) // store the function pointer in the child's stack
78
79 movq $__NR_clone, %rax // clone syscall number to rax
80 movq %rdx, %rdi // flags to rdi
81 movq %rcx, %rsi // child_stack to rsi
82 movq %r8, %rdx // parent_tid to rdx
83 movq %r9, %r10 // child_tid to r10
84 movq 8(%rsp), %r8 // TLS pointer to r8
85 .cfi_endproc // end FDE now to get proper unwind info in the
86 // child
87 syscall // call sys_clone
88 testq %rax, %rax // compare %rax && %rax to zero
89 jz .Lstart_thread // 0 == we're in the child
90 ret // we're in the parent with either an error or
91 // the child's TID
92
93.Lstart_thread: // ELF local label
94 .cfi_startproc
95 .cfi_undefined rip // previous value of the instruction pointer cannot
96 // be restored anymore
97 xorq %rbp, %rbp // clear the frame pointer
98
99 popq %rax // pop the function pointer
100 popq %rdi // pop the argument
101 call *%rax // call the function
102
103 movq %rax, %rdi // whatever the function returned goes to rdi
104 movq $__NR_exit, %rax // exit syscall number to %rax
105 syscall // call sys_exit
106 .cfi_endproc
107