C标准是否允许自我修改代码?

时间:2011-06-18 21:28:36

标签: c self-modifying

在C中以可移植的方式可以实现自修改代码吗?

我问的原因是,在某种程度上,OOP依赖于自修改代码(因为在运行时执行的代码实际上是作为数据生成的,例如在v表中),但似乎如果这样做太过分,那么它将阻止编译器中的大多数优化。

例如:

void add(char *restrict p, char *restrict pAddend, int len)
{
    for (int i = 0; i < len; i++)
        p[i] += *pAddend;
}

优化编译器可以将*pAddend提升出循环,因为它不会干扰p。但是,这不再是自修改代码中的有效优化

通过这种方式,似乎C不允许自修改代码,但与此同时,这不意味着你不能在C中做一些像OOP这样的事情吗? C真的支持自修改代码吗?

2 个答案:

答案 0 :(得分:8)

由于多种原因,C中无法自修改代码,其中最重要的是:

  1. 编译器生成的代码完全取决于编译器,可能看起来不像程序员尝试编写修改自身所需的代码。这完全是SMC的基本问题,而不仅仅是可移植性问题。
  2. 函数和数据指针在C中是完全独立的;语言无法在它们之间来回转换。这个问题并不重要,因为某些实现或更高级别的标准(POSIX)保证代码和数据指针共享一个表示。
  3. 除此之外,自修改代码只是一个非常糟糕的主意。 20年前它可能有一些用途,但现在它只会导致错误,恶劣的性能和可移植性失败。请注意,在某些ISA上,指令缓存是否甚至看到对缓存代码所做的更改可能是未指定/不可预测的!

    最后,vtable与自修改代码无关。这纯粹是修改函数指针的问题,它们是数据,而不是代码。

答案 1 :(得分:3)

严格地说,如果我正确理解标准,自修改代码就无法以C或C ++的可移植方式实现。

C / C ++中的自修改代码意味着:

uint8_t code_buffer[FUNCTION_SIZE];
void call_function(void)
{
   ... modify code_buffer here to the machine code we'd like to run.
   ((void (*)(void))code_buffer)();
}

这不合法,并且会在大多数现代架构上崩溃。这在哈佛架构上是不可能实现的,因为可执行代码是严格只读的,因此它不能成为任何标准的一部分。

大多数现代操作系统都有能够执行此hackery的工具,动态重新编译器使用它。例如,Unix中的mprotect()。