我正在尝试用asm-implementations替换某些方法。目标是iOS(iPhone 5S或更高版本)上的arm64。我要使用专用的汇编器文件,因为内联汇编器会带来额外的开销,而且是cumbersome to use with A64 memory offsets

互联网上没有太多的文档,因此我不确定该怎么做。因此,我将描述将函数移至ASM所遵循的过程。

此问题的候选函数是256位整数比较函数。

UInt256.h

@import Foundation;

typedef struct {
    uint64_t value[4];
} UInt256;

bool eq256(const UInt256 *lhs, const UInt256 *rhs);

Bridging-Header.h
#import "UInt256.h"

Reference implementation (Swift)
let result = x.value.0 == y.value.0
          && x.value.1 == y.value.1
          && x.value.2 == y.value.2
          && x.value.3 == y.value.3

UInt256.s
.globl _eq256
.align 2
_eq256:
    ldp        x9, x10, [x0]
    ldp       x11, x12, [x1]
    cmp        x9, x11
    ccmp      x10, x12, 0, eq
    ldp        x9, x10, [x0, 16]
    ldp       x11, x12, [x1, 16]
    ccmp       x9, x11, 0, eq
    ccmp      x10, x12, 0, eq
    cset       x0, eq
    ret

我找到了的资源
  • Procedure Call Standard for the ARM 64-bit Architecture (AArch64)文档的5.1.1节介绍了过程调用期间每个寄存器的用途。
  • iOS特定的deviations
  • iOS Assembler Directives


  • 问题

    我已经使用XCTest测试了代码,创建了两个随机数,在它们上运行了Swift和Asm实现,并验证了两者报告的结果相同。该代码似乎是正确的。
  • 在asm文件中:.align似乎是为了优化-这真的必要吗?如果是,则要对齐的正确值是什么?
  • 是否有明确说明解释了我的特定函数签名的调用约定的任何来源?

    一种。我怎么知道输入实际上是通过x0x1传递的?

    b。我怎么知道在x0中传递输出是正确的?

    C。我怎么知道掩盖x9-x12和状态寄存器是安全的?

    d。当我从C而不是Swift调用函数时,是否以相同的方式调用该函数?
  • “间接结果位置寄存器”对ARM文档中r8寄存器的描述是什么意思?
  • 除了.globl之外,我还需要其他任何汇编程序指令吗?
  • 当我设置断点时,调试器似乎在实际位置上感到困惑,显示错误的行等。我做错什么了吗?
  • 最佳答案

  • .align 2伪指令是程序正确性所必需的。 A64指令需要在32位边界上对齐。
  • 您链接的文档对我来说似乎很清楚,很遗憾,这不是寻求建议的地方。
  • 您可以按照链接的ARM 64位体系结构(AArch64)文档的过程调用标准的5.4.2节(参数传递规则)中给出的说明,确定将lhsrhs寄存器存储在X0X1中。由于参数都是指针,因此唯一适用的特定规则是C.7。
  • 您可以按照第5.5节(返回结果)中的说明确定使用哪个寄存器返回值。这只是让您遵循与参数相同的规则。由于该函数返回整数,因此仅适用规则C.7,因此该值将在X0中返回。
  • 可以安全地更改存储在寄存器X9至X12中的值,因为它们在第5.1.1节(通用寄存器)
  • 中给出的表中被列为临时寄存器。
  • 问题实际上是在Swift中调用函数的方式是否与在C中相同。链接的过程调用标准文档和Apple特有的异常文档均以C和C++定义。大概Swift遵循相同的约定,但是我不知道Apple是否在任何地方都明确了这一点。
  • 在第5.5节(结果返回)中描述了R8的用途。当返回值太大而无法放入用于返回值的寄存器中时使用。在这种情况下,调用方将为返回值创建一个缓冲区,并将其地址放入R8中。然后,该函数将返回值复制到该寄存器中。
  • 我不认为您的示例汇编程序中还需要其他任何东西。
  • 您问了太多问题。您应该发布一个单独的更详细的问题来描述您的问题。

  • 我应该说使用内联汇编编写代码的一个优点是,您不必担心任何这些。像下面未经测试的C代码这样的东西应该不会太笨拙:
    bool eq256(const UInt256 *lhs, const UInt256 *rhs) {
         const __int128 *lv = (__int128 const *) lhs->value;
         const __int128 *rv = (__int128 const *) rhs->value;
    
         uint64_t l1, l2, r1, r2, ret;
    
         asm("ldp       %1, %2, %5\n\t"
             "ldp       %3, %4, %6\n\t"
             "cmp       %1, %3\n\t"
             "ccmp      %2, %4, 0, eq\n\t"
             "ldp       %1, %2, %7\n\t"
             "ldp       %3, %4, %8\r\n"
             "ccmp      %1, %3, 0, eq\n\t"
             "ccmp      %2, %4, 0, eq\n\t"
             "cset      %0, eq\n\t",
             : "=r" (ret), "=r" (l1), "=r" (l2), "=r" (r1), "=r" (r2)
             : "Ump" (lv[0]), "Ump" (rv[0]), "Ump" (lv[1]), "Ump" (rv[1])
             : "cc")
    
         return ret;
    }
    

    好吧,也许有点笨拙。

    关于ios - 64位iOS(A64)上的汇编器,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30947422/

    10-15 11:56