c - gcc 中的 arm 内联汇编

标签 c gcc arm inline-assembly

我在处理一些内联汇编代码时遇到了一些问题。我知道应该做什么,但我想念“怎么做”!

我有这个“几乎”可以工作的校验和函数:

static unsigned long cksum_unroll( unsigned short **w, int *mlen)
{
  int len;
  unsigned short *w0;
  unsigned long sum=0;

  len = *mlen;
  w0 = *w;

  while( len >= 8) {
    asm volatile (
          "ldmia %[w0]!, {v1, v2}\n\t"
          "adds %[sum], %[sum], v1\n\t"
          "adcs %[sum], %[sum], v2\n\t"
          "adcs %[sum], %[sum], #0"
          : [sum] "+r" (sum) : [w0] "r" (w0)
          );
    len -= 8;
  }
  *mlen = len;
  *w = w0;
  return (sum);
}

我认为,我的问题是在行 ": [sum] "+r"(sum) : [w0] "r"(w0)" 在第一条流水线上,w0ldmia 正确处理(当流水线执行时,数据在 r4、r5 中,w0 递增)。但是 w0 的增量值并没有保存在某个地方,当代码循环时,w0 的原始值会再次加载(见下面的汇编代码)。 我的猜测是我应该将 w0 的值存储在行 ": [sum] "+r"(sum) : [w0] "r"(w0)"但我不知道如何...

下面是函数内联汇编部分的反汇编代码:

请注意:

len is stored at r11, #-16
w0 is stored at r11, #-20
sum is stored at r11, #-24

已编译,代码如下:

asm volatile (
          "ldmia %[w0]!, {v1, v2}\n\t"
          "adds %[sum], %[sum], v1\n\t"
          "adcs %[sum], %[sum], v2\n\t"
          "adcs %[sum], %[sum], #0"
          : [sum] "+r" (sum) : [w0] "r" (w0)
);
len -= 8;

生成:

00031910:   ldr r3, [r11, #-20]
00031914:   ldr r2, [r11, #-24]
00031918:   mov r4, r2
0003191c:   ldm r3!, {r4, r5}
00031920:   adds r4, r4, r4
00031924:   adcs r4, r4, r5
00031928:   adcs r4, r4, #0
0003192c:   str r4, [r11, #-24]
00031930:   ldr r3, [r11, #-16]
00031934:   sub r3, r3, #8
00031938:   str r3, [r11, #-16]

如您所见,我想在第 31928 行和 3192c 行之间添加类似“str r3, [r11, #-20]” 的内容,因为当程序循环到第 31910 行时,r3 加载了初始值r3...

我认为这对于堆栈溢出社区的内联汇编专家来说很简单!

顺便说一下,我正在研究 ARM7TDMI 处理器(但这可能与这个问题无关...)

提前致谢!

编辑:

为了验证我的想法,我测试了以下内容:

asm volatile ( 
"ldmia %[w0]!, {v1, v2}\n\t" 
"adds %[sum], %[sum], v1\n\t" 
"adcs %[sum], %[sum], v2\n\t" 
"adcs %[sum], %[sum], #0\n\t" 
"str %[w0], [r11, #-20]" 
: [sum] "+r" (sum) : [w0] "r" (w0) 
); 

这行得通。也许这是解决方案,但我用什么来替换“r11,#20”,如果我修改函数可能会改变?

最佳答案

问题似乎是您将 w0 指定为 INPUT 操作数,而实际上它应该是一个读写 OUTPUT 操作数,例如 sum。此外,您需要指定它在您使用这些寄存器时破坏 v1 和 v2(否则,gcc 可能会将一些其他 var 放入这些 regs 并期望它们被保留。)

所以你应该:

asm volatile (
      "ldmia %[w0]!, {v1, v2}\n\t"
      "adds %[sum], %[sum], v1\n\t"
      "adcs %[sum], %[sum], v2\n\t"
      "adcs %[sum], %[sum], #0"
      : [sum] "+r" (sum) , [w0] "+r" (w0) : : "v1", "v2"
      );

即两个读写输入/输出操作数,无独占输入操作数,两个寄存器破坏

关于c - gcc 中的 arm 内联汇编,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9302575/

相关文章:

c - 如何读取3个字节的整数?

c++ - SIFT 描述符维度

ruby - 在 Mountain Lion 上安装 Ruby 时出现问题 - ruby​​ 1.9.3 不会编译

c - 以数字作为变量的字符串,Unix C 问题

GCC 原子内置函数 : Is there a list showing which are supported on which platform?

c++ - 针对特定 CXXABI 和 GLIBCXX 版本进行交叉编译

assembly - 如何在 ARM 汇编函数中访问 4 个以上的参数?

c - getrusage 子进程

c++ - 在一个范围内生成无偏随机整数的最佳算法是什么?

c++ - 在 C++ 中重载位移运算符