为什么x86-64 Linux系统调用会修改RCX,这个值意味着什么?
我正试图在linux中使用为什么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中运行
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函数的接口稍有不同;看。具体来说,Linuxsys_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只会覆盖其中的内容。如果愿意,可以在系统调用之后设置它,但如果执行另一个系统调用,则该值将被删除。