将x86_64程序集移植到AArch64

时间:2015-03-28 19:28:06

标签: assembly x86-64 arm64

我试图将一些现有的内联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");

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

3 个答案:

答案 0 :(得分:0)

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

问题是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的更多信息。

答案 1 :(得分:0)

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

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

..等等。你的汇编程序应该足够聪明,可以意识到它可以使用movz或其他一些指令来生成w2中的立即数,但在最坏的情况下,它会以文字池加载的形式出现。在学习的过程中,ldr=是一个福音,你不应该尝试和汇编汇编程序,直到你知道它已经破坏或者不像你那样有效。

答案 2 :(得分:0)

不幸的是,几乎没有一个装配是正确的。 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声明的这一点。它应该通过检查条件标志来使签名溢出检测更有效。