【问题标题】:Is %gs caller- or callee-save for the System V AMD64 ABI?System V AMD64 ABI 是 %gs caller-还是 callee-save?
【发布时间】:2021-10-14 01:50:24
【问题描述】:

System V AMD64 ABI 是否说明了段寄存器 %gs?它被认为是调用者保存还是被调用者保存?还是保留?或者还没有为 %gs 定义任何内容?

【问题讨论】:

  • 我想你知道从哪里获取 ABI 文档本身,并且已经在其中搜索了 gs。但没有相关匹配。
  • 请注意,%gs%gs.base 的典型用途是将其设置在某个实用程序函数中,然后在程序的其余部分设置它,直到另行通知,如全局多变的。将其设置为调用者保存或被调用者保存将使该策略变得不可能。无论如何,它肯定不是保留的——我相信它是供程序员使用的。
  • 是的,我没有通过搜索我拥有的 ABI 文档找到它,所以我一直想知道是否真的有任何关于它的说明。我一直在考虑使用它来访问在运行时生成的汇编代码的线程本地数据。 “旨在供程序员使用”的问题在于它使程序或库不可组合。 Callee-save 实际上对我来说是最好的。
  • 至少,我认为您可以放心地假设任何不遵循“被调用者保存”策略的代码,至少在其外部接口处,都需要显着地记录这一事实。跨度>

标签: assembly x86-64 calling-convention abi memory-segmentation


【解决方案1】:

IIRC,调用约定/ABI 根本没有什么好说的。 FS 基础用于 x86-64 System V 上的线程本地存储,但您想对 GS 基础(和/或 GS 段选择器)做的任何事情都可能取决于您来定义你的程序如何使用它。

在调用约定方面,或者更通常在线程生命周期的早期设置一次,之后保持不变。就像 MXCSR 和 x87 舍入模式/精度控制是如何通过让函数保持不变来处理的,除了可能在进行任何进一步调用之前恢复的本地更改。 (这仍然可以描述为调用约定/ABI,但正如 Nate 评论的那样,它既不是保留调用也不是调用破坏。)

我认为 Linux 内核将保存/恢复用户空间的选择器值(也可能是段基础与由非 0 选择器值选择的某些 GDT 或 LDT 条目中的任何内容分开,而是通过系统调用设置为 write MSR,或者通过wrgsbase,如果内核允许它在支持它的硬件上使用用户空间。)如果是这样,那么用户空间将GS用于某些东西是可行的,比如备用TLS。

在实践中,您可以放心地假设调用库中编译器生成的代码(甚至是手写代码)不会改变它。所以你只需要担心系统调用和上下文切换;我建议进行测试。

请注意,mov 到 GS 的值不是 0 或 LDT 或 GDT 条目的有效选择器会出错,因此您可以使用的值集非常有限。

写 GS (Is a mov to a segmentation register slower than a mov to a general purpose register?) 也很慢,虽然读它的效率相当高(P4 除外)。可能比线程本地存储内存位置更有效,尽管 GS 不能作为存储以外的指令的源操作数。


有趣的事实:i386 SysV 使用 GS 进行 TLS;我认为 x86-64 已更改为 FS,因此 kernel-GS(由于 swapgs 而特殊)可能只是用于在 swapgs 之后查找任务的内核堆栈,而不必成为每个内核的内核 TLS 基础变量。

【讨论】:

  • (这不是我的想法;稍后将搜索 ABI PDF,除非在那之前有人可以确认或更正我。)
  • 我在 ABI PDF 中找不到任何内容,但我远不是了解其所有细节的专家。
  • 至于 GS base vs. segment-selector value:我对前者感兴趣。
  • 你说mov到GS很慢。你知道wrgsbase吗?
  • @Marc:我没有,uops.info/table.html 也没有任何信息。如果段基础被重命名,它应该很快(不需要耗尽 ROB);它也不需要触发 GDT 或 LDT 加载并解析条目。但是 OTOH 这是一条罕见的指令(通常每次上下文切换只有几次),因此它不需要进行大量优化。它很可能仍然是多指令的,并且可能比使用 TLS 内存更糟糕。或者,如果幸运的话,在 Intel 和/或 AMD 上可能不会。
猜你喜欢
  • 1970-01-01
  • 2012-09-18
  • 1970-01-01
  • 1970-01-01
  • 2019-12-19
  • 1970-01-01
  • 1970-01-01
  • 2013-08-10
相关资源
最近更新 更多