5

是否可以在 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 真的支持自修改代码吗?

4

2 回答 2

8

在 C 中不能进行自修改代码的原因有很多,其中最重要的是:

  1. 编译器生成的代码完全取决于编译器,并且可能看起来不像程序员试图编写修改自己的代码所期望的那样。这是做 SMC 的根本问题,而不仅仅是可移植性问题。
  2. 函数和数据指针在 C 中是完全分开的;该语言无法在它们之间来回转换。这个问题不是根本问题,因为一些实现或更高级别的标准 (POSIX) 保证代码和数据指针共享一个表示。

除此之外,自我修改代码只是一个非常糟糕的主意。20 年前它可能有一些用途,但现在它只会导致错误、糟糕的性能和可移植性失败。请注意,在某些 ISA 上,指令缓存是否甚至可以看到对缓存代码所做的更改可能是未指定/不可预测的!

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

于 2011-06-18T21:52:59.973 回答
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()。

于 2011-06-18T21:39:19.250 回答