【问题标题】:Assembly clone syscall thread function not called程序集克隆系统调用线程函数未调用
【发布时间】:2020-03-12 15:16:43
【问题描述】:

我正在尝试使用“克隆”系统调用创建一个线程......我搜索了太多! 例如,
link1
link2

现在这是我的 linux x64 汇编源代码:

FORMAT  ELF64 EXECUTABLE
ENTRY   thread_linux_x64

THREAD_MEM_SIZE = 1024

define PROT_READ        0x1
define PROT_WRITE       0x2
define PROT_EXEC        0x4

define MAP_PRIVATE      0x02
define MAP_ANONYMOUS    0x20

define CLONE_VM         0x00000100
define CLONE_FS         0x00000200
define CLONE_FILES      0x00000400
define CLONE_SIGHAND    0x00000800
define CLONE_PARENT     0x00008000
define CLONE_THREAD     0x00010000
define CLONE_IO         0x80000000

define SIGCHLD          20

CLONE_FLAGS = CLONE_VM OR CLONE_FS OR CLONE_FILES OR CLONE_SIGHAND OR CLONE_PARENT OR CLONE_THREAD OR CLONE_IO

MMAP_FLAG       = MAP_PRIVATE OR MAP_ANONYMOUS
MMAP_PERMISSION = PROT_READ   OR PROT_WRITE OR PROT_EXEC

SEGMENT READABLE EXECUTABLE
thread_linux_x64:

        ; Memory allocation using 'mmap' syscall
        mov     eax,  9                 ; sys_mmap
        xor     edi,  edi               ; addr = null (0)
        mov     esi,  THREAD_MEM_SIZE   ; Memory size
        mov     edx,  MMAP_PERMISSION   ; Permission
        mov     r10d, MMAP_FLAG         ; Flag
        mov     r8d,  -1                ; Fd = -1 (invalid fd)
        xor     r9d,  r9d               ; Offset = 0
        syscall

        cmp     rax, 0                  ; error ?
        jl      .error_mmap

        mov     r13, rax                ; r13 = memory address

        ; create a new child process (thread) using 'clone' syscall
        mov     eax,  56                                ; sys_clone
        mov     edi,  CLONE_FLAGS                       ; flags
        lea     rsi,  [r13 + THREAD_MEM_SIZE - 8]       ; stack address - 8 (8-BYTE to store the function address)
        mov     QWORD [rsi], thread_func                ; set function address
        xor     edx,  edx                               ; parent_tid = NULL (0)
        xor     r10d, r10d                              ; child_tid  = NULL (0)
        xor     r8d,  r8d                               ; tid = 0
        syscall

        cmp     rax, 0          ; error ?
        jle     .error_clone

        ; wait for the created thread to exit using 'wait4' syscall
        mov     rdi, rax        ; created-thread pid
        mov     eax, 61         ; sys_wait4
        xor     esi, esi        ; stat_addr = null (0)
        xor     edx, edx        ; options = 0
        xor     r10d, r10d      ; rusage = 0
        syscall

        ; free the allocated memory (r13) using 'munmap' syscall
        mov     eax, 11                 ; sys_munmap
        mov     rdi, r13                ; memory address
        mov     esi, THREAD_MEM_SIZE    ; memory size
        syscall

        ; exit (return 0 (success))
        mov     eax, 60         ; sys_exit
        xor     edi, edi        ; return 0
        syscall

.error_mmap:
        ; set error message to print
        mov     rsi, .mmap_failed_msg           ; error message
        mov     edx, .mmap_failed_msg_len       ; error message length
        jmp     short .error

.error_clone:
        ; free the allocated memory (r13) using 'munmap' syscall
        mov     eax, 11                 ; sys_munmap
        mov     rdi, r13                ; memory address
        mov     esi, THREAD_MEM_SIZE    ; memory size
        syscall

.error:
        ; print error message
        mov     eax, 1          ; sys_write
        xor     edi, edi        ; stdout (0)
        syscall

        ; exit (return 1 (error))
        mov     eax, 60         ; sys_exit
        mov     edi, 1          ; return 1
        syscall

.mmap_failed_msg db 'Memory allocation failed', 0x0a, 0x00
.mmap_failed_msg_len = $ - .mmap_failed_msg

.clone_failed_msg db 'Unable to create a new child process', 0x0a, 0x00
.clone_failed_msg_len = $ - .clone_failed_msg

thread_func:

        ; print message
        mov     eax, 1                  ; sys_write
        xor     edi, edi                ; stdout (0)
        mov     rsi, .message           ; message address
        mov     edx, .message_len       ; message length
        syscall

        ; exit (return 0 (success))
        mov     eax, 60         ; sys_exit
        xor     edi, edi        ; return 0
        syscall

        .message db 'Child process is called', 0x0a, 0x00
        .message_len = $ - .message   

一切正常!!!!但是当我运行这个程序时,我什么也得不到!!!!没有“调用子进程”消息打印!事实上,我认为我的线程函数没有运行...... 我也进行了 strace 测试,结果如下!!!

trace -f ./thread_linux_x64

execve("./thread_linux_x64", ["./thread_linux_x64"], 0x7fffd4db1b58 /* 53 vars */) = 0
mmap(NULL, 1024, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f32ba3e4000
clone(child_stack=0x7f32ba3e43f8, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_PARENT|CLONE_THREAD|CLONE_IOstrace: Process 32064 attached
) = 32064
[pid 32064] munmap(0x7f32ba3e4000, 1024 <unfinished ...>
[pid 32063] wait4(32064, NULL, 0, NULL) = -1 ECHILD (No child processes)
[pid 32064] <... munmap resumed>)       = 0
[pid 32063] munmap(0x7f32ba3e4000, 1024 <unfinished ...>
[pid 32064] write(0, "", 0 <unfinished ...>
[pid 32063] <... munmap resumed>)       = 0
[pid 32063] exit(0 <unfinished ...>
[pid 32064] <... write resumed>)        = 0
[pid 32063] <... exit resumed>)         = ?
[pid 32064] exit(1)                     = ?
[pid 32064] +++ exited with 1 +++
+++ exited with 0 +++

这个问题快把我逼疯了!因为没有错误......一切看起来都很好!!!!

更新:

在这里我更改了我的源代码以创建线程而不调用 thread_create 或 ... 函数(在主函数中) 现在我的问题解决了......事实上,'thread_func'现在被调用了,但我有一个新问题!我得到段失败!!!!我认为是关于我的 CLONE_FLAGS !!!!

FORMAT  ELF64 EXECUTABLE
ENTRY   thread_linux_x64

THREAD_MEM_SIZE = 1024

define PROT_READ        0x1
define PROT_WRITE       0x2
define PROT_EXEC        0x4

define MAP_PRIVATE      0x02
define MAP_ANONYMOUS    0x20

define CLONE_VM         0x00000100
define CLONE_FS         0x00000200
define CLONE_FILES      0x00000400
define CLONE_SIGHAND    0x00000800
define CLONE_PARENT     0x00008000
define CLONE_THREAD     0x00010000
define CLONE_IO         0x80000000

CLONE_FLAGS = CLONE_VM OR CLONE_FS OR CLONE_FILES OR CLONE_SIGHAND OR CLONE_PARENT OR CLONE_THREAD OR CLONE_IO

MMAP_FLAG       = MAP_PRIVATE OR MAP_ANONYMOUS
MMAP_PERMISSION = PROT_READ OR PROT_WRITE OR PROT_EXEC

SEGMENT READABLE EXECUTABLE
thread_linux_x64:

        ; Memory allocation using 'mmap' syscall (sys_mmap (9))
        mov     eax, 9                  ; sys_mmap
        xor     edi, edi                ; addr = 0 (NULL)
        mov     esi, THREAD_MEM_SIZE    ; Memory allocation size
        mov     edx, MMAP_PERMISSION    ; Permission (PROT_READ, ...)
        mov     r10d, MMAP_FLAG         ; Flag (MAP_PRIVATE, ...)
        mov     r8d, -1                 ; File descriptor (Fd) = -1 (invalid File descriptor)
        xor     r9d, r9d                ; Offset = 0
        syscall

        test    rax, rax                ; ERROR ?
        jl      .error_mmap

        mov     r13, rax                ; R13 = Memory address (RAX)

        ; Create a new child process (thread) using 'clone' syscall (sys_clone (56))
        mov     eax, 56                                 ; sys_clone
        mov     edi, CLONE_FLAGS                        ; Flag (CLONE_VM, ...)
        lea     rsi, [r13 + THREAD_MEM_SIZE - 16]       ; End of the stack - 16 (8-BYTE to store the function address and 8-BYTE to store the data (parameter) address)
        mov     qword [rsi], thread_func                ; Set thread function
        mov     qword [rsi+8], 0                        ; No data (parameter = NULL)
        xor     edx, edx                                ; * parent_tid = NULL (0)
        xor     r10d, r10d                              ; * child_tid  = NULL (0)
        xor     r8d, r8d                                ; tid = 0
        syscall

        test    rax, rax                ; pid == 0 ? | pid < 0 ?
        jg      short .parent_continue  ; parent !
        jl      .error_clone            ; ERROR !

        ; *** CHILD PROCESS ***
        ret                             ; by using the 'ret' instruction, we called the requested function (thread)
                                        ; because we moved the function address into the stack of child process and
                                        ; by using the 'ret' instruction, we jump to the thread function (thread_func)

.parent_continue:

        ; Wait for the created thread to exit using 'wait4' syscall (sys_wait4 (61))
        mov     rdi, rax        ; TID (Thread id)
        mov     eax, 61         ; sys_wait4
        xor     esi, esi
        xor     edx, edx
        xor     r10d, r10d
        syscall

        ; Free the memory (R13) using 'munmap' syscall (sys_munmap (11))
        mov     eax, 11                         ; sys_munmap
        mov     rdi, r13                        ; Memory address (R13)
        mov     esi, THREAD_MEM_SIZE            ; Memory size
        syscall

        ; Write 'done' message
        mov     eax, 1                  ; sys_write
        xor     edi, edi                ; STDOUT (0)
        mov     rsi, .message           ; Message address
        mov     edx, .message_len       ; Message length
        syscall

        ; exit (return 0)
        mov     eax, 60                 ; sys_exit
        xor     edi, edi                ; return 0
        syscall

.error_mmap:
        ; Set error message to write it to STDOUT
        mov     rsi, .mmap_failed_msg           ; Error message
        mov     edx, .mmap_failed_msg_len       ; Error message length
        jmp     short .error

.error_clone:
        ; Free the memory (R13) using 'munmap' syscall (sys_munmap (11))
        mov     eax, 11                         ; sys_munmap
        mov     rdi, r13                        ; Memory address (R13)
        mov     esi, THREAD_MEM_SIZE            ; Memory size
        syscall

        ; Set error message to write it to STDOUT
        mov     rsi, .clone_failed_msg          ; Error message
        mov     edx, .clone_failed_msg_len      ; Error message length

.error:
        ; Write error message to STDOUT
        mov     eax, 1          ; sys_write
        xor     edi, edi        ; STDOUT (0)
        syscall

        ; exit (return 1 (error))
        mov     eax, 60         ; sys_exit
        mov     edi, 1          ; return 1
        syscall

.message db 'Child process is terminated', 0x0a, 0x00
.message_len = $ - .message

.mmap_failed_msg db 'Memory allocation failed', 0x0a, 0x00
.mmap_failed_msg_len = $ - .mmap_failed_msg

.clone_failed_msg db 'Unable to create a new child process', 0x0a, 0x00
.clone_failed_msg_len = $ - .clone_failed_msg

thread_func:

        ; Write message from child process
        mov     eax, 1                  ; sys_write
        xor     edi, edi                ; STDOUT (0)
        mov     rsi, .message           ; Message address
        mov     edx, .message_len       ; Message length
        syscall

        ; exit (return 0)
        mov     eax, 60                 ; sys_exit
        xor     edi, edi                ; return 0
        syscall

.message db 'Child process is called', 0x0a, 0x00
.message_len = $ - .message

在这里,一切看起来都很好!但这是函数结果 ->
子进程终止
分段错误(核心转储)

但有时我也会得到这个!!!!!!!!!
调用子进程
子进程终止

有时我也会这样 !!!!!!!!!!!!!!!!!!
子进程被终止
子进程被调用

但 100% 存在问题,因为“分段错误”!!!!有什么问题?

strace

execve("./thread_linux_x64", ["./thread_linux_x64"], 0x7fff7cc37508 /* 53 vars */) = 0
mmap(NULL, 1024, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1f8b97b000
clone(child_stack=0x7f1f8b97b3f0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_PARENT|CLONE_THREAD|CLONE_IOstrace: Process 3131 attached
) = 3131
[pid  3131] write(0, "Child process is called\n\0", 25 <unfinished ...>
Child process is called
[pid  3130] wait4(3131,  <unfinished ...>
[pid  3131] <... write resumed>)        = 25
[pid  3130] <... wait4 resumed>NULL, 0, NULL) = -1 ECHILD (No child processes)
[pid  3131] exit(0 <unfinished ...>
[pid  3130] munmap(0x7f1f8b97b000, 1024 <unfinished ...>
[pid  3131] <... exit resumed>)         = ?
[pid  3130] <... munmap resumed>)       = 0
[pid  3131] +++ exited with 0 +++
write(0, "Child process is terminated\n\0", 29Child process is terminated
) = 29
exit(0)                                 = ?
+++ exited with 0 +++

C-PTHREAD 示例

这是带有 pthread 的 C 源代码:

#include <stdio.h>
#include <pthread.h>
#include <bits/signum.h>

void * thread_func(void * arg) {
    const char msg[] = "Child-> HELLO\n";
    asm volatile ("syscall"
    :: "a" (1), "D" (0), "S" (msg), "d" (sizeof(msg) - 1)
    : "rcx", "r11", "memory");
    return 0;
}

int
main() {
    pthread_t pthread;
    const char msg1[] = "Parent-> HELLO\n";
    const char msg2[] = "Parent-> BYE\n";

    asm volatile ("syscall"
    :: "a" (1), "D" (0), "S" (msg1), "d" (sizeof(msg1) - 1)
    : "rcx", "r11", "memory");

    pthread_create(& pthread, NULL, thread_func, NULL);
    pthread_join(pthread, NULL);

    asm volatile ("syscall"
    :: "a" (1), "D" (0), "S" (msg2), "d" (sizeof(msg2) - 1)
    : "rcx", "r11", "memory");

    return 0;
}

这个strace是:

mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8c296d3000
arch_prctl(ARCH_SET_FS, 0x7f8c296d3740) = 0
mprotect(0x7f8c29895000, 12288, PROT_READ) = 0
mprotect(0x7f8c298bb000, 4096, PROT_READ) = 0
mprotect(0x403000, 4096, PROT_READ)     = 0
mprotect(0x7f8c29906000, 4096, PROT_READ) = 0
munmap(0x7f8c298c3000, 98201)           = 0
set_tid_address(0x7f8c296d3a10)         = 10122
set_robust_list(0x7f8c296d3a20, 24)     = 0
rt_sigaction(SIGRTMIN, {sa_handler=0x7f8c298a6c50, sa_mask=[], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7f8c298b3b20}, NULL, 8) = 0
rt_sigaction(SIGRT_1, {sa_handler=0x7f8c298a6cf0, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART|SA_SIGINFO, sa_restorer=0x7f8c298b3b20}, NULL, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
write(0, "Parent-> HELLO\n", 15Parent-> HELLO
)        = 15
mmap(NULL, 8392704, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7f8c28ed2000
mprotect(0x7f8c28ed3000, 8388608, PROT_READ|PROT_WRITE) = 0
brk(NULL)                               = 0x13d2000
brk(0x13f3000)                          = 0x13f3000
brk(NULL)                               = 0x13f3000
clone(child_stack=0x7f8c296d1fb0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tid=[10123], tls=0x7f8c296d2700, child_tidptr=0x7f8c296d29d0) = 10123
futex(0x7f8c296d29d0, FUTEX_WAIT, 10123, NULLstrace: Process 10123 attached
 <unfinished ...>
[pid 10123] set_robust_list(0x7f8c296d29e0, 24) = 0
[pid 10123] write(0, "Child-> HELLO\n", 14Child-> HELLO
) = 14
[pid 10123] madvise(0x7f8c28ed2000, 8368128, MADV_DONTNEED) = 0
[pid 10123] exit(0)                     = ?
[pid 10122] <... futex resumed>)        = 0
[pid 10123] +++ exited with 0 +++
write(0, "Parent-> BYE\n", 13Parent-> BYE
)          = 13
exit_group(0)                           = ?
+++ exited with 0 +++

如果我们在 C 中使用 clone 和 wait 函数,我们将有 'wait4' 系统调用......甚至在我的 'wait' 系统调用中,子 ID 是正确的 !!!!!!!!!!!!所以应该没问题!

C 克隆示例

#define _GNU_SOURCE
#include <sched.h>

#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <wait.h>

#define MEM_SIZE        1024

#define CLONE_FLAGS     (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_PARENT | CLONE_THREAD | CLONE_IO)

int
thread_func(void * data) {
    static const char msg[] = "Hello from Child process\n";

    write(0, msg, sizeof(msg)-1);
    exit(0);
}

int
main() {
    static const char msg[] = "Child process is terminated\n";
    void * memory;

    if((memory = mmap(NULL, MEM_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) {
        printf("memory allocation failed\n");
        return 1;
    }

    int pid = clone(thread_func, (memory + MEM_SIZE), CLONE_FLAGS, NULL);
    if(pid < 0) {
        munmap(memory, MEM_SIZE);
        printf("clone() failed\n");
        return 1;
    }

    waitpid(pid, NULL, 0);

    write(0, msg, sizeof(msg)-1);

    munmap(memory, MEM_SIZE);
    exit(0);
}

有点奇怪!!!!同样的错误(段...)!!!! 即使在 C 示例中,我也会遇到相同的错误!!!!

这是 strace :

mprotect(0x7fd8b4492000, 12288, PROT_READ) = 0
mprotect(0x403000, 4096, PROT_READ)     = 0
mprotect(0x7fd8b44e1000, 4096, PROT_READ) = 0
munmap(0x7fd8b449e000, 98201)           = 0
mmap(NULL, 1024, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0) = 0x7fd8b44e0000
clone(child_stack=0x7fd8b44e03f0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_PARENT|CLONE_THREAD|CLONE_IOstrace: Process 19911 attached
) = 19911
[pid 19911] --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_ACCERR, si_addr=0x7fd8b44df9c0} ---
[pid 19910] wait4(19911,  <unfinished ...>) = ?
[pid 19911] +++ killed by SIGSEGV (core dumped) +++
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)

【问题讨论】:

  • 我们上次已经在 cmets 中回答了这个问题。原始的clone 系统调用不会从内存中读取函数指针。 必须自己使用在子线程/进程中运行的代码来执行此操作。相反,您让两个线程都运行 wait4munmapexit
  • 你之前的问题去哪儿了?你把它和回答它的 cmets 一起删除了吗?
  • 不,它没有被删除....但是如果您查看链接,他们将线程函数地址放在堆栈顶部,并且没有直接调用线程函数!!!其实它接缝clone调用函数!
  • 是的,glibc 的clone 包装器确实保存了一个函数指针并在子线程中调用它。
  • 哪个指令段错误?你确定你的wait4 系统调用是正确的吗?如果它在没有等待的情况下立即返回,与ret 竞争的 munmap 将解释段错误并获得两个订单。使用strace 调试您的代码。

标签: linux assembly x86-64 system-calls fasm


【解决方案1】:

我们已经在 cmets last time you asked 中回答了这个问题。原始的 clone 系统调用不会为您从内存中读取函数指针。

必须自己使用在子线程/进程中运行的代码来执行此操作。相反,您让两个线程继续运行wait4munmapexit

clone(2) 手册页对此进行了说明。该页面的主要部分记录了 glibc 包装器,该包装器采用函数指针在子线程中调用。但它清楚地表明这 不是 原始系统调用,请参阅 NOTES 部分。在那里你会找到原始 asm 系统调用的原型和文档:

long raw_clone(unsigned long flags, void *stack,
                        int *parent_tid, int *child_tid,
                        unsigned long tls);

原始的clone() 系统调用更接近于fork(2) 子进程的执行从调用点继续。 这样,clone() 包装函数的 fn 和 arg 参数是 省略。

您可以使用新堆栈作为一个方便的位置来存储函数指针,新线程的用户空间代码可以在其中找到它。 (新线程将无法轻松访问主线程的堆栈,因为 RSP 将指向其新堆栈;我不确定在进入新线程之前是否将 RAX 以外的寄存器归零。如果没有,您可以轻松只需将指针保存在 RAX、RCX 或 R11 以外的寄存器中即可。当然静态存储也是可用的,但您不需要使用它。)

您需要在返回值 0 上进行分支,这表明您处于子进程中。 (与 fork 一样,clone 在成功时返回两次:一次在具有 TID 的父级中,一次在具有 0 的子级中。我认为这是真的;手册页没有清楚地记录这部分,但这就是 fork 的工作原理)


正如 cmets 中所讨论的,link2 将函数地址存储在子线程堆栈中。当父级从包装函数返回时,它会正常返回。当孩子返回时,它将从现在的堆栈中弹出那个地址。

您选择使用仅在子进程中运行的ret 来实现它;没关系。您可以将 jmp 与寄存器或内存中的指针一起使用。


re:更新问题:

您的 wait4 系统调用正在返回 -1 ECHILD 而无需实际等待。

因此,您的 retmunmap 竞争,这将取消映射线程堆栈,如果 munmap 先发生,则会导致段错误。这也解释了您的输出在不崩溃时以不同的顺序发生。

我不确切知道正确的解决方案是什么,但显然不是这样。看看pthread_join 使用什么来等待子线程退出。也许clone 返回值实际上并不是与wait4 一起使用的正确值,或者wait4 不是正确的系统调用。

int *child_tid 输出指针的存在可能是有原因的,尽管可能只是这样父母和孩子都可以在没有 gettid 系统调用或 VDSO 调用的情况下获得它。)

或者可能是因为你没有通过__WCLONE__WALL 得到wait4 等待clone 孩子。

阅读您使用的系统调用的手册页,尤其是当 strace 显示它们没有按照您的预期执行时。这是调试/问题解决技术的第 2 步,在确定系统调用之后首先返回一个错误(strace)。

【讨论】:

  • 我读了你的答案......但我还是很困惑! ...请检查链接2 ...链接2中的人,没有调用线程函数...他只是使用“克隆”系统调用创建了线程,然后没有线程函数调用!!!请检查并告诉我他是否错了
  • @ELHASKSERVERS:这看起来像一个聪明的黑客,使用ret 跳转到新线程函数。子线程中的ret 在新线程堆栈上运行,从新线程堆栈的顶部弹出一个“返回地址”,并将其存储在[rax + STACK_SIZE - 8] 中。这就是push rdi 的全部意义,然后弹出到该包装函数内的内存目标。 (另一个关键是它是一个以ret 结尾的函数,与您的代码不同。)
  • 所以你告诉我在'thread_create'标签中,当我们执行系统调用(克隆)时,在系统调用之后,我们的rsp等于提供的堆栈(rsi)?并通过调用'ret',我们移动到线程函数?
  • @ELHASKSERVERS:原始系统调用有一个stack 参数,所以是的,我假设内核将子线程的堆栈指针设置为指向给定地址。如果内核将其留给用户空间,您将遇到信号处理程序的竞争条件。如果您不确定,请使用 GDB 单步执行来自 link2 的代码。 (我认为 GDB 可以选择停止新创建的线程,否则在该系统调用之后设置断点)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-05
  • 2013-12-18
  • 2021-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多