如何防止错误 "more than 30 operands in 'asm'" with inline assesmbly with gcc
How to prevent error "more than 30 operands in 'asm'" with inline assesmbly with gcc
我一直在编写用于教育目的的最小 lua 编译器,方法是使用 gcc 将 lua 代码转换为 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
提前致谢!
所以我没有找到问题的直接解决方案,但感谢 Ross Ridge 我能够很好地解决这个问题。
我所做的第一个改进是在可能的情况下将“+g”更改为 "g"。显然“+g”算作两个操作数,因为它允许读+写,所以我用 "g" 替换了可能的,只允许写。
此外,通过将函数移动到全局范围然后直接使用 "call print" 而不是 "call %[print]" 调用,我能够完全删除作为操作数的函数。但是应该注意,这仅适用于内联 C,不适用于内联 C++。
如果您正在编写像我这样的编译器,我建议您远离内联汇编。似乎更麻烦,简单地从汇编程序中手动调用 C 函数会更容易,而且我当然不会使用内联 C 来制作更大规模的编译器。
编辑:我也开始强制 "m" 和“+m”而不是使用 "g" 并将变量强制到堆栈上,这似乎工作正常。
我一直在编写用于教育目的的最小 lua 编译器,方法是使用 gcc 将 lua 代码转换为 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
提前致谢!
所以我没有找到问题的直接解决方案,但感谢 Ross Ridge 我能够很好地解决这个问题。
我所做的第一个改进是在可能的情况下将“+g”更改为 "g"。显然“+g”算作两个操作数,因为它允许读+写,所以我用 "g" 替换了可能的,只允许写。
此外,通过将函数移动到全局范围然后直接使用 "call print" 而不是 "call %[print]" 调用,我能够完全删除作为操作数的函数。但是应该注意,这仅适用于内联 C,不适用于内联 C++。
如果您正在编写像我这样的编译器,我建议您远离内联汇编。似乎更麻烦,简单地从汇编程序中手动调用 C 函数会更容易,而且我当然不会使用内联 C 来制作更大规模的编译器。
编辑:我也开始强制 "m" 和“+m”而不是使用 "g" 并将变量强制到堆栈上,这似乎工作正常。