首页 > 解决方案 > 有没有办法在 GCC 中禁用内联汇编程序?

问题描述

我正在为 LeetCode、Codeforces 等编程竞赛开发在线评委系统。对于大多数编程竞赛,C/C++ 中不允许使用内联汇编,所以我想在我的系统中添加相同的限制。

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

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

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

标签: c++cgccg++inline-assembly

解决方案


有没有办法在 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__,但它可能会给出误报,例如,您有一个包含 substring 的字符串文字、标识符或注释"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 原帖。


推荐阅读