2013-05-15 22 views
12

readelfを使用してオブジェクトファイルの逆アセンブリをチェックすると、データとbssセグメントに同じオフセットアドレスが含まれています。 データセクションには、初期化されたグローバルおよび静的変数が含まれます。 BSSには、初期化されていないグローバル変数と静的変数が含まれます。データセクションとCのbssセクションの違い

1 #include<stdio.h> 
    2 
    3 static void display(int i, int* ptr); 
    4 
    5 int main(){ 
    6 int x = 5; 
    7 int* xptr = &x; 
    8 printf("\n In main() program! \n"); 
    9 printf("\n x address : 0x%x x value : %d \n",(unsigned int)&x,x); 
10 printf("\n xptr points to : 0x%x xptr value : %d \n",(unsigned int)xptr,*xptr); 
11 display(x,xptr); 
12 return 0; 
13 } 
14 
15 void display(int y,int* yptr){ 
16 char var[7] = "ABCDEF"; 
17 printf("\n In display() function \n"); 
18 printf("\n y value : %d y address : 0x%x \n",y,(unsigned int)&y); 
19 printf("\n yptr points to : 0x%x yptr value : %d \n",(unsigned int)yptr,*yptr); 
20 } 

出力:

SSS:~$ size a.out 
    text data  bss  dec  hex filename 
    1311  260  8 1579  62b a.out 

ここで上記のプログラムでは、私は、任意の非intialisedデータを持っていけないが、BSSは、8つのバイトを占有しています。なぜ8バイトを占有するのですか? また、私は、オブジェクトファイルを逆アセンブルするとき、

EDITED:

[ 3] .data    PROGBITS  00000000 000110 000000 00 WA 0 0 4 
    [ 4] .bss    NOBITS   00000000 000110 000000 00 WA 0 0 4 
    [ 5] .rodata   PROGBITS  00000000 000110 0000cf 00 A 0 0 4 

データ、rodataとBSSが同じオフセットアドレスを持っています。ロナタ、データ、およびbssが同じアドレスを参照していることを意味しますか? データセクション、ロッドデータセクション、およびbssセクションには同じアドレスのデータ値が含まれていますか?そうであれば、データセクション、bssセクション、およびロッドセクションを区別する方法はありますか?

+3

Cでは、ポインタは%pで出力され、引数は '(void *)'にキャストされます。 – Jens

+1

「リンクされているライブラリにもデータがありますが、私はどのような非初期化データも持っていませんが、BSSは8バイトを占有しています。実際、あなたのプログラムはローカル変数とリテラルだけを持っているので、 'data'と' bss'セクションはすべてライブラリから来ていると思います。 –

答えて

31

.bssセクションは、プログラムがメモリにロードされたときにすべてゼロになることが保証されています。したがって、初期化されていない、またはゼロに初期化されたグローバルデータは、.bssセクションに配置されます。たとえば:

static int g_myGlobal = 0;  // <--- in .bss section 

この程度の素敵な部分があり、.bssセクションデータはディスク上のELFファイル(すなわちに含まれていなくてもゼロの領域全体がためにファイルにありません。 .bssセクション)。代わりに、ローダーはセクションヘッダから、.bssセクションにどれだけ割り当てるべきかを知っていて、プログラムに制御を渡す前にそれをゼロにするだけです。

お知らせreadelf出力:

[ 3] .data PROGBITS 00000000 000110 000000 00 WA 0 0 4 
[ 4] .bss NOBITS 00000000 000110 000000 00 WA 0 0 4 

.dataPROGBITSとしてマークされています。これは、ローダーがあなたのためにメモリに読み出す必要があるELFファイルにプログラムデータの「ビット」があることを意味します。一方、.bssにはNOBITSというマークがついています。つまり、ロードの一部としてメモリに読み込む必要があるファイルには何もありません。


例:

// bss.c 
static int g_myGlobal = 0; 

int main(int argc, char** argv) 
{ 
    return 0; 
} 

今、私たちはシンボルテーブルに私達の変数を探し$ readelf -S bss

Section Headers: 
    [Nr] Name    Type   Addr  Off Size ES Flg Lk Inf Al 
    [ 0]     NULL   00000000 000000 000000 00  0 0 0 
    : 
    [13] .text    PROGBITS  080482d0 0002d0 000174 00 AX 0 0 16 
    : 
    [24] .data    PROGBITS  0804964c 00064c 000004 00 WA 0 0 4 
    [25] .bss    NOBITS   08049650 000650 000008 00 WA 0 0 4 
    : 

とセクションヘッダで$ gcc -m32 -Xlinker -Map=bss.map -o bss bss.c

表情でそれをコンパイルします:$ readelf -s bss | grep g_myGlobal

37: 08049654  4 OBJECT LOCAL DEFAULT 25 g_myGlobal 

我々はセクションヘッダに戻ってみるとg_myGlobalは、セクション25の一部であることが示されていることに注意してください、私たちは25が.bssであることがわかります。


あなたの本当の質問に答えるために:

をここで上記のプログラムでは、私は、任意の非intialisedデータを持っていけないが、BSSは、8つのバイトを占有しています。なぜ8バイトを占有するのですか?

私の例を続けると、私たちはセクション25に任意のシンボルを探します。

$ readelf -s bss | grep 25 
    9: 0804825c  0 SECTION LOCAL DEFAULT 9 
    25: 08049650  0 SECTION LOCAL DEFAULT 25 
    32: 08049650  1 OBJECT LOCAL DEFAULT 25 completed.5745 
    37: 08049654  4 OBJECT LOCAL DEFAULT 25 g_myGlobal 

3列目はサイズです。予想される4バイトのg_myGlobalと、この1バイトのcompleted.5745が表示されます。これはおそらく、Cランタイム初期化のどこかの関数静的変数です.main()が呼び出される前に、多くの「もの」が発生することに注意してください。

4 + 1 = 5バイトです。しかし、.bssセクションヘッダーを振り返ってみると、最後の列が4であることがわかります。これはセクションの配置です。このセクションがロードされると、常に4バイトの倍数になります。次の倍数は5から8倍であるため、.bssセクションは8バイトです。


さらに

我々は最終的な出力でどこに置いてしまったものをオブジェクトファイルを参照するために、リンカによって生成されたマップファイルを見ることができます。

.bss   0x0000000008049650  0x8 
*(.dynbss) 
.dynbss  0x0000000000000000  0x0 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../lib/crt1.o 
*(.bss .bss.* .gnu.linkonce.b.*) 
.bss   0x0000000008049650  0x0 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../lib/crt1.o 
.bss   0x0000000008049650  0x0 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../lib/crti.o 
.bss   0x0000000008049650  0x1 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/32/crtbegin.o 
.bss   0x0000000008049654  0x4 /tmp/ccKF6q1g.o 
.bss   0x0000000008049658  0x0 /usr/lib/libc_nonshared.a(elf-init.oS) 
.bss   0x0000000008049658  0x0 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/32/crtend.o 
.bss   0x0000000008049658  0x0 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../lib/crtn.o 

また、第3列はサイズです。

.bssの4バイトが/tmp/ccKF6q1g.oから来ています。この簡単な例では、bss.cファイルのコンパイル時の一時オブジェクトファイルであることがわかりました。他の1バイトはcrtbegin.oからのもので、これはCランタイムの一部です。私たちは、この1つのバイトの謎のBSS変数がcrtbegin.oからであり、それがcompleted.xxxxという名前ですが、それは本当の名前だということを知っているので、


は最後に、completedあり、それはおそらく、いくつかの関数内で静的です。crtstuff.cを見ると、static _Bool completed__do_global_dtors_aux()の内側にあります。

+0

例 'static int g_myGlobal;を初期化せず、' .bss'になるようにしてください。コード内で使用する必要があります。そうしないと、コンパイラは完全に削除することで最適化できます。 –

+0

@BasileStarynkevitch今、私のlinux VMを起動しています.... –

+0

おそらく、.bssはインクルードされた標準ライブラリの内部変数から来ています。 printfなどはスレッドセーフではありません。 – Lundin

1

定義により、bssセグメントは(プログラムが開始されたとき)メモリ内でいくらかの場所をとりますが、ディスクスペースは必要ありません。あなたはそれが満たさ得るために、いくつかの変数を定義するので、あなたの簡単なプログラムが.bss内の任意のデータを持っていない可能性があります

int bigvar_in_bss[16300]; 
int var_in_data[5] = {1,2,3,4,5}; 

しようとする必要がある、と共有ライブラリは、(のようなlibc.so)は「自分の.bss

を有することができます

ファイルのオフセットとメモリアドレスは簡単には関連しません。

ELF仕様の詳細を読む、また、(例えばcat /proc/self/mapsは、そのコマンドを実行しているcatプロセスのアドレス空間を表示していました)/proc/を使用しています。 Read proc(5)

関連する問題