为什么Assembly x86_64系统调用参数不像i386那样按字母顺序排列

2023-12-01

有一个问题困扰着我。

那么...为什么在x86_32 the 参数在我认为在的寄存器中传递按字母顺序 (eax, ecx, edx, esi) and ranked order (esi, edi, ebp)

+---------+------+------+------+------+------+------+
| syscall | arg0 | arg1 | arg2 | arg3 | arg4 | arg5 |
+---------+------+------+------+------+------+------+
|   %eax  | %ebx | %ecx | %edx | %esi | %edi | %ebp |
+---------+------+------+------+------+------+------+

section .text
    global _start
_start:
    mov eax, 1     ; x86_64 opcode for sys_exit
    mov ebx, 0     ; first argument
    int 0x80

而在x86_64syscall的参数是在看起来有点像的寄存器中传递的randomly安排:

+---------+------+------+------+------+------+------+
| syscall | arg0 | arg1 | arg2 | arg3 | arg4 | arg5 |
+---------+------+------+------+------+------+------+
|   %rax  | %rdi | %rsi | %rdx | %r10 | %r8  | %r9  |
+---------+------+------+------+------+------+------+

section .text
    global _start
_start:
    mov eax, 1     ; x86_64 opcode for sys_exit
    mov edi, 0     ; first argument
    syscall

他们这样做是出于特定原因吗?我在这里没有看到什么吗?


x86-64 System V ABI 旨在最大限度地减少由第一批 AMD64 CPU 销售之前的 gcc 版本编译的 SPECint 中的指令数(以及一定程度的代码大小)。看这是一些历史记录和列表存档链接的答案.

从 5 分钟前开始,我认为所有寄存器都是相同的,但由于约定,它们的使用方式有所不同。现在一切对我来说都改变了

x86-64 不是完全正交的。某些指令隐式使用特定寄存器。例如push隐含地使用rsp作为堆栈指针,shl edx, cl仅适用于班次计数cl(直到BMI2shlx).

更很少使用:加宽mul rdi does rdx:rax = rax*rdi。表示字符串指令隐式使用 RDI、RSI 和 RCX,尽管它们通常不值得使用。

事实证明,选择参数传递寄存器,以便将其参数传递给 memcpy 的函数可以将其内联为rep movs在 Jan Hubicka 使用的度量中很有用,因此rdi and rsi被选为前两个参数。但那个离开rcx直到第四个参数更好才使用,因为cl可变计数移位需要。 (大多数函数不会碰巧使用它们的第三个参数作为移位计数。)(可能较旧的 GCC 版本内联memcpy or memset as rep movs更积极地;如今对于小型阵列来说,与 SIMD 相比,它通常不值得。)


x86-64 System V ABI 使用与系统调用几乎相同的函数调用约定。这不是巧合:它意味着 libc 包装函数的实现,例如mmap can be:

mmap:
    mov  r10, rcx       ; syscall destroys rcx and r11; 4th arg passed in r10 for syscalls
    mov  eax, __NR_mmap
    syscall

    cmp  rax, -4096
    ja  .set_errno_and_stuff
    ret

这是一个微小的优势,但确实没有理由not去做这个。它还会在内核中保存一些设置 arg 传递寄存器的指令,然后再分派到内核中系统调用的 C 实现。 (看这个答案查看系统调用处理的一些内核端。主要是关于int 0x80处理程序,但我想我提到了 64 位syscall处理程序并直接从 asm 分派到函数表。)

The syscall指令本身摧毁 RCX 和 R11(为了保存用户空间 RIP 和 RFLAGS,而不需要微代码来设置内核堆栈)因此约定不能相同,除非用户空间约定避免了 RCX 和 R11。但 RCX 是一个方便的寄存器,其低半部分可以在没有 REX 前缀的情况下使用,因此这可能比将其保留为像 R11 这样的被调用破坏的纯暂存器更糟糕。此外,用户空间约定使用 R10 作为具有一流嵌套函数(不是 C/C++)的语言的“静态链”指针。

让前 4 个参数能够避免 REX 前缀可能最适合整体代码大小,并且使用 RBX 或 RBP 而不是 RCX 会很奇怪。有几个不需要 REX 前缀 (EBX/EBP) 的调用保留寄存器是很好的。

See i386 和 x86-64 上的 UNIX 和 Linux 系统调用的调用约定是什么用于函数调用和系统调用约定。


i386 系统调用约定是一种笨重且不方便的约定: ebx是调用保留的,因此几乎每个系统调用包装器都需要保存/恢复ebx,除了没有参数的调用,例如getpid。 (为此,您甚至不需要进入内核,只需调用 vDSO:请参阅Linux 系统调用权威指南(在 x86 上)了解有关 vDSO 和大量其他内容的更多信息。)

但是 i386 函数调用约定传递堆栈上的所有参数,因此 glibc 包装函数仍然需要mov无论如何,每个参数。

另请注意,x86 寄存器的“自然”顺序是 EAX、ECX、EDX、EBX,根据它们在机器代码中的数字代码,以及pusha / popa使用。看为什么前四个 x86 GPR 的命名顺序如此不直观?.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么Assembly x86_64系统调用参数不像i386那样按字母顺序排列 的相关文章

  • 如何在 Debian 上编译 DOS 程序?

    在我的汇编语言课程中 我们使用 DPMI 编写 DOS 程序 不幸的是 我无法一直使用 32 位 Windows 机器 我在我使用的几乎每台计算机上都安装了 Debian 虚拟机 我已经安装了 DOSBox 和 DOSEMU 有什么办法可以
  • “mov (%ebx,%eax,4),%eax”如何工作? [复制]

    这个问题在这里已经有答案了 一直在从事装配作业 并且在很大程度上我对装配非常了解 或者至少对于这项任务来说足够好 但这个 mov 的声明让我很困惑 如果有人能解释这个 mov 语句如何操作寄存器值 我将非常感激 mov ebx eax 4
  • 程序集比较标志理解

    我正在努力理解汇编程序中的以下代码片段 if EAX gt 5 EBX 1 else EBX 2 在汇编程序中 可以写如下 根据我的书 模拟jge操作说明 https www felixcloutier com x86 jcc您通常会使用
  • 这个反斜杠在这段汇编代码中起什么作用?

    我不确定这些推线有什么区别 修剪下来来自 Linux 的 x86 entry calling h https github com torvalds linux blob 241e39004581475b2802cd63c111fec43b
  • 如何编译GCC生成的asm?

    我正在玩一些汇编代码 有些事情困扰着我 我编译这个 include
  • 是否可以在VM内使用VMX CPU指令?

    VM guest 内部的进程是否有可能使用 VMX AMD V VT x CPU 指令 然后由外部 VMM 处理而不是直接在 CPU 上处理 Edit 假设外部VM使用VMX本身来管理其虚拟客户机 即它在Ring 1中运行 如果可能的话 是
  • Visual Studio 2012 本机 C++ DLL x86 编译

    我最近将我的工具集从 Win 7 x86 Visual Studio 2010 升级到 Win 8 x64 Visual Studio 2012 但是 现在我的本机 C dll 编译为 x64 而不是 x86 除了将代码移至新操作系统并将其
  • GCC的sqrt()编译后如何工作?使用哪种root方法?牛顿-拉夫森?

    只是对标准感到好奇sqrt 来自 GCC 上的 math h 我自己编码的sqrt 使用牛顿拉夫森来做到这一点 是的 我知道 fsqrt 但CPU是如何做到这一点的呢 我无法调试硬件 现代 CPU 中的典型 div sqrt 硬件使用 2
  • 在 x86 程序集中存储大量布尔值的最佳方法是什么?

    最近我一直在处理充满布尔值的大型数组 目前 我将它们存储在 bss部分有一个 space指令 它允许我创建字节数组 但是 由于我只需要存储布尔值 因此我希望从数组中逐位读取和写入数据 目前 我能想到的最好方法是有一个 space指令所需存储
  • 为什么 Linux perf 使用事件 l1d.replacement 来处理 x86 上的“L1 dcache misses”?

    在英特尔 x86 上 Linux用途 https stackoverflow com a 52172985 149138事件l1d replacements来实施其L1 dcache load misses event 该事件定义如下 计数
  • 从类模板参数为 asm 生成唯一的字符串文字

    我有一个非常特殊的情况 我需要为类模板中声明的变量生成唯一的汇编程序名称 我需要该名称对于类模板的每个实例都是唯一的 并且我需要将其传递给asm关键字 see here https gcc gnu org onlinedocs gcc 12
  • 我们可以拥有一台只用寄存器作为内存的计算机吗? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 寄存器是计算机中最快的存储器 那么如果我们想构建一台只有寄存器甚至没有缓存的计算机 可能吗 我什至考虑用寄存器代替磁盘 尽管它们本质上是易
  • NASM 中的 equ 和 db 有什么区别?

    len equ 2 len db 2 它们是否相同 产生可以用来代替的标签2 如果不是 那么每种申报表的优点或缺点是什么 它们可以互换使用吗 第一个是equate 与 C 类似 define len 2 因为它实际上并没有在最终代码中分配任
  • 为什么X86中没有NAND、NOR和XNOR指令?

    它们是您可以在计算机上执行的最简单的 指令 之一 它们是我亲自实施的第一个指令 执行 NOT AND x y 会使执行时间和依赖链长度和代码大小加倍 BMI1 引入了 andnot 这是一个有意义的补充 是一个独特的操作 为什么不是这个问题
  • 何时可以重用avx指令中的源寄存器

    在 avx 指令中用作源的寄存器何时可以在指令开始处理后重用 例如 我想使用vgatherdps该指令消耗两个 ymm 寄存器 其中之一是位移索引 我意识到vgatherdps由于数据的局部性较差 因此需要花费大量时间来收集 位移索引寄存器
  • 整数溢出问题

    我不断遇到整数溢出问题 我不知道如何解决它 有人可以帮忙吗 edx 包含 181 eax 包含 174 xor eax edx mov edx 2 div edx 假设你谈论的是x86 div edx这实际上没有意义 32位div将edx
  • movzbl(%rdi, %rcx, 1), %ecx 在 x86-64 汇编中意味着什么?

    我想我明白 movzbl rdi rcx 1 ecx 意思是 将零扩展字节移至长整型 并表示将 ecx 扩展为 32 位 但我不完全确定语法 rdi rcx 1 指的是什么 我在某处看到该语法指的是 Base Index Scale 但我找
  • 查找哪些页面不再与写入时复制共享

    假设我在 Linux 中有一个进程 我从中fork 另一个相同的过程 后forking 因为原始进程将开始写入内存 Linux写时复制机制将为进程提供与分叉进程使用的不同的唯一物理内存页 在执行的某个时刻 我如何知道原始进程的哪些页面已被写
  • Intel:序列化指令和分支预测

    英特尔架构开发人员手册 http www intel com content www us en architecture and technology 64 ia 32 architectures software developer v
  • 当前的 x86 架构是否支持非临时加载(来自“正常”内存)?

    我知道有关此主题的多个问题 但是 我没有看到任何明确的答案或任何基准测量 因此 我创建了一个处理两个整数数组的简单程序 第一个数组a非常大 64 MB 第二个数组b很小 无法放入 L1 缓存 程序迭代a并将其元素添加到相应的元素中b在模块化

随机推荐

  • 代码可以在 Chrome 中运行,但不能在 Firefox 中运行

    以下代码适用于 Chrome 但在 Firefox 中 提交步骤不起作用
  • 如何在mgo(Go)中使用接口类型作为模型?

    假设您有一个由多个不同类型的嵌入节点组成的工作流程 由于节点的类型不同 我想到这里使用 Golang 接口并提出以下方案 type Workflow struct CreatedAt time Time StartedAt time Tim
  • Django 错误地期望 id 列

    我正在 Django 中使用现有的 SQL 数据库 由于某种原因 这些表从未被赋予主键 因此我只是浏览并为其分配主键 在其中一个模型中 我使用以下命令将现有唯一索引更改为主索引primary key True 然后我跑了 manage py
  • 文本框未重置

    我有一个文本框 我尝试在单击按钮后重置它 但它没有被重置 HTML 脚本
  • 在元组列表列表中查找重复项 Python

    我想从下面给定的列表中找到匹配的项目 我的列表可能非常大 元组 N1 10 中的第一项被复制并与另一个数组中的另一项匹配 ListA 中第一个数组中的元组 N1 10 N2 28 ListA 中第二个数组中的元组 N1 10 N3 98 L
  • 如何设置 UIImageView 的大小等于 UIImage 的大小?

    我有一个视图控制器UIImageView named someImageView 该图像视图没有默认值UIImage 我正在加载UIImage与下面的代码 UIImage myImage UIImage imageNamed sampleI
  • 如何在 Org 模式下将 csquotes 与 LaTeX 导出一起使用?

    使用时csquotes引号由 csquotes 根据上下文添加 这是通过用以下标记来完成的 enquote宏 即 enquote text 从 Org 模式导出到 LaTeX 时 引号标记为 and 例如作为 text 可以 Org mod
  • 如何在Android Google Analytics V4中获取clientId?

    我正在尝试在 Android 中获取自动设置的 Analytics clientId Android API 文档中对其设置的解释为setClientId 当我尝试使用时tracker get clientId 它返回空 有人有什么想法吗
  • 名称“File”在库“dart:html”和“dart:io”中定义

    有谁知道如何解决这个错误 这是我的代码 导入错误位于 文件 中 错误如下 名称 File 在库 dart html 和 dart io 中定义 override State createState gt ChatScreenState re
  • 如何在用户可见之前将 UITableView 滚动到所需的行?

    我想知道是否可以滚动UITableView到所需的行 甚至在用户可见之前 这样用户就不会意识到这种滚动操作 目前 这是我执行滚动到所需行的代码 class ThemeTableViewController UITableViewContro
  • java.lang.SecurityException:没有签名文件条目的清单部分

    我已经尝试过其他线程中的建议 但它们对我没有帮助 当我运行我的罐子时java jar BigJar jar我收到异常 Exception in thread main java lang SecurityException no manif
  • iOS Facebook 图书馆登录

    我刚刚通过此 URL 下载了适用于 iOS 的 facebook 库https github com facebook facebook ios sdk 我设法很好地运行示例应用程序 但是 当我单击登录按钮时 它实际上在浏览器中打开登录屏幕
  • Cron 作业未运行(在开发中)

    我已经指定了一个 cron 作业 用于在开发中进行测试 但它似乎没有运行 如何确保这些工作能够在生产中发挥作用 cron yaml cron description cron test gathering url test cron sch
  • scipy rv_连续非常慢

    我正在使用自定义函数f x 使用定义自定义分布copy s rv continuous班级 我的代码是 class my pdf gen rv continuous def pdf self x integral return f x in
  • 以透视方式绘制一系列 3D 投影的 2D 绘图

    我想绘制一个似然分布 基本上是NxT矩阵 其中每行代表每个时间步中某个变量的分布t t 0 T 这样我就可以可视化最大似然估计产生的轨迹 我想象了几个 2D 图 一个在另一个之前 如下所示 到目前为止基于this我试过了 def Traje
  • 如何调整 AVFrame 的大小?

    如何调整大小AVFrame I 这是我目前正在做的事情 AVFrame frame int width 600 height 400 AVFrame resizedFrame av frame alloc auto format AVPix
  • 从 Spring Boot 控制器返回 JAXB 生成的元素

    我正在生成大量 Java 文件http www ncpdp org的 XSD 文件 仅会员可用 生成它们后 我想在 Spring 控制器中使用它们 但在将响应转换为 XML 时遇到问题 我尝试返回元素本身以及 JAXBElement 但似乎
  • 如何将背景图像与猫头鹰轮播一起使用

    我想用猫头鹰旋转木马与背景图像而不是 img 标签 如使用http driveshift com car c10148 但是 插件站点中包含的每个示例都使用img tags 当您检查Shiftcarousel 它使用 url 图像作为 da
  • Java线程池[关闭]

    Closed 这个问题不符合堆栈溢出指南 目前不接受答案 我想学习用Java写一个线程池 有人能给我指出有用的资源吗 看看 Doug Lea 的书 它们现在已经相当老了 除非他发布了新书 不确定 但是 1 5 中添加的并发包是基于他的线程库
  • 为什么Assembly x86_64系统调用参数不像i386那样按字母顺序排列

    有一个问题困扰着我 那么 为什么在x86 32 the 参数在我认为在的寄存器中传递按字母顺序 eax ecx edx esi and ranked order esi edi ebp syscall arg0 arg1 arg2 arg3