execve(2)のドキュメントを注意深く読んでください (より広い視野を得るためにAdvanced Linux Programmingも読んでください)。仮想メモリ、ページング、MMU、プロセスについて読んでください。
execve
システムコールは、プロセスに新しい仮想アドレス空間をインストールしています(そのため、正常に実行されているプログラムの古い仮想アドレス空間は新しい仮想アドレス空間execve
によって上書きされて消えます)、以前のものとデータを共有しません(そして新しいプログラムが開始されるため、成功execve
は返されません)。あなたの新しいプログラムは、例えばmmap(2) ...を使って、後で仮想アドレス空間を変更することができます。
新しい仮想アドレス空間内の文字列のアドレスargv
は、 への引数のアドレスとは無関係execve
です。文字列の内容は同じです。古い仮想アドレス空間と新しい仮想アドレス空間の間でデータは共有されませんが、新しいプログラム (およびプログラム環境) への引数はコピーされます。ASLRについても読む
の引数はexecve
、開始関数 ( を呼び出すcrt0内)の新しい仮想アドレス空間の新しい呼び出しスタックにコピーされた (そのコピーがプッシュされた状態で)文字列です。もちろん、未定義の動作となるようなi-を行うべきではありません。_start
main
free
argv[
]
したがって、 int a; argv[1]=(char*)&a;
... execve
withは未定義の動作です。これは、 のアドレスにあるメモリ ゾーンが適切なヌル終了文字列argv
であることを保証できないためです。エンディアンとABIa
について読んでください。
そのexecve
ため、適切な文字列(任意のポインターではない) の終了配列と、文字列の別のNULL
終了 配列が必要であり、各文字列は 0 バイトで終了する必要があります。&を介して古いアドレス空間から新しいアドレス空間にコピーされる合計メモリ空間には、かなり小さい制限(通常は 128K バイト) があります。argv
NULL
env
ARG_MAX
argv
env
おそらく、共有メモリ ( shm_overview(7) を参照) を使用して、さまざまなプロセス間でメモリを共有することができます (また、セマフォと同期します。sem_overview(7)を参照してください...)。しかし、多くの場合、他のプロセス間通信手法 (たとえば、 pipe(7) -s、fifo(7) -s、socket(7) -s など)を好むでしょう。
ところで、strace(1)も使用して、プログラムに関与するシステムコールを理解し、特に実行してproc(5)を使用し、仮想アドレス空間について詳しく理解してください。cat /proc/$$/maps
cat /proc/
$pidofyourprogram
/maps
main
両方の関数 (execve
最初の関数の前return 0;
、2 番目の関数の前) に次のようなものを入れることもできます。
char cmd[64];
snprintf(cmd, sizeof(cmd), "/bin/cat /proc/%d/maps", (int)getpid());
printf("before running %s\n", cmd);
fflush(NULL);
int err = system(cmd);
if (err) fprintf(stderr, "system failed err=%d\n", err);
else printf("system %s done\n", cmd);
これにより、仮想アドレス空間のビューが表示されます。もちろん、より本格的なプログラムではfopen
、/proc/1234/maps
ファイルを作成してループし、それfgets
まですべての行を読み取る必要があります。EOF
fclose
辛抱強く、ここにあるすべての参考文献を読み、時間をかけて POSIX プログラミングについて詳しく学んでください。いくつかのフリー ソフトウェアのソース コード (たとえば、 http: //github.com/でいくつかの興味深いプロジェクトを選択できます...) を研究し、それらに貢献することは価値があるはずです。