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 では、キャッシュされたコードに加えられた変更を命令キャッシュが認識するかどうかが、未指定/予測不能であることに注意してください。

最後に、vtable は自己変更コードとは何の関係もありません。これは、コードではなくデータである関数ポインタを変更するだけの問題です。

于 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)();
}

これは合法ではなく、ほとんどの最新のアーキテクチャでクラッシュします。実行可能コードは厳密に読み取り専用であるため、これをハーバード アーキテクチャに実装することは不可能であり、標準の一部にすることはできません。

最近のほとんどの OS には、このハッカーを実行できる機能があり、動的再コンパイラーによって使用されます。たとえば、Unix の mprotect() 。

于 2011-06-18T21:39:19.250 に答える