2

C プログラムでは、テスト目的でプログラムを開始するときに、すべてのグローバル変数を再初期化する必要があります。

GCCライブラリで行われるロードメモリアドレス、LMAからVMA(ランタイムアドレス)へのデータコピーを再初期化機能で再現したい。たとえば、foo 変数がグローバルとして宣言され、初期化されているとします。そして、再初期化関数が re_init() の場合:

#include <stdio.h> 
int foo1 = 42;
int foo2 = 777;

int main(){
    foo1 = 0;
    foo2 = 0;
    re_init();
    printf("foo1:%d and foo2:%d",foo1,foo2);
    return 0;
}

次に、出力として持ちたい:

foo1:42 and foo2:777

これを行う正しい方法は、デフォルトのリンカ ファイルと、初期値を RAM にコピーするスタートアップ コードを使用することだと思います。では、GCC (cygwin) では、これを達成するにはどうすればよいでしょうか?

編集: このページはより正確に表示されているようです: http://sources.redhat.com/binutils/docs-2.12/ld.info/Output-Section-LMA.html#Output%20Section%20LMA

4

3 に答える 3

3

cygwin がこれをどのように行うのか正確にはわかりませんが、一般に、データ セクションは LMA から VMA にコピーされません。むしろ、実行可能ファイルの関連するチャンクが、カーネルによって目的の VMA で RAM にメモリ マップされ、ダイナミック リンカがデータ セクションを指す再配置を実行します。

したがって、実行可能ファイルの内容からデータ セクションを再初期化するには、ダイナミック リンカーとカーネル側の実行可能ローダーを十分に複製する必要があります。そのヘッダーを解析し、データ セクションを見つけます。古いマッピングを破棄し、適切な VMA で再作成します。すべての再配置を再度実行します。次に、C ライブラリのランタイム状態をその下からヤンクしたことによって引き起こされるすべてのフォールアウトに対処します (データ セクション内の独自のグローバル変数だけでなく、stdout や malloc のマスター アロケーション テーブルなどもそこにあります)。

「unexec」と「undump」でいくつか検索してください。これらは、リサイクルできるコードを取得する可能性がある、同様の (ただし同じではない) 問題を解決するものです。

于 2010-08-01T23:22:55.437 に答える
2

あなたが進んでいる道は、移植性の問題、バグ、悲しみに満ちています。

これを修正する最善の方法: グローバルは悪い! すべてのコードを分解して、渡される「コンテキスト」構造体に状態を格納します。そうすれば、「状態」をリセットすることは、新しい「コンテキスト」構造体を製造するだけです。

于 2010-08-01T23:28:38.173 に答える
0

解決策の別のアイデアを次に示しますが、グローバル状態を排除する方が良いと思います。

マクロを介してヘッダー ファイルですべてのグローバルを定義します。

globals.h:

DEFINE_GLOBAL(int, foo, 5);
DEFINE_GLOBAL(char, bar, 'x');

main.c:

#include <stdio.h>

#define DEFINE_GLOBAL(type, name, initialvalue) type name = initialvalue
#include "globals.h"
#undef DEFINE_GLOBAL

void resetState() {
    #define DEFINE_GLOBAL(type, name, initialvalue) name = initialvalue
    #include "globals.h"
    #undef DEFINE_GLOBAL
}

私はこれをテストしていないので、構文の修正が必要かもしれませんが、コンセプトは正しいと思います。

于 2010-08-01T23:31:37.937 に答える