21

これが私がやりたいことです:

  1. プログラムを実行し、いくつかのデータ構造を初期化します。
  2. 次に、既存のデータ構造にアクセス/変更できる追加のコードをコンパイルします。
  3. 必要に応じて手順 2 を繰り返します。

Unix ライクなシステム (特に Linux と Mac OS X) でCC++を使用してgcc(そして最終的には)両方でこれを実行できるようにしたいと考えています。Javaアイデアは、基本的にこれらの言語に対して、入力された式とステートメントをコンパイルし、それらを使用して既存のデータ構造を変更する read-eval-print ループを実装することです (スクリプト言語では常に行われていることです)。/ファイルpythonを生成するこのツールを で書いていますが、これは関係ありません。CC++

共有ライブラリでこれを行うことを検討しましたが、共有ライブラリを変更しても、既に実行されているプログラムには影響しないことがわかりました。共有メモリも使用してみましたが、関数をヒープにロードする方法が見つかりませんでした。アセンブリ コードの使用も検討しましたが、まだ試していません。

gccでそれを行う方法がまったくない場合を除き、コンパイラを使用しないことをお勧めしgccます。

誰かがアイデアを持っているか、これを行う方法を知っている場合は、どんな助けでも大歓迎です。

4

6 に答える 6

15

1つの簡単な解決策があります:

  1. 特別な機能を持つ独自のライブラリを作成する
  2. 作成したライブラリをロードする
  3. そのライブラリから関数を実行し、関数変数として構造体を渡します

構造を使用するには、ホストアプリケーションと同じヘッダーファイルをインクルードする必要があります。

structs.h:

struct S {
    int a,b;
};

main.cpp:

#include <iostream>
#include <fstream>
#include <dlfcn.h>
#include <stdlib.h>

#include "structs.h"

using namespace std;

int main ( int argc, char **argv ) {

    // create own program
    ofstream f ( "tmp.cpp" );
    f << "#include<stdlib.h>\n#include \"structs.h\"\n extern \"C\" void F(S &s) { s.a += s.a; s.b *= s.b; }\n";
    f.close();

    // create library
    system ( "/usr/bin/gcc -shared tmp.cpp -o libtmp.so" );

    // load library        
    void * fLib = dlopen ( "./libtmp.so", RTLD_LAZY );
    if ( !fLib ) {
        cerr << "Cannot open library: " << dlerror() << '\n';
    }

    if ( fLib ) {
        int ( *fn ) ( S & ) = dlsym ( fLib, "F" );

        if ( fn ) {
            for(int i=0;i<11;i++) {
                S s;
                s.a = i;
                s.b = i;

                // use function
                fn(s);
                cout << s.a << " " << s.b << endl;
            }
        }
        dlclose ( fLib );
    }

    return 0;
}

出力:

0 0
2 1
4 4
6 9
8 16
10 25
12 36
14 49
16 64
18 81
20 100

また、それ自体を変更する可変プログラム(ソースコード)を作成し、自分自身を再コンパイルしてから、実際の実行を共有メモリに置き換え、execvリソースを共有メモリに保存することもできます。

于 2012-05-12T15:42:13.410 に答える
13

動的ライブラリを使用し、実行時にそれらをロードすることでこれを達成できると思います(dlopenおよび友人を使用)。

void * lib = dlopen("mynewcode.so", RTLD_LAZY);
if(lib) {
    void (*fn)(void) = dlsym(lib, "libfunc");

    if(fn) fn();
    dlclose(lib);
}

作業を進めながら新しいコードをコンパイルする必要があることは明らかですが、置き換えを続ければ、これでうまくいくmynewcode.soと思います。

于 2012-05-12T14:46:29.670 に答える
5

LLVM は現在、主にコンパイル時の最適化とバックエンドの役割のために使用されていますが、そのコアは低レベル仮想マシンです。

戻り値の型が非常に不透明な場合でも、LLVM はコードを JIT できます。そのため、独自のコードをラップする準備ができていて、発生するキャストについてあまり心配しない場合は、役立つかもしれません。

ただし、C と C++ は、この種のことにはあまり適していません。

于 2012-05-12T15:01:49.027 に答える
3

はい - Runtime Compiled C++ (またはRCC++ ブログとビデオを参照)、またはその代替手段の 1 つを使用してこれを行うことができます。

于 2015-02-13T09:55:07.233 に答える
2

他に何も機能しない場合 - 特に、共有ライブラリのアンロードがランタイム プラットフォームでサポートされていない場合は、難しい方法で行うことができます。

1) system() などを使用して gcc を実行するか、make などを使用してコードをビルドします。

2)それをフラットバイナリとしてリンクするか、プラットフォームでリンカが出力する形式(elf?)を自分で解析します

3) 実行可能ファイルを mmap() するか、実行ビットを設定して匿名の mmap を実行し、そこにコードをコピー/アンパックして、いくつかの実行可能ページを取得します (すべてのプラットフォームがそのビットを気にするわけではありませんが、持っていると仮定しましょうするもの)

4) データキャッシュと命令キャッシュをフラッシュします (2 つの間の一貫性は通常保証されないため)。

5)関数ポインタなどを介して呼び出す

もちろん、別のオプションもあります。必要な対話のレベルに応じて、別のプログラムを作成し、それを起動して結果を待つか、フォークして起動し、パイプまたはソケットで対話することができます。これがあなたのニーズを満たすなら、それほどトリッキーではありません.

于 2012-05-12T15:17:19.660 に答える