5

初めてのポスター。CS2年生。

C ソース -> GCC コンパイル -> Linux 実行環境のコンテキストで、仮想アドレス空間の .data セクションに静的変数を作成する方法を調べています。

Cプログラムはtest.c

int main()
{
   register int i = 0;
   register int sum = 0;
   static int staticVar[10] = {1,2,3,4,5,6,7,8,9,-1};
   Loop: 
        sum = sum + staticVar[i]; //optimized away
    i = i+1;
    if(i != 10)
    goto Loop; 
   return 0;
 }

GDB に ' disass /m' を要求すると、staticVar[] 作成用のコードがないことがわかります。これは、.s ファイルを検査すると、プロセス作成時にそこに配置された仮想アドレス空間の読み取り/書き込み .data セグメントに変数が存在することが明らかになるためです。 (このプロセスは私が興味を持っているものです)。

(私は ' ' でしたが) の出力を調べるとreadelf -A test.o、オブジェクト ファイルには、データ セグメント内の配列の作成であると想定するアセンブリが含まれています。これがELF出力です。

(この出力を生成するコマンドを教えていただければボーナスです。readelfを使用して複製することはできません。Webサイトからコマンドを取得し、出力を保存しました。どのように生成されたか思い出せません)

[をちょきちょきと切る]

    00000000 <staticVar.1359>:
   0:01 00                  add    %eax,(%eax)
   2:00 00                  add    %al,(%eax) 
   4:02 00                  add    (%eax),%al
   6:00 00                  add    %al,(%eax)
   8:03 00                  add    (%eax),%eax
   a:00 00                  add    %al,(%eax)
   c:04 00                  add    $0x0,%al
   e:00 00                  add    %al,(%eax)
  10:05 00 00 00 06         add    $0x6000000,%eax
  15:00 00                  add    %al,(%eax)
  17:00 07                  add    %al,(%edi)
  19:00 00                  add    %al,(%eax)
  1b:00 08                  add    %cl,(%eax)
  1d:00 00                  add    %al,(%eax)
  1f:00 09                  add    %cl,(%ecx)
  21:00 00                  add    %al,(%eax)
  23:00 ff                  add    %bh,%bh
  25:ff                     (bad)  
  26:ff                     (bad)  
  27:ff                     .byte 0xff

[をちょきちょきと切る]

仮定 (修正してください) : このアセンブリは実行可能ファイルに存在し、load_elf_binary() または execve() によって開始される一連の関数の一部によって実行されます。私には at&t (基本的なインテル) 構文の知識はありませんが、直感的にさえ、これらの命令が配列を構築する方法がわかりません。レジスタ値を一緒に追加しているように見えます。

結論:この静的配列のライフサイクル、特にそれを構築する「不足しているコード」がどこにあるのか、どうすればそれを確認できるのか、可能な限り知りたいです。または、ローダープロセスをデバッグ (ステップスルー) するにはどうすればよいですか? __start_libc エントリ (またはそのようなもの) でメインの前にブレークポイントを設定しようとしましたが、この領域で有望なものを特定できませんでした。

追加情報へのリンクは素晴らしいです!御時間ありがとうございます!

4

4 に答える 4

1

私の実行可能形式は、もう使用されていない古い形式に限定されていますが、お探しのコードは ELF 実行可能ファイル自体には存在しないと確信しています。

実行可能ファイルは、プロセスのメモリに逐語的にコピー/マップされるセクションを定義します。実行可能ファイルに、それが定義する関数の命令ストリームを設定するコードが含まれていないのと同様に、静的な非実行可能データを設定するコードが含まれていません。そのためには、データ シンボルと実行可能シンボルの間に基本的な違いはないことを覚えておいてください。ストレージに関する限り、どちらもデータです。

C++ などの一部の言語では、動的初期化子を使用できます。動的イニシャライザは、実行可能ファイルのエントリ ポイントの前に実行され、コンパイル時に推測できなかった情報をデータ シンボルに入力します。その場合、はい、そのためのコードがあります。ただし、静的に初期化されたシンボルはそれを必要とせず、プロセスのアドレス空間に直接コピーまたはマップできます。

staticVar詳しくはデータをご覧ください。指示を少し忘れてください。すべてのバイトを隣り合わせにするとどうなりますか?

01 00 00 00
02 00 00 00
03 00 00 00
04 00 00 00
05 00 00 00
06 00 00 00
07 00 00 00
08 00 00 00
09 00 00 00
ff ff ff ff

これは、リトルエンディアン整数のシーケンスを 16 進数で表現した{1, 2, 3, 4, 5, 6, 7, 8, 9, -1}もので、見つけやすいように 4 バイトのグループに配置されています。

于 2013-09-03T01:00:54.950 に答える
0

zneak がオブジェクト ファイルで回答したように、staticVar変数を初期化するコードはありません。セクションの実際のバイトは.data、ファイルに直接含まれていtest.oます。const変数を定義すると、デフォルトでセクションgccに配置.rodataされます。

おそらく によって得られた分解ですobjdump --disassemble-all file.o。おそらく、データの逆アセンブルにより、それが実際のコードであると考えるように混乱した可能性があります。通常の使用ではobjdump --disassemble file.o、実際のマシン コードを含むセクションだけを逆アセンブルすることをお勧めします。

以下を実行すると、詳細な関連情報を取得できます。objdump -xdst test.o

の人生について簡単にstaticVar

  1. gcc.dataは、静的に初期化された変数であるため、変数 (その値を含む) をセクションに配置します。セクションのサイズは変数のサイズだけで、アドレスはまだ決定されていません。を参照してくださいobjdump -xdst test.o
  2. リンカーは.data、オブジェクト ファイルが既知であるため、セクション (およびその他) のアドレスを決定します。セクションには.data、他のオブジェクト ファイルの他の変数が表示されます。を参照してくださいobjdump -xdst test
  3. バイナリが実行されると、含まれているセグメントがプロセスのアドレス空間にtest直接マップ ( ) されるため、 の値がバイナリから直接読み取られます(おそらく必要な場合)。次に、ダイナミック リンクマップ共有ライブラリ( . またはのプロセスがメモリにロードされたときに表示されます。mmap()staticVartestld-linuxlibccat /proc/$PID/mapspmap $PID$PID

Cには変数の初期化コードがある可能性があります

staticVar をローカルの非静的変数に変更してみてください (つまり、デフォルトでスタックに格納されます)。

   int staticVar[10] = {1,2,3,4,5,6,7,8,9,-1};

デフォルトでは、gcc はmain()関数内で直接初期化コードを生成します。見てくださいobjdump -xdst test.o。これは、実行時にスタック変数が割り当てられる (そのアドレスが決定される) ためです。

于 2013-09-03T01:43:59.147 に答える