为什么x86-64 Linux系统调用会修改RCX,这个值意味着什么?



assembly system-calls (1)

系统调用返回值一如既往地在 rax 。 请参阅 i386和x86-64上UNIX和Linux系统调用的调用约定是什么

请注意, sys_brk 界面与 brk / sbrk POSIX函数略有不同; 请参阅 Linux brk(2) 手册页 C库/内核差异部分 。 具体来说, Linux sys_brk 设置 程序中断 ; arg和返回值都是指针。 请参阅 Assembly x86 brk()调用 。 这个答案需要upvotes,因为它是这个问题上唯一的好人。

你问题的另一个有趣的部分是:

在这种情况下,我不太了解rcx寄存器中的值

您将看到 syscall / sysret 指令如何设计为允许内核恢复用户空间执行但仍然很快的机制。

syscall 不执行任何加载或存储,它只修改寄存器。 它不使用特殊寄存器来保存返回地址,而只使用常规整数寄存器。

在内核返回到用户空间代码之后, RCX=RIPR11=RFLAGS 并不是巧合 。 这种情况的唯一方法是,如果 ptrace 系统调用在内核中修改了进程保存的 rcxr11 值。 ( ptrace 是gdb使用的系统调用)。 在这种情况下,Linux将使用 iret 而不是 sysret 返回用户空间,因为较慢的通用情况 iret 可以做到这一点。 ( 如果你在64位代码中使用32位int 0x80 Linux ABI会发生什么? 对于Linux系统调用入口点的一些演练。大多数是32位进程的入口点,而不是来自64位系统调用的入口点然而,这是一个过程。)

而不是将返回地址推送到内核堆栈(如 int 0x80 ), syscall

  • 设置RCX = RIP,R11 = RFLAGS(因此在执行 syscall 之前,内核甚至无法查看这些寄存器的原始值)。
  • 使用配置寄存器( IA32_FMASK MSR)中的预配置掩码屏蔽 IA32_FMASK 。 这让内核禁用中断(IF),直到它完成 swapgs 并将 swapgs 设置为指向内核堆栈。 即使将 cli 作为入口点的第一条指令,也会有一个漏洞的窗口。 你也可以通过屏蔽 DF 来免费获得 rep movs 所以即使用户空间使用了 stdrep movs / rep movs 也会向上移动。

    有趣的事实:AMD首次提出的 syscall / swapgs 设计并没有掩盖RFLAGS,但 他们在内核开发人员在amd64邮件列表上的反馈之后 (在〜2000年,第一个芯片之前的几年)改变了它。

  • 跳转到配置的 syscall 入口点(设置CS:RIP = IA32_LSTAR )。 我想,旧的 CS 值不会保存在任何地方。

  • 它没有做任何其他事情,内核必须使用 swapgs 来访问保存内核堆栈指针的信息块,因为 rsp 仍然有来自用户空间的值。

因此, syscall 的设计需要一个系统调用ABI,其中注册符号,这就是为什么这些值是它们的原因。

我正在尝试使用 sys_brk syscall在linux中分配一些内存。 这是我尝试过的:

BYTES_TO_ALLOCATE equ 0x08

section .text
    global _start

_start:
    mov rax, 12
    mov rdi, BYTES_TO_ALLOCATE
    syscall

    mov rax, 60
    syscall

根据linux调用约定,我希望返回值在 rax 寄存器中(指向已分配内存的指针)。 我在gdb中运行它,在进行 sys_brk 系统调用之后,我注意到以下寄存器内容

在系统调用之前

rax            0xc      12
rbx            0x0      0
rcx            0x0      0
rdx            0x0      0
rsi            0x0      0
rdi            0x8      8

在系统调用之后

rax            0x401000 4198400
rbx            0x0      0
rcx            0x40008c 4194444 ; <---- What does this value mean?
rdx            0x0      0
rsi            0x0      0
rdi            0x8      8

在这种情况下,我不太了解 rcx 寄存器中的值。 哪一个用作指向我用 sys_brk 分配的8个字节的开头的指针?





system-calls