当前位置: 首页 > 面试题库 >

为什么x86-64 Linux系统调用会修改RCX,值是什么意思?

阳文轩
2023-03-14
问题内容

我正在尝试使用sys_brksyscall 在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_brksyscall
后注意到以下寄存器内容

在系统调用之前

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在这种情况下,我不太了解寄存器中的值。哪个指针可以用作我分配给它的8个字节的开头的指针sys_brk


问题答案:

系统调用返回值rax始终位于中。请参阅i386和x86-64上的UNIX&Linux系统调用的调用约定是什么]。

注意,sys_brk其接口与brk/sbrkPOSIX函数略有不同;请参见Linuxbrk(2)手册页的C库/内核差异部分。具体来说, Linuxsys_brk 设置
程序中断
;arg和返回值都是指针。请参阅Assemblyx86brk()调用use。该答案需要投票,因为这是该问题上唯一的好答案。

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

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

您正在了解syscall/
sysret指令的设计原理,以允许内核恢复用户空间执行,但仍然很快。

syscall不进行任何加载或存储,仅修改寄存器。与其使用特殊的寄存器来保存返回地址,不如使用常规的整数寄存器。

这不是一个巧合,RCX=RIPR11=RFLAGS内核返回到用户空间的代码之后。唯一的解决办法是,如果系统调用在内核内部修改了该进程的保存或值,则该调用
不起作用
。(是gdb使用的系统调用)。在那种情况下,Linux将使用而不是返回用户空间,因为较慢的一般情况可以做到这一点。(请参阅如果以64位代码使用32位int0x80LinuxABI会发生什么情况?了解Linux系统调用入口点的一些演练。大多数入口点来自32位进程,而不是来自64位进程。一点点的过程。)ptrace``rcx``r11``ptrace``iret``sysret``iret)syscall

与其将返回地址压入内核堆栈(就像这样int 0x80做), syscall 不如:

  • 设置RCX = RIP,R11 = RFLAGS(因此内核在执行之前甚至无法看到这些reg的原始值syscall)。
  • 掩模RFLAGS从一个配置寄存器中(预先配置的掩模IA32_FMASKMSR)。这使内核可以禁用中断(IF),直到完成swapgs并设置rsp为指向内核堆栈为止。即使cli作为入口点的第一条指令,也存在一个漏洞窗口。即使cld掩盖了DFso rep movs/ up,您也可以免费获得,stos即使使用了user space std

有趣的事实:AMD的第一个提议syscall/swapgs设计并未掩盖RFLAGS,但在内核开发人员在amd64邮件列表上](大约在2000年,比第一个芯片问世几年之前)反馈后,他们对其进行了更改。

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

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

因此,的设计syscall需要系统调用ABI来注册,这就是为什么值就是它们的原因。



 类似资料:
  • 在UNIX中,我应该编写一个Java文件,将“exit 1”打印到标准错误,然后以1的状态退出。 这是我的方法。 如果是,我应该如何在Unix shell中使用它?当我在bash中编译并运行它时,它只是打印“exit 1”(所以它做了与System.out.println相同的事情,为什么我要使用“err”?)。这里的“标准误差”是什么?

  • 本文向大家介绍系统调用的目的是什么?,包括了系统调用的目的是什么?的使用技巧和注意事项,需要的朋友参考一下 进程和操作系统之间的接口由系统调用提供。通常,系统调用可用作汇编语言说明。它们也包含在汇编级程序员使用的手册中。通常在用户模式下的进程需要访问资源时进行系统调用。然后,它请求内核通过系统调用提供资源。 通常,在以下情况下需要系统调用- 如果文件系统需要创建或删除文件。从文件读取和写入也需要系

  • 本文向大家介绍C++系统调用是什么,你用过哪些系统调用相关面试题,主要包含被问及C++系统调用是什么,你用过哪些系统调用时的应答技巧和注意事项,需要的朋友参考一下 参考回答: 1)概念: 在计算机中,系统调用(英语:system call),又称为系统呼叫,指运行在使用者空间的程序向操作系统内核请求需要更高权限运行的服务。系统调用提供了用户程序与操作系统之间的接口(即系统调用是用户程序和内核交互的

  • 问题内容: 根据System V X86-64ABI,应用程序中的函数调用使用以下寄存器序列传递整数参数: 但是系统调用参数(而不是系统调用号)在另一个寄存器序列中传递: 为什么内核使用而不是第四个参数?它与当下没有保留的事实有某种联系吗? 问题答案: X86-64系统调用使用说明。该指令将返回地址保存到,然后从MSR 加载。即立即被摧毁。这就是为什么必须替换系统调用ABI的原因。 相同的指令也保

  • 我正在上我的第一堂操作系统课,所以希望我在这里没有任何大的误解。 我想知道为什么getpid()在Linux中实现为系统调用。据我所知,某些函数被做成系统调用,因为它们访问或更改操作系统可能想要保护的信息,所以它们被实现为系统调用,以便将控制权转移到内核。 但据我所知,getpid()只是返回调用进程的进程id。是否存在不授予此信息权限的情况?简单地让getpid()成为一个普通的用户函数不是很安

  • 本文向大家介绍在i386和x86-64上UNIX和Linux系统调用的调用约定是什么,包括了在i386和x86-64上UNIX和Linux系统调用的调用约定是什么的使用技巧和注意事项,需要的朋友参考一下 系统调用是应用程序和Linux内核之间的基本接口。当Unix / Linux程序执行文件I / O,网络数据传输或调用某个与低级指令直接或间接交互的进程时,就会涉及系统调用。进行这些调用通常涉及使