简体   繁体   English

将x86_64程序集移植到AArch64

[英]Porting x86_64 Assembly to AArch64

I'm trying to convert some existing inline x86_64 assembly to AArch64 compatible version. 我正在尝试将一些现有的嵌入式x86_64程序集转换为AArch64兼容版本。 I am encountering the following errors upon compilation: 编译时遇到以下错误:

/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'

The x86_64 code below if the original and the AARch64 code is my attempt at porting it. 下面是x86_64代码(如果原始代码和AARch64代码是我尝试移植的代码)。

x86_64 Assembly: 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 Assembly 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");

Edit:Updated with new attempt and error messages 编辑:更新了新的尝试和错误消息

When you want to do something can not be describe by one instruction, you need to split it into several instructions. 当您想做某事无法用一条指令来描述时,您需要将其分成几条指令。

The problem is that AArch64 doesn't have an instruction to store immediate value to a memory. 问题在于AArch64没有指令将立即值存储到内存中。 You need to move immediate value to an register and then store the register to memory like: 您需要将立即值移动到寄存器,然后将寄存器存储到内存中,例如:

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 instructions are RISC (Reduced instruction set computer) like instructions. ARM指令类似于RISC(精简指令集计算机)指令。 The benefit is that instructions are all very simple and fixed length. 好处是指令都很简单且固定长度。 X86 has more complicated instructions. X86有更复杂的指令。 But you still need to split your behaviour into several instructions if it hasn't an instruction support your behavour. 但是,如果没有指令支持您的行为,您仍然需要将您的行为分为几个指令。 You can find more information about AArch64 in http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488d/CIHGGBGB.html . 您可以在http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488d/CIHGGBGB.html中找到有关AArch64的更多信息。

A better solution might be to use the ldr= pseudo-op which would make the cryptic movz usage easier to read: 更好的解决方案可能是使用ldr=伪操作,这将使隐藏的movz用法更易于阅读:

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

.. and so on. .. 等等。 Your assembler should be smart enough to realize that it can use movz or some other instruction to generate the immediate in w2 , but in the worst case this'll come out as a literal pool load. 您的汇编器应该足够聪明,以意识到它可以使用movz或其他指令在w2生成立即数,但在最坏的情况下,它将作为文字池加载出现。 While learning, ldr= is a boon, and you shouldn't try and game the assembler until you know it's broken or not as efficient as you. 学习时, ldr=是一个福音,在您知道汇编器损坏或效率不如您之前,不应该尝试对汇编器进行游戏。

Unfortunately, almost none of your assembly is correct. 不幸的是,您的程序集几乎都不正确。 The A64 instruction set uses a load/store architecture. A64指令集使用加载/存储架构。 This means that there are specific instruction that load and store values from memory into and from registers. 这意味着有特定的指令可以将值从内存加载和存储到寄存器中以及从寄存器中存储值。 No other instructions access memory. 没有其他指令访问内存。 So for example an ADD instruction can't access memory. 因此,例如ADD指令无法访问内存。 This means that your add %0, %0, #1 statement doesn't increment op1->value , it increments the register that holds the address of op1->value . 这意味着您add %0, %0, #1语句不会增加op1->value ,它会增加保存op1->value地址的op1->value It's basically like you did op1++ in C instead of op1->value++ . 基本上就像您在C中op1->value++ 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");

You'll notice that the x86 INC instruction becomes three separate instructions. 您会注意到x86 INC指令变成了三个单独的指令。 The first ones loads the value into a register, the second adds one to the register, and finally the the third stores it back. 第一个将值加载到寄存器中,第二个将值添加到寄存器中,最后第三个将其存储回去。

The two constants 0x43e000000000000 and IS_DOUBLE happen to be ones that can be loaded into a register with a single instruction. 这两个常量0x43e000000000000IS_DOUBLE恰好可以通过一条指令加载到寄存器中。 Using the MOV pseudo instruction allows allows the assembler to figure out which one. 使用MOV伪指令允许汇编器找出哪一条。 Otherwise instead the LDR= pseudo instruction would have to be used to load the constant from memory. 否则,必须使用LDR =伪指令从内存中加载常量。 Either way, as claymore said in his answer you can't store an immediate value directly to memory. 无论哪种方式,正如克莱莫尔在回答中所说的那样,您不能将立即值直接存储到内存中。

Finally the asm statement uses the ADDS instruction instead of the ADD instruction. 最后,asm语句使用ADDS指令而不是ADD指令。 The former sets the condition flags according the result, the later doesn't. 前者根据结果设置条件标志,而后者则不设置。 This whole point of the asm statement. asm语句的整个要点。 It supposed to make signed overflow detection more efficient by checking the condition flags. 它应该通过检查条件标志来使带符号的溢出检测更加有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM