assembly 违反macOS的ARM64调用约定的后果

ahy6op9u  于 2022-12-13  发布在  Mac
关注(0)|答案(2)|浏览(206)

我正在将一些AArch 64/ARM 64/Apple Silicon汇编代码从Linux移植到macOS。
此代码使用所有31个可用寄存器(堆栈指针不计算在内)来避免几乎所有溢出情况; Linux调用约定允许我使用那么多寄存器。
如果有人追问,我会承认,溢出一个额外的寄存器(从而使其减少到使用30个寄存器)是可行的,因为性能将受到最小的影响,但如果限制在29个或更少的可用寄存器,性能将受到更大的影响。因此,我真的希望有至少30个可用寄存器,最好是31个。
我刚刚从this官方Apple文档中了解到,除了Linux调用约定所要求的之外,还保留了两个额外的寄存器:
尊重特定CPU寄存器的用途
ARM标准将某些决策委托给平台设计者。Apple平台遵循以下选择:

  • 平台保留寄存器x18。请勿使用此寄存器。
  • 帧指针寄存器(x29)必须始终寻址有效的帧记录。某些函数-例如叶函数或尾部调用-可能选择不在此列表中创建条目。因此,即使没有调试信息,堆栈跟踪也始终有意义。

尽管有这些声明,我的代码在没有它的情况下似乎运行得很好。
现在,我完全理解忽略这样的ABI要求是一件非常糟糕的事情(TM)。然而,我想确切地了解由于使用x18和x29中的每一个,代码可能会如何中断。
例如,通过阅读上面的文档,我的理解是x29是用来支持调试或崩溃转储的。假设我并不特别关心调试这个函数(实际上我并不关心),或者生成的崩溃转储是否有意义。在这种情况下,使用x29有什么坏处吗?
至于x18,你知道它是干什么用的吗?我假设(没有任何证据支持),如果在这段代码运行时执行中断或上下文切换,x18不会被保存,因此一旦它返回,就会破坏我的函数的结果。这将是一个更严重的情况,在这种情况下,我会听从建议不要使用x18。
还要注意,所讨论的代码是一个叶函数,因此中断从其中调用的任何函数都没有问题。

lyfkaqu1

lyfkaqu11#

如果中断的回溯对您来说是可接受的损失,您可以安全地重敲x29
x18则是另一回事。
在macOS上,Rosetta使用了它,所以苹果不可能在不重构它的情况下再把它搞砸。他们还使用have a kernel test来确保x18在“支持它的硬件上”被恢复。到目前为止,这是所有支持arm 64 macOS的硬件,所有支持Apple Silicon的macOS版本都启用了这种行为。
不过在iOS上,有些硬件并不支持它,特别是A11系列芯片和更老的芯片。在这些芯片上,内核配置了__ARM_KERNEL_PROTECT__,这使得Spectre缓解在内核有机会溢出任何寄存器之前,在所有异常处理程序上使用x18 *,甚至异步处理程序 *。所以除非你在关闭中断的情况下运行,你的x18可以在任何时间点被归零。此外,即使在A12和更高版本上,iOS 14. 0之前的iOS版本也确实有意地痛击x18
现在,如果您 checkout 链接测试,您可能会在运行时检查sysctl hw.optional.arm_kernel_protect,但不幸的是,它只在XNU的DEVELOPMENTDEBUG配置上导出。
因此,如果你的目标是iOS,你就不能使用x18。如果你的目标是macOS,那么你暂时可以使用它,但这可能会在未来发生变化。你可以尝试通过做同样的测试来检测这种变化:将x18设置为某个值,调用sched_yield(),然后检查该值。但同样,这依赖于所有异常都将x18视为相同的,虽然它们目前是这样做的,但将来也可能会改变。
| 更新|
| - -|
| macOS 13确实改变了这一点!虽然macOS 11和12会无条件地保留x18,但macOS 13现在有了更复杂的规则。x18现在只为在Rosetta下运行的进程以及针对macOS 12 SDK或更早版本构建的进程保留,或者保留com.apple.private.uexccom.apple.private.custom-x18-abi权限。同样的规则也适用于iOS 16,但需要注意的是,没有Rosetta,你不能运行基于macOS SDK构建的二进制文件。因此,从iOS 16开始,x18必须再次被视为所有设备的禁区。|

hsvhsicv

hsvhsicv2#

我认为,如果你不想工作回溯的话,可以把x29用于任何你喜欢的事情。
当苹果在iOS上推出aarch 64的时候,他们还没有对x18有任何具体的用途,但是他们想保留它,以确保人们不会意外地依赖它。所以当时,内核把x18搞砸了,在每次上下文切换时都把它设置为一些非零的伪值,这样每个人都很清楚你不能使用它。
自从macOS在Apple Silicon上发布以来,他们确实删除了故意破坏这个寄存器的代码。我不确定这是否是因为他们实际上在某个地方找到了寄存器的特定用途(所以他们不能让内核把它打得落花流水),或者只是选择了更好地处理它。(它确实有助于例如用户空间使用Wine模拟Windows可执行文件-在Windows中,x18应该总是指向TEB(线程环境块)的指针。
因此,虽然x18看起来确实可以在今天的macOS上使用,但不确定它是否可以在iOS上使用,它可以用于某些用途,所以我建议不要使用它。

相关问题