如何使用gcc内联assesmbly防止“'asm'中超过30个操作数”的错误

时间:2016-09-28 17:07:46

标签: c gcc assembly inline-assembly

我一直在编写一个用于教育目的的最小lua编译器,它将lua代码转换为使用gcc的C中的内联汇编。

一段时间后,当我生成的输出开始变长,C语句中声明的变量和函数的操作数更多时,就会出现此错误。

test.c: In function ‘int main()’:
test.c:100:6: error: more than 30 operands in ‘asm’
     );

当谷歌搜索我发现的唯一其他信息是some gcc mailing list from 2008,但他们说没有修复,除了重新编译gcc(我不感兴趣)。

具有讽刺意味的是,我经常甚至没有30个操作数,但我仍然会收到此错误!

这是一个最小的例子(有19个操作数,仍然给我错误)

// Standard functions
void io_read(){}
void io_write(){}
void print(){}
int main(){
    // Working vars decl
    long _t0, _t1, _t2, _t3, _t4, _t5, _t6, _t7, _t8;
    long factorial, i, n, x;
    // Strings decl
    const char* _s0 = "enter a number:";
    const char* _s1 = "*number";
    const char* _s2 = "factorial of ";
    const char* _s3 = " is ";
    asm("" // My inline asm code
    : // Output symbols
      [_s0] "+g" (_s0),
      [_s1] "+g" (_s1),
      [_s2] "+g" (_s2),
      [_s3] "+g" (_s3),
      [_t0] "+g" (_t0),
      [_t1] "+g" (_t1),
      [_t3] "+g" (_t3),
      [_t4] "+g" (_t4),
      [_t5] "+g" (_t5),
      [_t6] "+g" (_t6),
      [_t7] "+g" (_t7),
      [_t8] "+g" (_t8),
      [factorial] "+g" (factorial),
      [i] "+g" (i),
      [n] "+g" (n),
      [x] "+g" (x)
    : // Input symbols
      [io_read] "r" (io_read),
      [io_write] "r" (io_write),
      [print] "r" (print)
    : // Clobbers
      "cc", "rax", "rbx", "rcx", "rdx"
    );
}

我的gcc版本是6.2.1 20160830

提前致谢!

1 个答案:

答案 0 :(得分:1)

所以我没有找到问题的直接解决方案,但感谢Ross Ridge我能很好地解决这个问题。

我做的第一个改变就是改变" + g"用" g"在可能的情况。显然" + g"算作两个操作数,因为它允许读取和写入,所以我用" g"只允许写。

此外,我能够将我的函数作为操作数完全删除,方法是将它们移动到全局范围,然后直接调用" call print"而不是"调用%[print]"。但应该注意,这只适用于内联C,不适用于内联C ++。

如果您正在编写像我这样的编译器,我建议远离内联汇编。看起来更麻烦,简单地从Assembler手动调用C函数会更容易,而且我肯定不会使用内联C更大规模地编译。

编辑:我开始强迫" m"和" + m"而不是使用" g"并强制变量到堆栈上似乎工作正常。