为什么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=RIP
和
R11=RFLAGS
并不是巧合
。
这种情况的唯一方法是,如果
ptrace
系统调用在内核中修改了进程保存的
rcx
或
r11
值。
(
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
所以即使用户空间使用了std
,rep 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个字节的开头的指针?