i386 和 x86-64 架构下 UNIX & Linux 系统调用的调用约定是什么?
系统调用是应用程序和 Linux 内核之间的基本接口。当一个 Unix/Linux 程序进行文件 I/O、网络数据传输或调用直接或间接与底层指令交互的某些进程时,就会涉及系统调用。进行这些调用通常涉及使用名为 **glibc** 的库,其中包含这些函数。
示例
以下是一些常用系统调用及其用途的列表。
序号 | 系统调用 | 用途 |
---|---|---|
1 | chmod | 更改文件权限 |
2 | chdir | 更改工作目录 |
3 | fork | 创建子进程 |
4 | unlink | 删除名称,并可能删除它所引用的文件 |
系统程序员编写的程序不会直接进行系统调用,而是只会指定要使用的系统调用。这涉及使用取决于内核所在系统硬件架构的调用约定。因此,不同的架构具有不同的调用约定。
调用约定是在实现级别上设计子程序如何从调用者接收参数以及如何返回结果。各种实现的差异包括参数、返回值、返回地址和作用域链接的位置(寄存器、堆栈或内存等),以及在调用函数之前进行准备和之后恢复环境的任务如何在调用者和被调用者之间分配。
调用约定差异
以下是描述调用约定在不同架构之间如何变化的一些场景列表。
- 被调用函数必须为调用者保留哪些寄存器。
- 调用函数之前和之后进行设置和清理的任务如何在调用者和被调用者之间分配。
- 返回值如何从被调用者传递回调用者——在堆栈上、在寄存器中或在堆中。
- 参数、返回值和返回地址放置的位置。
- 传递形式参数的实际参数的顺序。
比较 x86-32 和 x86-64 位
单个 CPU 架构总是有多个可能的调用约定,但业界已就不同生产商的架构达成了一些通用方法。32 位架构有 32 个寄存器,而 x64 将 x86 的 8 个通用寄存器扩展为 64 位。因此,调用约定的实现存在差异。以下是这两种架构之间主要调用约定的比较。
x-86 32位 | x-86 64位 |
---|---|
用于系统调用的寄存器为:%ebx、%ecx、%edx、%esi、%edi、%ebp | 用于系统调用的寄存器为:%rdi、%rsi、%rdx、%r10、%r8 和 %r9 |
使用 PUSH 机制在堆栈上传递参数。如果参数超过六个,%ebx 必须包含存储参数列表的内存位置。 | 系统调用最多只能有六个参数。如果超过 6 个 INTEGER 参数,则第 7 个 INTEGER 参数及以后的参数将通过堆栈传递。 |
返回值存储在 %eax 寄存器中。 | 返回值存储在 %rax 寄存器中。 |
在 x86-32 中,参数通过堆栈传递。最后一个参数首先压入堆栈,直到所有参数都完成,然后执行调用指令。 | 首先将参数划分为几类。每个参数的类别决定它传递给被调用函数的方式。 |
32 位 int ABI(应用程序二进制接口)可在 64 位代码中使用。 | 64 位 ABI 调用不能在 32 位系统中使用。 |
广告