程序集 - 内联 asm - 从一个数组复制到另一个数组?

Assembly - inline asm - copy from one array to another?

上下文:

Linux64.美国电话电报公司

GCC 4.8.2(带 -O3 -march=native)

我左手下的x86_64 abi,​​在第21页打开。

预期的 C 代码:

为了明确意图,这里是想法:

int32_t res[] = {0,0,0,0};
int32_t primo[] = {5,8,50,150};

for (int32_t x = 0; x < 4; ++x) {

    res[x] = primo[x];
}

printf("%d %d %d %d\n", res[0], res[1], res[2], res[3]);

错误的C代码:

检测到错误:

Error: `(%rsp,%esi,4)' is not a valid base/index expression

代码:

int32_t res[] = {0,0,0,0};
int32_t primo[] = {5,8,50,150};
int32_t counter = 0;

    __asm__ volatile(
        "start_loop:\n\t"
        "movl (%1,%2,4), (%0,%2,4)\n\t"
        "addl , %2\n\t"
        "cmp , %2\n\t"
        "jne start_loop"
        : "=&r"(res)
        : "r"(primo),"r"(counter)
        :"cc"
        );

printf("%d %d %d %d\n", res[0], res[1], res[2], res[3]);

汇编代码(问题所在的行):

...
start_loop:
movl (%rsp,%edx,4), (%si,%edx,4)
addl , %edx
cmp , %edx
jne start_loop
...

问题:

如何表达正确的代码?我哪里做错了?

谢谢

更新:

将流水线改为

movl (%rsp,%rdx,4), (%rsi,%rdx,4)

我明白了

Error: too many memory references for 'mov'

什么??

更新 2

对于读者来说,我的系统似乎很特别,它不会放入正确的指令大小。

我必须以 int64_t 为例手动键入我的变量,以强制 r*x 事情发生。如果 c11/c++11 使用 uintptr_t 类型。

否则,gcc 会坚持使用导致无效 base/index 错误的 32 位版本。

它咬了我好几次。我希望它现在不会适合你。

现在关闭ABI doc,打开intel手册,基础架构和指令集参考当然:->

首先,mov不接受两个内存操作数,你必须通过寄存器或使用专门的字符串移动movs。其次,在有效地址中不能混合使用 16、32 和 64 位寄存器。鉴于您的代码片段中的类型,编译器为您替换了 16 位寄存器非常可疑。此外,由于不可能的约束,它甚至不应该编译,res 是一个数组,你不能将它用作输出。此外,您正在更改 counter 变量,但您没有告诉编译器。

gcc内联汇编是一个很复杂的东西。如果可能最好避免它,特别是如果你是初学者,否则你将与编译器作斗争而不是学习汇编。

固定版本可能如下所示:

#include <stdint.h>
#include <stdio.h>

int main()
{
    int32_t res[] = {0,0,0,0};
    int32_t primo[] = {5,8,50,150};
    int32_t counter = 0;
    int32_t tmp;

    __asm__ volatile(
        "start_loop:\n\t"
        "movl (%3, %q1, 4), %0\n\t"
        "movl %0, (%2, %q1, 4)\n\t"
        "addl , %1\n\t"
        "cmp , %1\n\t"
        "jne start_loop"
        : "=&r" (tmp), "+r" (counter)
        : "r" (res), "r"(primo)
        : "cc", "memory"
        );

    printf("%d %d %d %d\n", res[0], res[1], res[2], res[3]);
    return 0;
}