有没有办法在GCC中禁用嵌入式汇编器?

时间:2019-03-16 01:23:47

标签: c++ c gcc g++ inline-assembly

我正在为诸如LeetCode,Codeforces之类的编程竞赛开发在线裁判系统。对于大多数编程竞赛,C / C ++均不允许内联汇编程序,因此我想对系统添加相同的限制。

我想让GCC和G ++在编译包含内联汇编程序的C / C ++程序时产生错误,以便任何包含内联汇编程序的代码都将导致编译错误。

有没有办法做到这一点?我应该将一些命令行参数传递给GCC / G ++吗?

注意:禁用内联汇编程序仅是为了遵守规则,而不是出于安全考虑。

1 个答案:

答案 0 :(得分:10)

是否可以在GCC中禁用内联汇编程序?

是的,有两种方法。

在编译器中关闭程序集

要在编译阶段执行此操作,请使用参数-fno-asm。但是,请记住,这只会影响asm,而不会影响__asm__

文档:

  

-fno-asm

     

请勿将“ asm”,“ inline”或“ typeof”识别为关键字,以便代码可以将这些单词用作标识符。您可以改用关键字“ __asm__,“ __inline__”和“ __typeof__”。 -ansi暗示-fno-asm

     

在C ++中,此开关仅影响“ typeof”关键字,因为“ asm”和“ inline”是标准关键字。您可能需要改用-fno-gnu-keywords标志,其效果相同。在C99模式(-std=c99-std=gnu99)中,此开关仅影响“ asm”和“ typeof”关键字,因为“ inline”是标准ISO C99中的关键字。

定义宏

您可以使用参数-Dasm=error -D__asm__=error

请注意,此构造是通用的。它的作用是创建宏。它的工作原理很像#define。该文档说:

  

-D name=definition

     

对定义的内容进行标记和处理,就像它们出现在#define指令的第三翻译阶段中一样。特别是,该定义将被嵌入的换行符截断。

     

...

因此,它所做的只是将asm__asm__的出现更改为error。这是在预处理阶段完成的。您不必使用error。只需选择不会编译的任何东西即可。

使用在编译过程中触发的宏

zwol的注释中所建议,通过使用宏在编译阶段解决该问题的方法,可以使用-D'asm(...)=_Static_assert(0,"inline assembly not allowed")'。如果存在一个名为error的标识符,这也将解决该问题。

注意:此方法需要-std=c11或更高版本。

在使用gcc之前先使用grep

另一种可能解决您问题的方法是在编译前仅在源树的根目录中执行grep

grep -nr "asm"

这也会捕获__asm__,但可能会带来误报,例如,您有一个包含子字符串"asm"的字符串文字,标识符或注释。但是根据您的情况,您可以通过在源代码中的任何位置禁止该字符串的出现来解决此问题。只需更改规则。

可能的意外问题

请注意,禁用汇编可能会导致其他问题。例如,我不能将stdio.h与该选项一起使用。系统标题通常包含内联汇编代码。

一种欺骗上述方法的方法

可以将字符串作为机器代码执行。例如,请参见以下答案:https://stackoverflow.com/a/18477070/6699433

上面链接中的一部分代码:

/* our machine code */
char code[] = {0x55,0x48,0x89,0xe5,0x89,0x7d,0xfc,0x48,
0x89,0x75,0xf0,0xb8,0x2a,0x00,0x00,0x00,0xc9,0xc3,0x00};

/* copy code to executable buffer */    
void *buf = mmap (0,sizeof(code),PROT_READ|PROT_WRITE|PROT_EXEC,
            MAP_PRIVATE|MAP_ANON,-1,0);
memcpy (buf, code, sizeof(code));

/* run code */
int i = ((int (*) (void))buf)();

上面的代码仅用于快速了解如何欺骗OP陈述的规则。它不打算成为如何在现实中实际执行的好例子。此外,该代码不是我的。这只是我提供的链接中的简短代码引用。如果您有改进的想法,请在4pie0:s的原始帖子中发表评论。