【问题标题】:Porting x86_64 Assembly to AArch64将 x86_64 程序集移植到 AArch64
【发布时间】:2015-03-28 19:28:06
【问题描述】:

我正在尝试将一些现有的内联 x86_64 程序集转换为 AArch64 兼容版本。我在编译时遇到以下错误:

/tmp/ccSvqF1I.s:72547: Error: operand 1 should be an integer register -- `str [0x4,x1],#0x43e00000'
/tmp/ccSvqF1I.s:72548: Error: operand 1 should be an integer register -- `str [20,x1],2'

下面的 x86_64 代码如果是原始代码和 AARch64 代码是我移植它的尝试。

x86_64 组装:

                __asm__(
                        "incq (%0)\n\t"
                        "jno  0f\n\t"
                        "movl $0x0, (%0)\n\t"
                        "movl $0x43e00000, 0x4(%0)\n\t"
                        "movb %1, %c2(%0)\n"
                        "0:"
                        :
                        : "r"(&op1->value),
                          "n"(IS_DOUBLE),
                          "n"(ZVAL_OFFSETOF_TYPE)
                        : "cc");

AArch64 组装

                __asm__(
                        "add %0, %0, #1\n\t"
                        "bvc  0f\n\t"
                        "mov %0, #0x0\n\t"
                        "str [0x4, %0], #0x43e00000\n\t"
                        "str [%c2, %0], %1\n\t"
                        "0:"
                        :
                        : "r"(&op1->value),
                          "n"(IS_DOUBLE),
                          "n"(ZVAL_OFFSETOF_TYPE)
                        : "cc");

编辑:更新了新的尝试和错误消息

【问题讨论】:

  • 听起来并不粗鲁,但您可能应该尝试使用 AArch64 指令和语法,而不是这样。
  • @Notlikethat 我猜我真正的问题是不理解 x86 代码的 %c2(%0) 部分。我似乎找不到任何描述该代码作用的文档。
  • 我的 x86 程序集相当生疏,我的知识是 Intel 语法,而不是 GNU 愚蠢的 AT&T 语法,但我认为这只是基址寄存器 + 立即偏移寻址,具有 ZVAL_OFFSETOF_TYPE 的约束必须是编译时常量 - 请参阅 "x86 Operand Modifiers" in the docs。无论哪种方式,任何内存操作数都不适合 ARM mov 指令。
  • @Notlikethat 所以装配线将%1 中的值移动到%c2 中,偏移%0 的值?对于 ARM 中的内存操作,mov 指令的替代方案是什么?我查看了str,但这似乎只是将一个寄存器+偏移量移动到一个寄存器中,这与 x86 代码的作用相反。我已经用我的新尝试和相应的错误消息更新了代码。
  • x64 和 ARM64 的功能和语法有很大不同。为什么不让编译器为某些 C 代码生成汇编语言列表,以查看它对 ARM64 的期望。 ARM 是一种加载/存储架构,您不能将立即值存储到内存中。指令只能将寄存器移动到内存或内存到寄存器。

标签: assembly x86-64 arm64


【解决方案1】:

当你想做的事情不能用一条指令来描述时,你需要把它分成几条指令。

问题在于 AArch64 没有将立即值存储到内存的指令。您需要将立即值移动到寄存器,然后将寄存器存储到内存中,例如:

movz    w2, #0x43e0, lsl #16         // move #0x43e00000 to a register
str w2, [x1, #20]                    // store to address [x1, #20]
orr w2, wzr, #0x2                    // move #0x2 to a register
str w2, [x1, #4]                     // store to address [x1, #4]

ARM 指令类似于 RISC(精简指令集计算机)指令。好处是指令都非常简单且长度固定。 X86 有更复杂的指令。但是,如果没有一条指令支持您的行为,您仍然需要将您的行为分成几条指令。 你可以在http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488d/CIHGGBGB.html找到更多关于AArch64的信息。

【讨论】:

    【解决方案2】:

    更好的解决方案可能是使用 ldr= 伪操作,这将使隐秘的 movz 用法更易于阅读:

    ldr  w2, =0x43e00000
    str  w2, [x1, #20]
    

    .. 等等。您的汇编程序应该足够聪明,能够意识到它可以使用movz 或其他一些指令在w2 中生成立即数,但在最坏的情况下,这将作为文字池加载出现。在学习的过程中,ldr= 是一个福音,在您知道它已损坏或效率不如您之前,您不应该尝试玩弄汇编器。

    【讨论】:

    • 我们需要翻译来理解这个回复。
    【解决方案3】:

    不幸的是,几乎没有一个程序集是正确的。 A64 指令集使用加载/存储架构。这意味着有特定的指令可以将内存中的值加载和存储到寄存器中。没有其他指令访问内存。因此,例如 ADD 指令无法访问内存。这意味着您的add %0, %0, #1 语句不会增加op1->value,它会增加保存op1->value 地址的寄存器。这基本上就像您在 C 中使用 op1++ 而不是 op1->value++

        zend_long temp;
        static zend_long const overflow = 0x43e0000000000000;
        asm("ldr %[temp], %[value]\n\t"
            "adds %[temp], %[temp], #1\n\t"
            "str %[temp], %[value]\n\t"
            "b.vc 0f\n\t"
            "mov %[temp], #%[overflow]\n\t"
            "str %[temp], %[value]\n\t"
            "mov %w[temp], #%[is_double]\n\t"
            "str %w[temp], %[type_info]\n\t"
            "0:\n\t"
            :
            [temp] "=&r" (temp),
            [value] "+m" (op1->value.lval),
            [type_info] "=m" (op1->u1.type_info)
            :
            [overflow] "N" (overflow),
            [is_double] "M" (IS_DOUBLE)
            : "cc");
    

    您会注意到 x86 INC 指令变成了三个独立的指令。第一个将值加载到寄存器中,第二个将值加到寄存器中,最后第三个将其存储回来。

    0x43e000000000000IS_DOUBLE 这两个常量恰好是可以通过一条指令加载到寄存器中的常量。使用 MOV 伪指令允许汇编器找出哪一个。否则,将不得不使用 LDR= 伪指令从内存中加载常量。无论哪种方式,正如克莱莫尔在他的回答中所说,您不能将立即值直接存储到内存中。

    最后,asm 语句使用了 ADDS 指令而不是 ADD 指令。前者根据结果设置条件标志,后者不设置。 asm 语句的全部要点。它应该通过检查条件标志来提高有符号溢出检测的效率。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-18
      • 1970-01-01
      • 2012-05-09
      • 1970-01-01
      • 2011-03-13
      • 2017-05-21
      • 2010-10-13
      • 2010-11-29
      相关资源
      最近更新 更多