Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么x86-64 Linux系统调用会修改RCX,这个值意味着什么?_Linux_Assembly_X86 64_System Calls - Fatal编程技术网

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

为什么x86-64 Linux系统调用会修改RCX,这个值意味着什么?,linux,assembly,x86-64,system-calls,Linux,Assembly,X86 64,System Calls,我正试图在linux中使用sys\u brksyscall分配一些内存。以下是我尝试过的: 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中运行

我正试图在linux中使用
sys\u brk
syscall分配一些内存。以下是我尝试过的:

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\u brk
syscall之后,我注意到以下寄存器内容

系统调用前

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
rax 0x401000 4198400
rbx 0x0 0

rcx 0x40008c 4194444 系统调用返回值始终在
rax
中。看

请注意,
sys\u brk
brk
/
sbrk
POSIX函数的接口稍有不同;看。具体来说,Linux
sys_brk
设置程序中断
;arg和返回值都是指针。看见这个答案需要投票,因为它是这个问题上唯一的好答案


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

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

您看到了/指令的设计机制,它允许内核恢复用户空间执行,但速度仍然很快

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

在内核返回到用户空间代码后,
RCX=RIP
R11=RFLAGS
不是巧合。如果
ptrace
系统调用在进程位于内核内部时修改了进程保存的
rcx
r11
值,则这种情况就不会发生。(
ptrace
是gdb使用的系统调用)。在这种情况下,Linux将使用
iret
而不是
sysret
返回用户空间,因为较慢的通用情况
iret
可以做到这一点。(有关Linux系统调用入口点的一些介绍,请参阅。大多数入口点来自32位进程,而不是64位进程中的
syscall


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

  • 设置RCX=RIP,R11=RFLAGS(因此在执行
    syscall
    之前,内核甚至不可能看到这些regs的原始值)

  • 使用配置寄存器(IA32_FMASK
MSR)中预先配置的掩码屏蔽
RFLAGS
。这允许内核禁用中断(IF),直到完成
swapgs
并将
rsp
设置为指向内核堆栈。即使将
cli
作为入口点的第一条指令,也会出现漏洞窗口。您还可以通过屏蔽
DF
免费获得
cld
,因此
rep mov
/
stos
即使用户空间使用了
std
,也可以向上移动

有趣的事实:AMD第一次提出的
syscall
/
swapgs
设计没有屏蔽RFLAG,但是(在2000年,第一块硅芯片诞生前的几年)

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

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


  • 因此,
    syscall
    的设计需要一个缓冲寄存器的系统调用ABI,这就是为什么值是这样的。

    RCX和R11被指令本身缓冲。从指令集引用:在将SYSCALL之后的指令地址保存到RCX之后)。RFLAGS被存储到R11@MichaelPetch非常有趣。这意味着为了使用,比如说以后注册,我需要先清除它,对吗?我的意思是,例如
    xor cl,cl
    然后
    mov cl,7
    。在系统调用之后,不能依赖RCX或R11的值。因此,您必须使用其他寄存器中的一个,而不是RCX和R11(以及RAX),或者必须保存值(例如堆栈)并在之后恢复。RCX和R11不是由您设置的,您只是不能使用它们并期望它们在系统调用前后都是相同的。@MichaelPetch但是只清除它们有什么问题?在系统调用之前清除它们会被系统调用覆盖。SYSCALL只会覆盖其中的内容。如果愿意,可以在系统调用之后设置它,但如果执行另一个系统调用,则该值将被删除。